From 5385889ebd79c46134430a932fbc18a105c67e10 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Fri, 24 Sep 2021 23:14:55 -0400 Subject: [PATCH 001/715] Revert "Revert "Merge pull request #4463 from urbit/m/next-gen-term"" This reverts commit 3fba32185dce321661647c5fe3a8a3be930aee32. --- bin/brass.pill | 4 +- bin/ivory.pill | 4 +- bin/solid.pill | 4 +- pkg/arvo/app/herm.hoon | 91 +-- pkg/arvo/app/hood.hoon | 25 +- pkg/arvo/gen/aqua/dojo.hoon | 4 +- pkg/arvo/lib/dill.hoon | 93 +++ pkg/arvo/lib/hood/drum.hoon | 391 ++++++------ pkg/arvo/lib/ph/util.hoon | 8 +- pkg/arvo/mar/belt.hoon | 15 +- pkg/arvo/mar/blit.hoon | 47 +- pkg/arvo/mar/dill/belt.hoon | 4 +- pkg/arvo/mar/dill/blit.hoon | 6 +- pkg/arvo/mar/herm/task.hoon | 46 ++ pkg/arvo/sur/herm.hoon | 9 + pkg/arvo/sys/lull.hoon | 86 ++- pkg/arvo/sys/vane/clay.hoon | 10 +- pkg/arvo/sys/vane/dill.hoon | 320 ++++++---- pkg/arvo/sys/vane/gall.hoon | 20 +- pkg/arvo/sys/vane/jael.hoon | 11 +- pkg/arvo/sys/zuse.hoon | 101 +++ pkg/arvo/ted/aqua/dill.hoon | 5 +- pkg/hs/urbit-king/lib/Urbit/Arvo/Effect.hs | 37 +- pkg/hs/urbit-king/lib/Urbit/Arvo/Event.hs | 80 ++- pkg/hs/urbit-king/lib/Urbit/Vere/Pier.hs | 2 +- pkg/hs/urbit-king/lib/Urbit/Vere/Term.hs | 295 ++++++--- pkg/hs/urbit-king/lib/Urbit/Vere/Term/API.hs | 2 +- .../urbit-king/lib/Urbit/Vere/Term/Logic.hs | 61 +- .../urbit-king/lib/Urbit/Vere/Term/Render.hs | 34 +- pkg/interface/package-lock.json | Bin 882585 -> 1363532 bytes pkg/interface/package.json | 2 + pkg/interface/src/logic/lib/bel.js | 1 - pkg/interface/src/logic/lib/bel.ts | 1 + pkg/interface/src/logic/state/term.ts | 21 + pkg/interface/src/views/apps/term/api.tsx | 50 -- pkg/interface/src/views/apps/term/app.tsx | 526 +++++++++++++--- .../views/apps/term/components/history.tsx | 35 -- .../src/views/apps/term/components/line.tsx | 66 -- .../src/views/apps/term/css/custom.css | 16 - pkg/interface/src/views/apps/term/store.tsx | 94 --- .../src/views/apps/term/subscription.tsx | 87 --- pkg/npm/api/term/index.ts | 2 + pkg/npm/api/term/lib.ts | 22 + pkg/npm/api/term/types.ts | 60 ++ pkg/urbit/compat/posix/ptty.c | 3 + pkg/urbit/configure | 2 +- pkg/urbit/daemon/main.c | 4 +- pkg/urbit/include/c/motes.h | 3 + pkg/urbit/include/vere/vere.h | 49 +- pkg/urbit/jets/c/rep.c | 2 +- pkg/urbit/jets/c/rip.c | 2 +- pkg/urbit/jets/e/argon2.c | 2 +- pkg/urbit/jets/e/jam.c | 6 +- pkg/urbit/jets/e/rub.c | 2 +- pkg/urbit/jets/e/secp.c | 2 +- pkg/urbit/jets/f/core.c | 2 +- pkg/urbit/jets/f/look.c | 2 +- pkg/urbit/noun/allocate.c | 16 +- pkg/urbit/noun/events.c | 20 +- pkg/urbit/noun/jets.c | 42 +- pkg/urbit/noun/log.c | 2 + pkg/urbit/noun/manage.c | 36 +- pkg/urbit/noun/nock.c | 2 +- pkg/urbit/noun/trace.c | 6 +- pkg/urbit/noun/vortex.c | 8 +- pkg/urbit/vere/auto.c | 8 +- pkg/urbit/vere/dawn.c | 46 +- pkg/urbit/vere/disk.c | 10 +- pkg/urbit/vere/foil.c | 4 +- pkg/urbit/vere/io/ames.c | 96 +-- pkg/urbit/vere/io/behn.c | 4 +- pkg/urbit/vere/io/cttp.c | 10 +- pkg/urbit/vere/io/fore.c | 14 +- pkg/urbit/vere/io/hind.c | 4 +- pkg/urbit/vere/io/http.c | 74 +-- pkg/urbit/vere/io/term.c | 581 ++++++++++-------- pkg/urbit/vere/io/unix.c | 102 +-- pkg/urbit/vere/king.c | 46 +- pkg/urbit/vere/lord.c | 12 +- pkg/urbit/vere/newt.c | 2 +- pkg/urbit/vere/pier.c | 97 +-- pkg/urbit/vere/save.c | 2 +- pkg/urbit/vere/walk.c | 14 +- pkg/urbit/worker/serf.c | 14 +- 84 files changed, 2387 insertions(+), 1764 deletions(-) create mode 100644 pkg/arvo/lib/dill.hoon create mode 100644 pkg/arvo/mar/herm/task.hoon create mode 100644 pkg/arvo/sur/herm.hoon delete mode 100644 pkg/interface/src/logic/lib/bel.js create mode 100644 pkg/interface/src/logic/lib/bel.ts create mode 100644 pkg/interface/src/logic/state/term.ts delete mode 100644 pkg/interface/src/views/apps/term/api.tsx delete mode 100644 pkg/interface/src/views/apps/term/components/history.tsx delete mode 100644 pkg/interface/src/views/apps/term/components/line.tsx delete mode 100644 pkg/interface/src/views/apps/term/css/custom.css delete mode 100644 pkg/interface/src/views/apps/term/store.tsx delete mode 100644 pkg/interface/src/views/apps/term/subscription.tsx create mode 100644 pkg/npm/api/term/index.ts create mode 100644 pkg/npm/api/term/lib.ts create mode 100644 pkg/npm/api/term/types.ts diff --git a/bin/brass.pill b/bin/brass.pill index 6b9140a68..034893638 100644 --- a/bin/brass.pill +++ b/bin/brass.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8c497bba51152dc3e54463a9f33c02876345419457a2f0ce2f15810db9daac72 -size 5041231 +oid sha256:f70a6e20ac6fd7dfb620f7ace725c5b031d040c0fe97caab251233ba31bc9819 +size 5155717 diff --git a/bin/ivory.pill b/bin/ivory.pill index 86a18b8b4..0f3973589 100644 --- a/bin/ivory.pill +++ b/bin/ivory.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5c6ad04e9c83caf6667ef12f4ba9627e9d409381fc4cd151dd2964faed105f8a -size 1148833 +oid sha256:c871af4da5d779a2ccc8a8187ca06e2ccf19a984db9bede7f2d721fa43525210 +size 1259429 diff --git a/bin/solid.pill b/bin/solid.pill index a25dae6d3..2c88500aa 100644 --- a/bin/solid.pill +++ b/bin/solid.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3cc76dec0e5110e35647a8a7341c5c1648d33eab636c067b4ce5893d13af86d8 -size 6755088 +oid sha256:5f97a6c105b89973b6f7ee2bace9f0aff018efb65db7a3b90948761abb8c6b18 +size 6876039 diff --git a/pkg/arvo/app/herm.hoon b/pkg/arvo/app/herm.hoon index cd791b2af..7be319b95 100644 --- a/pkg/arvo/app/herm.hoon +++ b/pkg/arvo/app/herm.hoon @@ -1,7 +1,13 @@ :: herm: stand-in for term.c with http interface :: +/- herm /+ default-agent, dbug, verb -=, jael +:: keep relevant mark conversions in cache for performance +:: +/$ bj %blit %json +/$ jb %json %belt +/$ jt %json %herm-task +:: |% +$ state-0 [%0 ~] -- @@ -12,17 +18,9 @@ %- agent:dbug ^- agent:gall => |% - ++ request-tube - |= [bowl:gall from=mark to=mark next=?] - ^- card:agent:gall - :* %pass /tube/[from]/[to] - %arvo %c %warp - our q.byk ~ - :: - ?: next - [%next %c da+now /[from]/[to]] - [%sing %c da+now /[from]/[to]] - == + ++ pass-session + |= [ses=@tas tas=session-task:dill] + [%pass /dill/[ses] %arvo %d %shot ses tas] -- |_ =bowl:gall +* this . @@ -30,14 +28,7 @@ :: ++ on-init ^- (quip card:agent:gall _this) - :_ this - :: set up dill session subscription, - :: and ensure the tubes we use are in cache - :: - :~ [%pass [%view %$ ~] %arvo %d %view ~] - (request-tube bowl %blit %json |) - (request-tube bowl %json %belt |) - == + [~ this] :: ++ on-save !>([%0 ~]) ++ on-load @@ -48,54 +39,70 @@ ++ on-watch |= =path ^- (quip card:agent:gall _this) - ?> ?=([%session @ ~] path) :_ this - :: scry prompt and cursor position out of dill for initial response - :: - =/ base=^path - /dx/(scot %p our.bowl)//(scot %da now.bowl)/sessions - :~ [%give %fact ~ %blit !>(.^(blit:dill (weld base //line)))] - [%give %fact ~ %blit !>(`blit:dill`hop+.^(@ud (weld base //cursor)))] + ?> ?=([%session @ ~] path) + =* ses i.t.path + :~ :: subscribe to the requested session + :: + ::NOTE multiple views do not result in multiple subscriptions + :: because they go over the same wire/duct + :: + (pass-session ses %view ~) + :: tell session to refresh, so new client knows what's on screen + ::TODO should client be responsible for this? + :: + (pass-session ses %hail ~) == :: ++ on-arvo |= [=wire =sign-arvo] ^- (quip card:agent:gall _this) + ~| wire ?+ wire !! :: pass on dill blits for the session :: - [%view %$ ~] + [%dill @ ~] + =* ses i.t.wire ?. ?=([%dill %blit *] sign-arvo) ~| [%unexpected-sign [- +<]:sign-arvo] !! :_ this %+ turn p.sign-arvo |= =blit:dill - [%give %fact [%session %$ ~]~ %blit !>(blit)] + [%give %fact [%session ses ~]~ %blit !>(blit)] :: - :: ensure the tubes we need remain in cache + :: clean up old-style subscriptions :: - [%tube @ @ ~] - =* from i.t.wire - =* to i.t.t.wire - ?. ?=([%clay %writ *] sign-arvo) - ~| [%unexpected-sign [- +<]:sign-arvo] - !! + [%view @ ~] + =* ses i.t.wire :_ this - [(request-tube bowl from to &)]~ + [%pass wire %arvo %d %shot ses %flee ~]~ == :: ++ on-poke |= [=mark =vase] ^- (quip card:agent:gall _this) - ?. ?=(%belt mark) - ~| [%unexpected-mark mark] - !! :_ this - [%pass [%belt %$ ~] %arvo %d %belt !<(belt:dill vase)]~ + :_ ~ + ?+ mark ~|([%unexpected-mark mark] !!) + %belt (pass-session %$ %belt !<(belt:dill vase)) + %herm-task (pass-session !<(task:herm vase)) + == +:: +++ on-peek + |= =path + ^- (unit (unit cage)) + ?+ path ~ + [%x %sessions ~] + :+ ~ ~ + :- %json + !> ^- json + =- a+(turn ~(tap in -) (lead %s)) + .^((set @tas) %dy /(scot %p our.bowl)//(scot %da now.bowl)/sessions) + == :: ++ on-leave on-leave:def -++ on-peek on-peek:def +:: ++ on-agent on-agent:def ++ on-fail on-fail:def -- diff --git a/pkg/arvo/app/hood.hoon b/pkg/arvo/app/hood.hoon index 13410cda9..753560969 100644 --- a/pkg/arvo/app/hood.hoon +++ b/pkg/arvo/app/hood.hoon @@ -2,7 +2,7 @@ /+ drum=hood-drum, helm=hood-helm, kiln=hood-kiln |% +$ state - $: %15 + $: %16 drum=state:drum helm=state:helm kiln=state:kiln @@ -10,14 +10,15 @@ +$ any-state $% state [ver=?(%1 %2 %3 %4 %5 %6) lac=(map @tas fin-any-state)] - [%7 drum=state:drum helm=state:helm kiln=state-1:kiln] - [%8 drum=state:drum helm=state:helm kiln=state-1:kiln] - [%9 drum=state:drum helm=state:helm kiln=state-1:kiln] - [%10 drum=state:drum helm=state:helm kiln=state-1:kiln] - [%11 drum=state:drum helm=state:helm kiln=state-1:kiln] - [%12 drum=state:drum helm=state:helm kiln=state-1:kiln] - [%13 drum=state:drum helm=state:helm kiln=state-1:kiln] - [%14 drum=state:drum helm=state:helm kiln=state:kiln] + [%7 drum=any-state:drum helm=state:helm kiln=state-1:kiln] + [%8 drum=any-state:drum helm=state:helm kiln=state-1:kiln] + [%9 drum=any-state:drum helm=state:helm kiln=state-1:kiln] + [%10 drum=any-state:drum helm=state:helm kiln=state-1:kiln] + [%11 drum=any-state:drum helm=state:helm kiln=state-1:kiln] + [%12 drum=any-state:drum helm=state:helm kiln=state-1:kiln] + [%13 drum=any-state:drum helm=state:helm kiln=state-1:kiln] + [%14 drum=any-state:drum helm=state:helm kiln=state:kiln] + [%15 drum=any-state:drum helm=state:helm kiln=state:kiln] == +$ any-state-tuple $: drum=any-state:drum @@ -83,8 +84,7 @@ :: ?+ mark (on-poke:def mark vase) %atom poke-helm(mark %helm-atom) - %dill-belt poke-drum(mark %drum-dill-belt) - %dill-blit poke-drum(mark %drum-dill-blit) + %dill-poke poke-drum %hood-sync poke-kiln(mark %kiln-sync) %write-sec-atom poke-helm(mark %helm-write-sec-atom) == @@ -97,7 +97,7 @@ |= =path ^- step:agent:gall ?+ path (on-watch:def +<) - [%drum *] =^(c drum.state (peer:drum-core +<) [c this]) + [%dill *] =^(c drum.state (peer:drum-core +<) [c this]) == :: ++ on-agent @@ -114,7 +114,6 @@ |= [=wire syn=sign-arvo] ^- step:agent:gall ?+ wire ~|([%hood-bad-wire wire] !!) - [%drum *] =^(c drum.state (take-arvo:drum-core t.wire syn) [c this]) [%helm *] =^(c helm.state (take-arvo:helm-core t.wire syn) [c this]) [%kiln *] =^(c kiln.state (take-arvo:kiln-core t.wire syn) [c this]) == diff --git a/pkg/arvo/gen/aqua/dojo.hoon b/pkg/arvo/gen/aqua/dojo.hoon index 03d63f505..d9ef58a1d 100644 --- a/pkg/arvo/gen/aqua/dojo.hoon +++ b/pkg/arvo/gen/aqua/dojo.hoon @@ -5,8 +5,8 @@ :- %aqua-events %+ turn ^- (list unix-event) - :~ [/d/term/1 %belt %ctl `@c`%e] - [/d/term/1 %belt %ctl `@c`%u] + :~ [/d/term/1 %belt %mod %ctl `@c`%e] + [/d/term/1 %belt %mod %ctl `@c`%u] [/d/term/1 %belt %txt ((list @c) command)] [/d/term/1 %belt %ret ~] == diff --git a/pkg/arvo/lib/dill.hoon b/pkg/arvo/lib/dill.hoon new file mode 100644 index 000000000..d4cecdf14 --- /dev/null +++ b/pkg/arvo/lib/dill.hoon @@ -0,0 +1,93 @@ +:: dill: utilities for dill's data structures +:: +=, dill +|% +++ enjs + |% + ++ blit + |= =blit:dill + ^- json + =, enjs:format + %+ frond -.blit + ?- -.blit + %bel b+& + %clr b+& + %hop ?@ p.blit (numb p.blit) + (pairs 'r'^(numb r.p.blit) 'c'^(numb c.p.blit) ~) + %put a+(turn p.blit |=(c=@c s+(tuft c))) + %nel b+& + %url s+p.blit + %wyp b+& + :: + %sag + %- pairs + :~ 'path'^(path p.blit) + 'file'^s+(en:base64:mimes:html (as-octs:mimes:html (jam q.blit))) + == + :: + %sav + %- pairs + :~ 'path'^(path p.blit) + 'file'^s+(en:base64:mimes:html (as-octs:mimes:html q.blit)) + == + :: + %klr + :- %a + %+ turn p.blit + |= [=stye text=(list @c)] + %- pairs + :~ 'text'^a+(turn text |=(c=@c s+(tuft c))) + :: + :- 'stye' + %- pairs + |^ :~ 'back'^(color p.q.stye) + 'fore'^(color q.q.stye) + 'deco'^a+(turn ~(tap in p.stye) |=(d=deco ?~(d ~ s+d))) + == + ++ color + |= =tint + ?@ tint ?~(tint ~ s+tint) + =, tint + (pairs r+(numb r) g+(numb g) b+(numb b) ~) + -- + == + == + -- +:: +++ dejs + |% + ++ belt + |= jon=json + ^- belt:dill + ?: ?=([%s *] jon) + (taft p.jon) + =, dejs:format + %. jon + %- of + |^ :* mod+(ot 'mod'^mod 'key'^bot ~) + txt+(ar (cu taft so)) + bol + == + :: + ++ bol + :~ aro+(su (perk %d %l %r %u ~)) + bac+ul + del+ul + hit+(ot 'r'^ni 'c'^ni ~) + ret+ul + == + :: + ++ bot + |= j=json + ^- bolt:dill + ?+ j !! + [%s *] (taft p.j) + [%o *] ((of bol) j) + == + :: + ++ mod + |= j=json + ((su (perk %ctl %met %hyp ~)) j) + -- + -- +-- \ No newline at end of file diff --git a/pkg/arvo/lib/hood/drum.hoon b/pkg/arvo/lib/hood/drum.hoon index 01b1b2919..1a3f3e73b 100644 --- a/pkg/arvo/lib/hood/drum.hoon +++ b/pkg/arvo/lib/hood/drum.hoon @@ -1,14 +1,14 @@ /- *sole /+ sole |% -+$ any-state $%(state) -+$ state [%2 pith-2] ++$ any-state $%(state state-2) ++$ state [%3 pith] :: -++ pith-2 :: +++ pith :: $: eel=(set gill:gall) :: connect to ray=(set well:gall) :: fur=(map dude:gall (unit server)) :: servers - bin=(map bone source) :: terminals + bin=(map @ source) :: terminals == :: :: :: ++ server :: running server @@ -49,6 +49,42 @@ pom=sole-prompt :: static prompt inp=sole-command :: input state == :: +:: +:: ++$ state-2 [%2 pith-2] +:: ++$ pith-2 + $: eel=(set gill:gall) + ray=(set well:gall) + fur=(map dude:gall (unit server)) + bin=(map bone source-2) + == +:: ++$ source-2 + $: edg=_80 + off=@ud + kil=kill + inx=@ud + fug=(map gill:gall (unit target-2)) + mir=(pair @ud stub) + == +:: ++$ target-2 + $: $= blt + %+ pair + (unit dill-belt-2) + (unit dill-belt-2) + ris=(unit search) + hit=history + pom=sole-prompt + inp=sole-command + == +:: ++$ dill-belt-2 + $% [%ctl p=@c] + [%met p=@c] + dill-belt:dill + == -- :: :: :: :::: :: :: @@ -121,26 +157,34 @@ ++ en-gill :: gill to wire |= gyl=gill:gall ^- wire + ::TODO include session? [%drum %phat (scot %p p.gyl) q.gyl ~] :: ++ de-gill :: gill from wire |= way=wire ^- gill:gall ?>(?=([@ @ ~] way) [(slav %p i.way) i.t.way]) -- -:: TODO: remove .ost :: |= [hid=bowl:gall state] =* sat +<+ -=/ ost 0 -=+ (~(gut by bin) ost *source) +=/ ses=@tas %$ +=+ (~(gut by bin) ses *source) =* dev - =| moz=(list card:agent:gall) =| biz=(list dill-blit:dill) |% ++ this . +++ klr klr:format +$ state ^state :: proxy +$ any-state ^any-state :: proxy ++ on-init se-abet:this(eel (deft-fish our.hid)) +:: +++ prep + |= s=@tas + =. ses ses + =. dev (~(gut by bin) ses *source) + this +:: ++ diff-sole-effect-phat :: app event |= [way=wire fec=sole-effect] =< se-abet =< se-view @@ -150,6 +194,8 @@ :: ++ peer :: |= pax=path + =? this ?=([%dill @ ~] pax) + (prep i.t.pax) ~| [%drum-unauthorized our+our.hid src+src.hid] :: ourself ?> (team:title our.hid src.hid) :: or our own moon =< se-abet =< se-view @@ -166,15 +212,15 @@ =. ray (deft-apes our.hid lit) [~ sat] :: +++ poke-dill + |= [ses=@tas bet=dill-belt:dill] + (poke-dill-belt:(prep ses) bet) +:: ++ poke-dill-belt :: terminal event |= bet=dill-belt:dill =< se-abet =< se-view (se-belt bet) :: -++ poke-dill-blit :: terminal output - |= bit=dill-blit:dill - se-abet:(se-blit-sys bit) -:: ++ poke-start :: start app |= wel=well:gall =< se-abet =< se-view @@ -206,8 +252,7 @@ ++ poke |= [=mark =vase] ?+ mark ~|([%poke-drum-bad-mark mark] !!) - %drum-dill-belt =;(f (f !<(_+<.f vase)) poke-dill-belt) - %drum-dill-blit =;(f (f !<(_+<.f vase)) poke-dill-blit) + %dill-poke =;(f (f !<(_+<.f vase)) poke-dill) %drum-exit =;(f (f !<(_+<.f vase)) poke-exit) %drum-link =;(f (f !<(_+<.f vase)) poke-link) %drum-put =;(f (f !<(_+<.f vase)) poke-put) @@ -218,53 +263,89 @@ == :: ++ on-load - |= [hood-version=@ud old=any-state] - =< se-abet =< se-view - =. sat old - =. dev (~(gut by bin) ost *source) - =? ..on-load (lte hood-version %4) - ~> %slog.0^leaf+"drum: starting os1 agents" - => (se-born | %home %s3-store) - => (se-born | %home %contact-view) - => (se-born | %home %contact-hook) - => (se-born | %home %contact-store) - => (se-born | %home %metadata-hook) - => (se-born | %home %metadata-store) - => (se-born | %home %goad) - ~> %slog.0^leaf+"drum: resubscribing to %dojo and %chat-cli" - => (se-drop:(se-pull our.hid %dojo) | our.hid %dojo) - (se-drop:(se-pull our.hid %chat-cli) | our.hid %chat-cli) - =? ..on-load (lte hood-version %5) - (se-born | %home %file-server) - =? ..on-load (lte hood-version %7) - (se-born | %home %glob) - =? ..on-load (lte hood-version %8) - => (se-born | %home %group-push-hook) - (se-born | %home %group-pull-hook) - =? ..on-load (lte hood-version %9) - (se-born | %home %graph-store) - =? ..on-load (lte hood-version %10) - => (se-born | %home %graph-push-hook) - (se-born | %home %graph-pull-hook) - =? ..on-load (lte hood-version %11) - => (se-born | %home %hark-graph-hook) - => (se-born | %home %hark-group-hook) - => (se-born | %home %hark-chat-hook) - => (se-born | %home %hark-store) - => (se-born | %home %observe-hook) - => (se-born | %home %metadata-pull-hook) - => (se-born | %home %metadata-push-hook) - (se-born | %home %herm) - =? ..on-load (lte hood-version %12) - => (se-born | %home %contact-push-hook) - => (se-born | %home %contact-pull-hook) - => (se-born | %home %settings-store) - (se-born | %home %group-view) - =? ..on-load (lte hood-version %13) - (se-born | %home %dm-hook) - =? ..on-load (lte hood-version %15) - (se-born | %home %notify) - ..on-load + |^ |= [hood-version=@ud old=any-state] + =< se-abet =< se-view + =. sat (load-state old) + =. dev (~(gut by bin) ses *source) + (load-apps hood-version) + :: + ++ load-state + |= old=any-state + ^- state + ?- -.old + %3 old + %2 [%3 (pith-2-to-3 +.old)] + == + :: + ++ pith-2-to-3 + |= p=pith-2 + ^- pith + p(bin (~(run by bin.p) source-2-to-3)) + :: + ++ source-2-to-3 + |= s=source-2 + ^- source + s(fug (~(run by fug.s) |=(t=(unit target-2) (bind t target-2-to-3)))) + :: + ++ target-2-to-3 + |= t=target-2 + ^- target + :_ +.t + :- (bind p.blt.t belt-2-to-3) + (bind q.blt.t belt-2-to-3) + :: + ++ belt-2-to-3 + |= b=dill-belt-2 + ^- dill-belt:dill + ?. ?=(?(%ctl %met) -.b) b + [%mod -.b p.b] + :: + ++ load-apps + |= hood-version=@ud + =? ..on-load (lte hood-version %4) + ~> %slog.0^leaf+"drum: starting os1 agents" + => (se-born | %home %s3-store) + => (se-born | %home %contact-view) + => (se-born | %home %contact-hook) + => (se-born | %home %contact-store) + => (se-born | %home %metadata-hook) + => (se-born | %home %metadata-store) + => (se-born | %home %goad) + ~> %slog.0^leaf+"drum: resubscribing to %dojo and %chat-cli" + => (se-drop:(se-pull our.hid %dojo) | our.hid %dojo) + (se-drop:(se-pull our.hid %chat-cli) | our.hid %chat-cli) + =? ..on-load (lte hood-version %5) + (se-born | %home %file-server) + =? ..on-load (lte hood-version %7) + (se-born | %home %glob) + =? ..on-load (lte hood-version %8) + => (se-born | %home %group-push-hook) + (se-born | %home %group-pull-hook) + =? ..on-load (lte hood-version %9) + (se-born | %home %graph-store) + =? ..on-load (lte hood-version %10) + => (se-born | %home %graph-push-hook) + (se-born | %home %graph-pull-hook) + =? ..on-load (lte hood-version %11) + => (se-born | %home %hark-graph-hook) + => (se-born | %home %hark-group-hook) + => (se-born | %home %hark-chat-hook) + => (se-born | %home %hark-store) + => (se-born | %home %observe-hook) + => (se-born | %home %metadata-pull-hook) + => (se-born | %home %metadata-push-hook) + (se-born | %home %herm) + =? ..on-load (lte hood-version %12) + => (se-born | %home %contact-push-hook) + => (se-born | %home %contact-pull-hook) + => (se-born | %home %settings-store) + (se-born | %home %group-view) + =? ..on-load (lte hood-version %13) + (se-born | %home %dm-hook) + =? ..on-load (lte hood-version %15) + (se-born | %home %notify) + ..on-load + -- :: ++ reap-phat :: ack connect |= [way=wire saw=(unit tang)] @@ -277,12 +358,6 @@ :: (se-drop & gyl) :: -++ take-arvo - |= [=wire =sign-arvo] - %+ take-onto wire - ?> ?=(%onto +<.sign-arvo) - +>.sign-arvo -:: ++ take-coup-phat :: ack poke |= [way=wire saw=(unit tang)] =< se-abet =< se-view @@ -293,19 +368,6 @@ :_ u.saw >[%drum-coup-fail src.hid gyl]< :: -++ take-onto :: ack start - |= [way=wire saw=(each suss:gall tang)] - =< se-abet =< se-view - ?> ?=([@ @ ~] way) - ?> (~(has by fur) i.t.way) - =/ wel=well:gall [i.way i.t.way] - ?- saw - [%| *] (se-dump p.saw) - [%& *] ?> =(q.wel p.p.saw) - :: =. +>.$ (se-text "live {}") - +>.$(fur (~(put by fur) q.wel `[p.wel %da r.p.saw])) - == -:: ++ take-agent |= [=wire =sign:agent:gall] ?+ wire ~|([%drum-bad-take-agent wire -.sign] !!) @@ -333,12 +395,13 @@ ++ se-abet :: resolve ^- (quip card:agent:gall state) =. . se-subze:se-adze:se-subit:se-adit - :_ sat(bin (~(put by bin) ost dev)) + :_ sat(bin (~(put by bin) ses dev)) ^- (list card:agent:gall) ?~ biz (flop moz) :_ (flop moz) =/ =dill-blit:dill ?~(t.biz i.biz [%mor (flop biz)]) - [%give %fact ~[/drum] %dill-blit !>(dill-blit)] + ::TODO remove /drum after dill cleans up + [%give %fact ~[/drum /dill/[ses]] %dill-blit !>(dill-blit)] :: ++ se-adit :: update servers ^+ this @@ -423,14 +486,14 @@ (se-peer gil) :: ++ se-subze :: downdate connections - =< .(dev (~(got by bin) ost)) - =. bin (~(put by bin) ost dev) + =< .(dev (~(got by bin) ses)) + =. bin (~(put by bin) ses dev) ^+ . %- ~(rep by bin) =< .(con +>) - |: $:,[[ost=bone dev=source] con=_.] ^+ con - =+ xeno=se-subze-local:%_(con ost ost, dev dev) - xeno(ost ost.con, dev dev.con, bin (~(put by bin) ost dev.xeno)) + |: $:,[[ses=@tas dev=source] con=_.] ^+ con + =+ xeno=se-subze-local:%_(con ses ses, dev dev) + xeno(ses ses.con, dev dev.con, bin (~(put by bin) ses dev.xeno)) :: ++ se-subze-local ^+ . @@ -445,7 +508,7 @@ ++ se-aint :: ignore result |= gyl=gill:gall ^- ? - ?. (~(has by bin) ost) & + ?. (~(has by bin) ses) & =+ gyr=(~(get by fug) gyl) |(?=(~ gyr) ?=(~ u.gyr)) :: @@ -554,6 +617,21 @@ leaf+(weld (scag (sub edg 3) tape) "...") leaf+tape :: +++ se-blin :: print and newline + |= $= lin + $~ [%put ~] + $>(?(%put %klr) dill-blit:dill) + ^+ +> + :: newline means we need to redraw the prompt, + :: so update the prompt mirror accordingly. + :: + =. mir [0 ~] + ::TODO doing hops and wyps conditionally based on the mirror state seems + :: better, but doesn't cover edge cases. results in dojo's ">=" being + :: rendered alongside the prompt in scrollback, for example. + :: figure out a way to make that work! + (se-blit %mor [%hop 0] [%wyp ~] lin [%nel ~] ~) +:: ++ se-dump :: print tanks |= tac=(list tank) ^+ +> @@ -564,7 +642,7 @@ ?. ((sane %t) (crip i.wol)) :: XX upstream validation ~& bad-text+<`*`i.wol> $(wol t.wol) - $(wol t.wol, +>.^$ (se-blit %out (tuba i.wol))) + $(wol t.wol, +>.^$ (se-blin %put (tuba i.wol))) :: ++ se-join :: confirm connection |= gyl=gill:gall @@ -597,15 +675,16 @@ :: ++ se-blit-sys :: output to system |= bil=dill-blit:dill ^+ +> - (se-emit %give %fact ~[/drum] %dill-blit !>(bil)) + ::TODO remove /drum after dill cleans up + (se-emit %give %fact ~[/drum /dill/[ses]] %dill-blit !>(bil)) :: ++ se-show :: show buffer, raw |= lin=(pair @ud stub) ^+ +> ?: =(mir lin) +> - =. +> ?:(=(p.mir p.lin) +> (se-blit %hop p.lin)) - =. +> ?:(=(q.mir q.lin) +> (se-blit %pom q.lin)) - +>(mir lin) + %- se-blit(mir lin) + ?: =(q.mir q.lin) [%hop p.lin] + mor+[[%hop 0] [%wyp ~] [%klr q.lin] [%hop p.lin] ~] :: ++ se-just :: adjusted buffer |= [pom=stub lin=(pair @ud (list @c))] @@ -643,7 +722,7 @@ ?. ((sane %t) (crip txt)) :: XX upstream validation ~& bad-text+<`*`txt> +> - (se-blit %out (tuba txt)) + (se-blin %put (tuba txt)) :: ++ se-poke :: send a poke |= [gyl=gill:gall par=cage] @@ -651,6 +730,7 @@ :: ++ se-peer :: send a peer |= gyl=gill:gall + ::TODO include session =/ =path /sole/(cat 3 'drum_' (scot %p our.hid)) %- se-emit(fug (~(put by fug) gyl ~)) [%pass (en-gill gyl) %agent gyl %watch path] @@ -711,13 +791,19 @@ ?< ?=([?(%cru %hey %rez %yow) *] bet) :: target-specific =. blt [q.blt `bet] :: remember belt ?- bet + @ (ta-txt bet ~) [%aro *] (ta-aro p.bet) [%bac *] ta-bac - [%ctl *] (ta-ctl p.bet) [%del *] ta-del - [%met *] (ta-met p.bet) + [%hit *] (ta-hit +.bet) [%ret *] ta-ret [%txt *] (ta-txt p.bet) + :: + [%mod *] + ?+ mod.bet $(bet key.bet) + %ctl (ta-ctl key.bet) + %met (ta-met key.bet) + == == :: ++ ta-det :: send edit @@ -741,7 +827,7 @@ (ta-hom %del (dec pos.inp)) :: ++ ta-ctl :: hear control - |= key=@ud + |= key=bolt:dill ^+ +> =. ris ?.(?=(?(%g %r) key) ~ ris) ?+ key ta-bel @@ -762,7 +848,7 @@ ?: =(pos.inp len) ta-bel (ta-kil %r [pos.inp (sub len pos.inp)]) - %l +>(..ta (se-blit %clr ~)) + %l +>(..ta (se-blit(q.mir ~) %clr ~)) %n (ta-aro %d) %p (ta-aro %u) %r ?~ ris @@ -795,6 +881,15 @@ ta-bel (ta-hom %del pos.inp) :: + ++ ta-hit :: hear click + |= [r=@ud c=@ud] + ^+ +> + ?. =(0 r) +> + =/ pol=@ud + (lent-char:klr (make:klr cad.pom)) + ?: (lth c pol) +>.$ + +>.$(pos.inp (min (sub c pol) (lent buf.say.inp))) + :: ++ ta-erl :: hear local error |= pos=@ud ta-bel(pos.inp (min pos (lent buf.say.inp))) @@ -806,14 +901,13 @@ ++ ta-fec :: apply effect |= fec=sole-effect ^+ +> - ?- fec + ?+ fec +>(..ta (se-blit fec)) [%bel *] ta-bel [%blk *] +> [%bye *] +>(..ta (se-klin gyl)) - [%clr *] +>(..ta (se-blit fec)) [%det *] (ta-got +.fec) [%err *] (ta-err p.fec) - [%klr *] +>(..ta (se-blit %klr (make:klr p.fec))) + [%klr *] +>(..ta (se-blin %klr (make:klr p.fec))) [%mor *] |- ^+ +>.^$ ?~ p.fec +>.^$ $(p.fec t.p.fec, +>.^$ ^$(fec i.p.fec)) @@ -821,10 +915,8 @@ [%pro *] (ta-pro +.fec) [%tab *] +>(..ta (se-tab p.fec)) [%tan *] +>(..ta (se-dump p.fec)) - [%sag *] +>(..ta (se-blit fec)) - [%sav *] +>(..ta (se-blit fec)) [%txt *] +>(..ta (se-text p.fec)) - [%url *] +>(..ta (se-blit fec)) + [%url *] +>(..ta (se-text:(se-blit fec) (trip p.fec))) == :: ++ ta-dog :: change cursor @@ -876,8 +968,8 @@ kil ?. ?& ?=(^ old.kil) ?=(^ p.blt) - ?| ?=([%ctl ?(%k %u %w)] u.p.blt) - ?=([%met ?(%d %bac)] u.p.blt) + ?| ?=([%mod %ctl ?(%k %u %w)] u.p.blt) + ?=([%mod %met ?(%d [%bac ~])] u.p.blt) == == %= kil :: prepend num +(num.kil) @@ -894,17 +986,18 @@ == :: ++ ta-met :: meta key - |= key=@ud + |= key=bolt:dill ^+ +> =. ris ~ ?+ key ta-bel - %dot ?. &(?=(^ old.hit) ?=(^ i.old.hit)) :: last "arg" from hist + %'.' ?. &(?=(^ old.hit) ?=(^ i.old.hit)) :: last "arg" from hist ta-bel =+ old=`(list @c)`i.old.hit =+ sop=(ta-jump(buf.say.inp old) %l %ace (lent old)) (ta-hom (cat:edit pos.inp (slag sop old))) :: - %bac ?: =(0 pos.inp) :: kill left-word + [%bac ~] + ?: =(0 pos.inp) :: kill left-word ta-bel =+ sop=(ta-pos %l %edg pos.inp) (ta-kil %l [(sub pos.inp sop) sop]) @@ -960,8 +1053,8 @@ :: %y ?. ?& ?=(^ old.kil) :: rotate & yank ?=(^ p.blt) - ?| ?=([%ctl %y] u.p.blt) - ?=([%met %y] u.p.blt) + ?| ?=([%mod %ctl %y] u.p.blt) + ?=([%mod %met %y] u.p.blt) == == ta-bel =+ las=(lent ta-yan) @@ -1139,82 +1232,4 @@ ?: |(?=(~ a) (alnm i.a)) i $(i +(i), a t.a) -- -:: -++ klr :: styx/stub engine - =, dill - |% - ++ make :: stub from styx - |= a=styx ^- stub - =| b=stye - %+ reel - |- ^- stub - %- zing %+ turn a - |= a=$@(@t (pair styl styx)) - ?@ a [b (tuba (trip a))]~ - ^$(a q.a, b (styd p.a b)) - :: - |= [a=(pair stye (list @c)) b=stub] - ?~ b [a ~] - ?. =(p.a p.i.b) [a b] - [[p.a (weld q.a q.i.b)] t.b] - :: - ++ styd :: stye from styl - |= [a=styl b=stye] ^+ b :: with inheritance - :+ ?~ p.a p.b - ?~ u.p.a ~ - (~(put in p.b) u.p.a) - (fall p.q.a p.q.b) - (fall q.q.a q.q.b) - :: - ++ lent-char - |= a=stub ^- @ - (roll (lnts-char a) add) - :: - ++ lnts-char :: stub pair tail lengths - |= a=stub ^- (list @) - %+ turn a - |= a=(pair stye (list @c)) - (lent q.a) - :: - ++ brek :: index + incl-len of - |= [a=@ b=(list @)] :: stub pair w= idx a - =| [c=@ i=@] - |- ^- (unit (pair @ @)) - ?~ b ~ - =. c (add c i.b) - ?: (gte c a) - `[i c] - $(i +(i), b t.b) - :: - ++ slag :: slag stub, keep stye - |= [a=@ b=stub] - ^- stub - =+ c=(lnts-char b) - =+ i=(brek a c) - ?~ i b - =+ r=(^slag +(p.u.i) b) - ?: =(a q.u.i) - r - =+ n=(snag p.u.i b) - :_ r :- p.n - (^slag (sub (snag p.u.i c) (sub q.u.i a)) q.n) - :: - ++ scag :: scag stub, keep stye - |= [a=@ b=stub] - ^- stub - =+ c=(lnts-char b) - =+ i=(brek a c) - ?~ i b - ?: =(a q.u.i) - (^scag +(p.u.i) b) - %+ welp - (^scag p.u.i b) - =+ n=(snag p.u.i b) - :_ ~ :- p.n - (^scag (sub (snag p.u.i c) (sub q.u.i a)) q.n) - :: - ++ swag :: swag stub, keep stye - |= [[a=@ b=@] c=stub] - (scag b (slag a c)) - -- -- diff --git a/pkg/arvo/lib/ph/util.hoon b/pkg/arvo/lib/ph/util.hoon index 53979b425..46e47947e 100644 --- a/pkg/arvo/lib/ph/util.hoon +++ b/pkg/arvo/lib/ph/util.hoon @@ -28,8 +28,8 @@ %+ send-events-to who ^- (list unix-event) :~ - [/d/term/1 %belt %ctl `@c`%e] - [/d/term/1 %belt %ctl `@c`%u] + [/d/term/1 %belt %mod %ctl `@c`%e] + [/d/term/1 %belt %mod %ctl `@c`%u] [/d/term/1 %belt %txt ((list @c) what)] [/d/term/1 %belt %ret ~] == @@ -40,7 +40,7 @@ |= [who=ship what=term] ^- (list ph-event) %+ send-events-to who - :~ [/d/term/1 %belt %ctl (,@c what)] + :~ [/d/term/1 %belt %mod %ctl (,@c what)] == :: :: Inject a file into a ship @@ -67,7 +67,7 @@ :: %+ lien p.q.uf |= =blit:dill - ?. ?=(%lin -.blit) + ?. ?=(%put -.blit) | !=(~ (find what p.blit)) == diff --git a/pkg/arvo/mar/belt.hoon b/pkg/arvo/mar/belt.hoon index 1c5a6e1ea..acbf284c9 100644 --- a/pkg/arvo/mar/belt.hoon +++ b/pkg/arvo/mar/belt.hoon @@ -1,5 +1,7 @@ :: belt: runtime belt structure :: +/+ dill +:: |_ =belt:dill ++ grad %noun :: +grab: convert from @@ -7,18 +9,7 @@ ++ grab |% ++ noun belt:dill - ++ json - ^- $-(^json belt:dill) - =, dejs:format - %- of - :~ aro+(su (perk %d %l %r %u ~)) - bac+ul - ctl+(cu taft so) - del+ul - met+(cu taft so) - ret+ul - txt+(ar (cu taft so)) - == + ++ json belt:dejs:dill -- :: +grow: convert to :: diff --git a/pkg/arvo/mar/blit.hoon b/pkg/arvo/mar/blit.hoon index 4c23c5705..4b852aa60 100644 --- a/pkg/arvo/mar/blit.hoon +++ b/pkg/arvo/mar/blit.hoon @@ -1,5 +1,7 @@ :: blit: runtime blit structure :: +/+ dill +:: |_ =blit:dill ++ grad %noun :: +grab: convert from @@ -13,49 +15,6 @@ ++ grow |% ++ noun blit - ++ json - ^- ^json - =, enjs:format - %+ frond -.blit - ?- -.blit - %bel b+& - %clr b+& - %hop (numb p.blit) - %lin a+(turn p.blit |=(c=@c s+(tuft c))) - %mor b+& - %url s+p.blit - :: - %sag - %- pairs - :~ 'path'^(path p.blit) - 'file'^s+(en:base64:mimes:html (as-octs:mimes:html (jam q.blit))) - == - :: - %sav - %- pairs - :~ 'path'^(path p.blit) - 'file'^s+(en:base64:mimes:html (as-octs:mimes:html q.blit)) - == - :: - %klr - :- %a - %+ turn p.blit - |= [=stye text=(list @c)] - %- pairs - :~ 'text'^a+(turn text |=(c=@c s+(tuft c))) - :: - :- 'stye' - %- pairs - |^ :~ 'back'^(color p.q.stye) - 'fore'^(color q.q.stye) - 'deco'^a+(turn ~(tap in p.stye) |=(d=deco ?~(d ~ s+d))) - == - ++ color - |= =tint - ?@ tint ?~(tint ~ s+tint) - s+(crip ((x-co:co 6) (rep 3 ~[b g r]:tint))) - -- - == - == + ++ json (blit:enjs:dill blit) -- -- diff --git a/pkg/arvo/mar/dill/belt.hoon b/pkg/arvo/mar/dill/belt.hoon index 1677b6ef1..5d50dcd98 100644 --- a/pkg/arvo/mar/dill/belt.hoon +++ b/pkg/arvo/mar/dill/belt.hoon @@ -45,8 +45,8 @@ =+ cha=(tuba (trip q.kev)) ?> ?=([@ ~] cha) :: of a single character ?+ mod !! :: modified by one buckykey - [%ctrl ~ ~] [%ctl i.cha] - [%alt ~ ~] [%met i.cha] + [%ctrl ~ ~] [%mod %ctl i.cha] + [%alt ~ ~] [%mod %met i.cha] == ?@ q.kev [%txt (tuba (trip q.kev))] diff --git a/pkg/arvo/mar/dill/blit.hoon b/pkg/arvo/mar/dill/blit.hoon index 77e5cecf4..5ec9b08cb 100644 --- a/pkg/arvo/mar/dill/blit.hoon +++ b/pkg/arvo/mar/dill/blit.hoon @@ -19,8 +19,10 @@ ^- ^json ?+ -.dib ~|(unsupported-blit+-.dib !!) %mor [%a (turn p.dib |=(a=dill-blit:dill json(dib a)))] - %hop (frond %hop (numb p.dib)) - ?(%pro %out) (frond -.dib (tape (tufa p.dib))) + %hop %+ frond %hop + ?@ p.dib (numb p.dib) + (pairs 'r'^(numb r.p.dib) 'c'^(numb c.p.dib) ~) + %put (frond -.dib (tape (tufa p.dib))) ?(%bel %clr) (frond %act %s -.dib) == -- diff --git a/pkg/arvo/mar/herm/task.hoon b/pkg/arvo/mar/herm/task.hoon new file mode 100644 index 000000000..93757418e --- /dev/null +++ b/pkg/arvo/mar/herm/task.hoon @@ -0,0 +1,46 @@ +:: task: herm task for passthrough to dill +:: +/- herm +/+ dill +:: +|_ =task:herm +++ grad %noun +:: +grab: convert from +:: +++ grab + |% + ++ noun task:herm + :: + ++ json + |= jon=^json + ^+ task + ~| jon + ?> ?=([%o *] jon) + =+ ses=(~(got by p.jon) 'session') + ?> ?=([%s *] ses) + :- ?: =('' p.ses) %$ + (slav %tas p.ses) + =. p.jon (~(del by p.jon) 'session') + %. jon + =, dejs:format + |^ task + ++ task + %- of + :~ belt+belt:dejs:^dill + blew+(ot 'w'^ni 'h'^ni ~) + hail+ul + open+(ot 'term'^(se %tas) 'apps'^(ar gill) ~) + shut+ul + == + :: + ++ gill + (ot 'who'^(se %p) 'app'^(se %tas) ~) + -- + -- +:: +grow: convert to +:: +++ grow + |% + ++ noun task + -- +-- diff --git a/pkg/arvo/sur/herm.hoon b/pkg/arvo/sur/herm.hoon new file mode 100644 index 000000000..eab8cbb1b --- /dev/null +++ b/pkg/arvo/sur/herm.hoon @@ -0,0 +1,9 @@ +:: herm: stand-in for term.c with http interface +:: +|% ++$ task + $~ [%$ %hail ~] + $: session=@tas + task=$>(?(%open %shut %belt %blew %hail) session-task:dill) + == +-- diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index e20f41ec9..ea7757413 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -741,7 +741,6 @@ [%hill p=(list @tas)] :: mount points [%done error=(unit error:ames)] :: ames message (n)ack [%mere p=(each (set path) (pair term tang))] :: merge result - [%note p=@tD q=tank] :: debug message [%ogre p=@tas] :: delete mount point [%rule red=dict wit=dict] :: node r+w permissions [%writ p=riot] :: response @@ -1031,9 +1030,7 @@ ++ dill ^? |% +$ gift :: out result <-$ - $% [%bbye ~] :: reset prompt - [%blit p=(list blit)] :: terminal output - [%burl p=@t] :: activate url + $% [%blit p=(list blit)] :: terminal output [%logo ~] :: logout [%meld ~] :: unify memory [%pack ~] :: compact memory @@ -1041,29 +1038,32 @@ == :: +$ task :: in request ->$ $~ [%vega ~] :: - $% [%belt p=belt] :: terminal input - [%blew p=blew] :: terminal config - [%boot lit=? p=*] :: weird %dill boot + $% [%boot lit=? p=*] :: weird %dill boot [%crop p=@ud] :: trim kernel state [%crud p=@tas q=(list tank)] :: print error - [%flee session=~] :: unwatch session [%flog p=flog] :: wrapped error - [%flow p=@tas q=(list gill:gall)] :: terminal config - [%hail ~] :: terminal refresh [%heft ~] :: memory report - [%hook ~] :: this term hung up - [%harm ~] :: all terms hung up $>(%init vane-task) :: after gall ready [%meld ~] :: unify memory - [%noop ~] :: no operation [%pack ~] :: compact memory - [%talk p=tank] :: - [%text p=tape] :: - [%view session=~] :: watch session blits + [%shot ses=@tas task=session-task] :: task for session + [%talk p=(list tank)] :: print tanks + [%text p=tape] :: print tape $>(%trim vane-task) :: trim state $>(%vega vane-task) :: report upgrade [%verb ~] :: verbose mode [%knob tag=term level=?(%hush %soft %loud)] :: error verbosity + session-task :: for default session + == :: + :: :: + +$ session-task :: session request + $% [%belt p=belt] :: terminal input + [%blew p=blew] :: terminal config + [%flee ~] :: unwatch session + [%hail ~] :: terminal refresh + [%open p=dude:gall q=(list gill:gall)] :: setup session + [%shut ~] :: close session + [%view ~] :: watch session blits == :: :: :::: :: (1d2) @@ -1071,14 +1071,10 @@ +$ blew [p=@ud q=@ud] :: columns rows +$ belt :: client input $? bolt :: simple input - $% [%mod mod=?(%ctl %met %hyp) key=bolt] :: w/ modifier + [%mod mod=?(%ctl %met %hyp) key=bolt] :: w/ modifier [%txt p=(list @c)] :: utf32 text ::TODO consider moving %hey, %rez, %yow here :: - ::TMP forward backwards-compatibility :: - :: :: - [%ctl p=@c] :: - [%met p=@c] :: - == == :: + == :: +$ bolt :: simple input $@ @c :: simple keystroke $% [%aro p=?(%d %l %r %u)] :: arrow key @@ -1087,43 +1083,29 @@ [%hit r=@ud c=@ud] :: mouse click [%ret ~] :: return == :: - +$ blit :: old blit + +$ blit :: client output $% [%bel ~] :: make a noise [%clr ~] :: clear the screen - [%hop p=@ud] :: set cursor position - [%klr p=stub] :: set styled line - [%lin p=(list @c)] :: set current line - [%mor ~] :: newline + [%hop p=$@(@ud [r=@ud c=@ud])] :: set cursor col/pos + [%klr p=stub] :: put styled + [%put p=(list @c)] :: put text at cursor + [%nel ~] :: newline [%sag p=path q=*] :: save to jamfile [%sav p=path q=@] :: save to file [%url p=@t] :: activate url + [%wyp ~] :: wipe cursor line == :: - +$ dill-belt :: new belt - $% [%aro p=?(%d %l %r %u)] :: arrow key - [%bac ~] :: true backspace + +$ dill-belt :: arvo input + $% belt :: client input [%cru p=@tas q=(list tank)] :: echo error - [%ctl p=@] :: control-key - [%del ~] :: true delete [%hey ~] :: refresh - [%met p=@] :: meta-key - [%ret ~] :: return [%rez p=@ud q=@ud] :: resize, cols, rows - [%txt p=(list @c)] :: utf32 text [%yow p=gill:gall] :: connect to app == :: - +$ dill-blit :: new blit - $% [%bel ~] :: make a noise - [%clr ~] :: clear the screen - [%hop p=@ud] :: set cursor position - [%klr p=stub] :: styled text + +$ dill-blit :: arvo output + $% blit :: client output [%mor p=(list dill-blit)] :: multiple blits - [%pom p=stub] :: styled prompt - [%pro p=(list @c)] :: show as cursor+line [%qit ~] :: close console - [%out p=(list @c)] :: send output line - [%sag p=path q=*] :: save to jamfile - [%sav p=path q=@] :: save to file - [%url p=@t] :: activate url == :: +$ flog :: sent to %dill $% [%crop p=@ud] :: trim kernel state @@ -1134,6 +1116,11 @@ [%text p=tape] :: [%verb ~] :: verbose mode == :: + :: :: + +$ poke :: dill to userspace + $: ses=@tas :: target session + dill-belt :: input + == :: -- ::dill :: :::: :::: ++eyre :: (1e) http-server @@ -1634,7 +1621,6 @@ +$ gift :: outgoing result $% [%boon payload=*] :: ames response [%done error=(unit error:ames)] :: ames message (n)ack - [%onto p=(each suss tang)] :: about agent [%unto p=sign:agent] :: == :: +$ task :: incoming request @@ -2163,9 +2149,6 @@ :: %ames: hear packet :: $>(%hear task:ames) - :: %dill: hangup - :: - $>(%hook task:dill) :: %clay: external edit :: $>(%into task:clay) @@ -2181,6 +2164,9 @@ :: %eyre: starts handling an backdoor http request :: $>(%request-local task:eyre) + :: %dill: close session + :: + $>(%shut task:dill) :: %behn: wakeup :: $>(%wake task:behn) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 2f2281e4b..06fecce26 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -319,7 +319,10 @@ task :: == :: $: %d :: to %dill - $>(%flog task:dill) :: + $> $? %flog :: + %text :: + == :: + task:dill :: == :: $: %g :: to %gall $>(%deal task:gall) :: @@ -343,7 +346,6 @@ == == :: $: %clay :: $> $? %mere :: - %note :: %writ :: == :: gift :: @@ -1890,7 +1892,8 @@ |= [prefix=@tD paths=(set path)] %+ turn ~(tap in paths) |= =path - [u.hun %give %note prefix (path-to-tank path)] + ^- move + [u.hun %pass /note %d %text prefix ' ' ~(ram re (path-to-tank path))] :: ++ path-to-tank |= =path @@ -4788,7 +4791,6 @@ q.p.p.+.hin [~ ..^$] :: - %note [[hen %give +.hin]~ ..^$] %wake :: TODO: handle behn errors :: diff --git a/pkg/arvo/sys/vane/dill.hoon b/pkg/arvo/sys/vane/dill.hoon index fa15461fe..5423e60d4 100644 --- a/pkg/arvo/sys/vane/dill.hoon +++ b/pkg/arvo/sys/vane/dill.hoon @@ -8,27 +8,25 @@ -- :: => |% :: console protocol +$ axle :: - $: %4 ::TODO replace ducts with session ids :: + $: %5 :: hey=(unit duct) :: default duct - dug=(map duct axon) :: conversations - eye=(jug duct duct) :: outside listeners + dug=(map @tas axon) :: conversations + eye=(jug @tas duct) :: outside listeners lit=? :: boot in lite mode $= veb :: vane verbosities $~ (~(put by *(map @tas log-level)) %hole %soft) :: quiet packet crashes (map @tas log-level) :: == :: -+$ axon :: dill per duct ++$ axon :: dill session $: ram=term :: console program tem=(unit (list dill-belt)) :: pending, reverse wid=_80 :: terminal width - pos=@ud :: cursor position - see=$%([%lin (list @c)] [%klr stub]) :: current line == :: +$ log-level ?(%hush %soft %loud) :: none, line, full -- => :: |% :: protocol outward +$ mess :: - $% [%dill-belt p=(hypo dill-belt)] :: + $% [%dill-poke p=(hypo poke)] :: == :: +$ move [p=duct q=(wind note gift)] :: local move +$ note :: out request $-> @@ -72,7 +70,6 @@ == == :: $: %clay :: $> $? %mere :: - %note :: %writ :: == :: gift:clay :: @@ -81,10 +78,7 @@ $>(%blit gift:dill) :: == :: $: %gall :: - $> $? %onto :: - %unto :: - == :: - gift:gall :: + $>(%unto gift:gall) :: == == :: :::::::: :: dill tiles -- @@ -94,39 +88,27 @@ |% ++ as :: per cause =| moz=(list move) - |_ [hen=duct axon] + |_ [hen=duct ses=@tas axon] ++ abet :: resolve ^- [(list move) axle] - [(flop moz) all(dug (~(put by dug.all) hen +<+))] + [(flop moz) all(dug (~(put by dug.all) ses +<+>))] :: ++ call :: receive input |= kyz=task ^+ +> ?+ -.kyz ~& [%strange-kiss -.kyz] +> - %flow +> - %harm +> %hail (send %hey ~) - %text (from %out (tuba p.kyz)) + %belt (send `dill-belt`p.kyz) + %talk (talk p.kyz) + %text (fore (tuba p.kyz) ~) %crud :: (send `dill-belt`[%cru p.kyz q.kyz]) (crud p.kyz q.kyz) - %blew (send %rez p.p.kyz q.p.kyz) + %blew (send(wid p.p.kyz) %rez p.p.kyz q.p.kyz) %heft (pass /whey %$ whey/~) %meld (dump kyz) %pack (dump kyz) %crop (dump trim+p.kyz) %verb (pass /verb %$ kyz) - :: - %belt - %- send - ::TMP forwards compatibility with next-dill - :: - ?@ p.kyz [%txt p.kyz ~] - ?: ?=(%hit -.p.kyz) [%txt ~] - ?. ?=(%mod -.p.kyz) p.kyz - =/ =@c - ?@ key.p.kyz key.p.kyz - ?:(?=(?(%bac %del %ret) -.key.p.kyz) `@`-.key.p.kyz ~-) - ?:(?=(%met mod.p.kyz) [%met c] [%ctl c]) == :: ++ crud @@ -136,30 +118,30 @@ =/ lev=log-level (~(gut by veb.all) err %loud) :: apply log level for this error tag :: - =/ =wall - ?- lev - %hush ~ - %soft ~["crud: %{(trip err)} event failed"] - %loud :- "crud: %{(trip err)} event failed" - %- zing - %+ turn (flop tac) - |=(a=tank (~(win re a) [0 wid])) - == - |- ^+ +>.^$ - ?~ wall +>.^$ - $(wall t.wall, +>.^$ (from %out (tuba i.wall))) + ?- lev + %hush +>.$ + %soft (fore (tuba "crud: %{(trip err)} event failed") ~) + %loud (talk leaf+"crud: %{(trip err)} event failed" (flop tac)) + == + :: + ++ talk + |= tac=(list tank) + %- fore + %- zing + %+ turn tac + |= a=tank + (turn (~(win re a) [0 wid]) tuba) :: ++ dump :: pass down to hey |= git=gift ?> ?=(^ hey.all) +>(moz [[u.hey.all %give git] moz]) :: - ++ done :: return gift + ++ done :: gift to viewers |= git=gift =- +>.$(moz (weld - moz)) %+ turn - :- hen - ~(tap in (~(get ju eye.all) hen)) + ~(tap in (~(get ju eye.all) ses)) |=(=duct [duct %give git]) :: ++ deal :: pass to %gall @@ -170,6 +152,30 @@ |= [=wire =note] +>(moz :_(moz [hen %pass wire note])) :: + ++ fore :: send dill output + ::NOTE there are still implicit assumptions + :: about the underlying console app's + :: semantics here. specifically, trailing + :: newlines are important to not getting + :: overwritten by the drum prompt, and a + :: bottom-of-screen cursor position gives + :: nicest results. a more agnostic solution + :: will need to replace this arm, someday. + :: perhaps +send this to .ram instead? + :: + |= liz=(list (list @c)) + ~? !=(%$ ses) [%d %foreing-in-session ses] + ^+ +> + =. +> + =| biz=(list blit) + |- ^+ +>.^$ + ?~ liz (done %blit [%hop 0] [%wyp ~] biz) + $(liz t.liz, biz (welp biz [%put i.liz] [%nel ~] ~)) + :: since dill is acting on its own accord, + :: we %hey the term app so it may clean up. + :: + (send %hey ~) + :: ++ from :: receive blit |= bit=dill-blit ^+ +> @@ -177,34 +183,6 @@ |- ^+ +>.^$ ?~ p.bit +>.^$ $(p.bit t.p.bit, +>.^$ ^$(bit i.p.bit)) - ?: ?=(%out -.bit) - %+ done %blit - :~ [%lin p.bit] - [%mor ~] - see - [%hop pos] - == - ?: ?=(%klr -.bit) - %+ done %blit - :~ [%klr p.bit] - [%mor ~] - see - [%hop pos] - == - ?: ?=(%pro -.bit) - =. see [%lin p.bit] - (done %blit [see [%hop pos] ~]) - ?: ?=(%pom -.bit) - ::NOTE treat "styled prompt" without style as plain prompt, - :: to allow rendering by older runtimes - ::TODO remove me once v0.10.9+ has high/guaranteed adoption - :: - ?: (levy p.bit (cork head |*(s=stye =(*stye s)))) - $(bit [%pro (zing (turn p.bit tail))]) - =. see [%klr p.bit] - (done %blit [see [%hop pos] ~]) - ?: ?=(%hop -.bit) - (done(pos p.bit) %blit [bit ~]) ?: ?=(%qit -.bit) (dump %logo ~) (done %blit [bit ~]) @@ -241,18 +219,33 @@ =. tem `(turn gyl |=(a=gill [%yow a])) (pass / [%c %warp our %home `[%sing %y [%ud 1] /]]) :: + ++ open + |= gyl=(list gill) + =. +> (pass / %g %conf ram) + =. +> peer + %+ roll gyl + |= [g=gill _..open] + (send [%yow g]) + :: + ++ shut + ::TODO send a %bye blit? + pull(eye.all (~(del by eye.all) ses)) + :: ++ send :: send action |= bet=dill-belt ^+ +> ?^ tem +>(tem `[bet u.tem]) - (deal / [%poke [%dill-belt -:!>(bet) bet]]) + (deal /send/[ses] [%poke [%dill-poke !>([ses bet])]]) :: ++ hood-set-boot-apps (deal / [%poke %drum-set-boot-apps !>(lit.all)]) :: ++ peer - (deal / [%watch /drum]) + (deal /peer/[ses] %watch /dill/[ses]) + :: + ++ pull + (deal /peer/[ses] %leave ~) :: ++ show :: permit reads on desk |= des=desk @@ -266,13 +259,6 @@ |= [tea=wire sih=sign] ^+ +> ?- sih - [%gall %onto *] - :: ~& [%take-gall-onto +>.sih] - ?- -.+>.sih - %| (crud %onto p.p.+>.sih) - %& (done %blit [%lin (tuba "{}")]~) - == - :: [%gall %unto *] :: ~& [%take-gall-unto +>.sih] ?- -.+>.sih @@ -288,9 +274,6 @@ +>.$ (from ;;(dill-blit q.q.cage.p.+>.sih)) == - :: - [%clay %note *] - (from %out (tuba p.sih ' ' ~(ram re q.sih))) :: [?(%behn %clay) %writ *] init @@ -305,12 +288,20 @@ == -- :: - ++ ax :: make ++as - |= hen=duct + ++ ax :: make ++as from name + |= [hen=duct ses=@tas] ^- (unit _as) - =/ nux (~(get by dug.all) hen) + =/ nux (~(get by dug.all) ses) ?~ nux ~ - (some ~(. as hen u.nux)) + (some ~(. as hen ses u.nux)) + :: + ++ aw :: make ++as from wire + |= [hen=duct wir=wire] + ^- (unit _as) + %+ ax hen + ?+ wir %$ + [?(%peer %send) @ *] i.t.wir + == -- |% :: poke+peek pattern ++ call :: handle request @@ -321,7 +312,10 @@ ^+ [*(list move) ..^$] ~| wrapped-task =/ task=task ((harden task) wrapped-task) + :: unwrap session tasks, default to session %$ :: + =^ ses=@tas task + ?:(?=(%shot -.task) +.task [%$ task]) :: error notifications "downcast" to %crud :: =? task ?=(^ dud) @@ -351,10 +345,11 @@ :: =* duc (need hey.all) =/ app %hood - =/ see (tuba "") - =/ zon=axon [app input=[~ ~] width=80 cursor=(lent see) lin+see] + =/ say (tuba "") + =/ zon=axon [app input=[~ ~] width=80] :: - =^ moz all abet:(~(into as duc zon) ~) + =^ moz all abet:(~(into as duc %$ zon) ~) + =. eye.all (~(put ju eye.all) %$ duc) [moz ..^$] :: %flog tasks are unwrapped and sent back to us on our default duct :: @@ -375,35 +370,55 @@ ?: ?=(%knob -.task) =. veb.all (~(put by veb.all) tag.task level.task) [~ ..^$] + :: %open opens a new dill session + :: + ?: ?=(%open -.task) + ?: (~(has by dug.all) ses) + ::TODO should we allow, and just send the %yow blits? + ~| [%cannot-open-existing ses] + !! + =/ zon=axon [p.task ~ width=80] + =^ moz all abet:(~(open as hen ses zon) q.task) + =. eye.all (~(put ju eye.all) ses hen) + [moz ..^$] + :: %shut closes an existing dill session + :: + ?: ?=(%shut -.task) + ?: =(%$ ses) + ~| %cannot-shut-default-session + !! + =/ nus + ~| [%no-session ses] + (need (ax hen ses)) + =^ moz all abet:shut:nus + [moz ..^$] + :: %view opens a subscription to the target session, on the current duct :: ?: ?=(%view -.task) - :: crash on viewing non-existent session + =/ nus + :: crash on viewing non-existent session + :: + ~| [%no-session ses] + (need (ax hen ses)) + :: register the viewer and send a %hey so they get the full screen :: - ~| [%no-session session.task] - ?> =(~ session.task) - =/ session (need hey.all) - =/ =axon (~(got by dug.all) session) - :: register the viewer and send them the prompt line - :: - :- [hen %give %blit [see.axon]~]~ - ..^$(eye.all (~(put ju eye.all) session hen)) + =^ moz all + abet:(send:nus %hey ~) + :- moz + ..^$(eye.all (~(put ju eye.all) ses hen)) + :: %flee closes a subscription to the target session, from the current duct :: ?: ?=(%flee -.task) :- ~ - ~| [%no-session session.task] - ?> =(~ session.task) - =/ session (need hey.all) - ..^$(eye.all (~(del ju eye.all) session hen)) + ..^$(eye.all (~(del ju eye.all) ses hen)) :: - =/ nus (ax hen) - =? nus &(?=(~ nus) ?=(^ hey.all)) - ::TODO allow specifying target session in task - (ax u.hey.all) + =/ nus + (ax hen ses) ?~ nus - :: :hen is an unrecognized duct + :: session :ses does not exist :: could be before %boot (or %boot failed) :: - ~& [%dill-call-no-flow hen -.task] + ~& [%dill-call-no-session ses hen -.task] =/ tan ?:(?=(%crud -.task) q.task ~) [((slog (flop tan)) ~) ..^$] :: @@ -411,8 +426,63 @@ [moz ..^$] :: ++ load :: import old state - |= old=axle - ..^$(all old) + =< |= old=any-axle + ?- -.old + %5 ..^$(all old) + %4 $(old (axle-4-to-5 old)) + == + |% + +$ any-axle $%(axle axle-4) + :: + +$ axle-4 + $: %4 + hey=(unit duct) + dug=(map duct axon-4) + eye=(jug duct duct) + lit=? + veb=(map @tas log-level) + == + :: + +$ axon-4 + $: ram=term + tem=(unit (list dill-belt-4)) + wid=_80 + pos=$@(@ud [@ud @ud]) + see=$%([%lin (list @c)] [%klr stub]) + == + :: + +$ dill-belt-4 + $% [%ctl p=@c] + [%met p=@c] + dill-belt + == + :: + ++ axle-4-to-5 + |= axle-4 + ^- axle + :- %5 + =- [hey nug nay lit veb] + %+ roll ~(tap by dug) + |= [[=duct =axon-4] nug=(map @tas axon) nay=(jug @tas duct)] + =/ ses=@tas + ~| [%unexpected-duct duct] + ?>(=([//term/1]~ duct) %$) + :- (~(put by nug) ses (axon-4-to-5 axon-4)) + %+ ~(put by nay) ses + (~(put in (~(get ju eye) duct)) duct) + :: + ++ axon-4-to-5 + |= axon-4 + ^- axon + =; tem [ram tem wid] + ?~ tem ~ + %- some + %+ turn u.tem + |= b=dill-belt-4 + ^- dill-belt + ?. ?=(?(%ctl %met) -.b) b + [%mod -.b p.b] + -- :: ++ scry ^- roon @@ -441,19 +511,12 @@ =(%$ syd) == ~ - :: /dx/sessions//line blit current line (prompt) of default session - :: /dx/sessions//cursor @ud current cursor position of default session - ::TODO support asking for specific sessions once session ids are real + :: /dy/sessions (set @tas) all existing sessions + :: /du/sessions/[ses] ? does session ses exist? :: - ?. ?=(%x ren) ~ - ?+ tyl ~ - [%sessions %$ *] - ?~ hey.all [~ ~] - ?~ session=(~(get by dug.all) u.hey.all) [~ ~] - ?+ t.t.tyl ~ - [%line ~] ``blit+!>(`blit`see.u.session) - [%cursor ~] ``atom+!>(pos.u.session) - == + ?+ [ren tyl] ~ + [%y %sessions ~] ``noun+!>(~(key by dug.all)) + [%u %sessions @ ~] ``noun+!>((~(has by dug.all) (snag 1 tyl))) == :: ++ stay all @@ -464,12 +527,11 @@ ?^ dud ~|(%dill-take-dud (mean tang.u.dud)) :: - =/ nus (ax hen) + =/ nus (aw hen tea) ?~ nus - :: :hen is an unrecognized duct - :: could be before %boot (or %boot failed) + :: :tea points to an unrecognized session :: - ~& [%dill-take-no-flow hen -.hin +<.hin] + ~& [%dill-take-no-session tea -.hin +<.hin] [~ ..^$] =^ moz all abet:(take:u.nus tea hin) [moz ..^$] diff --git a/pkg/arvo/sys/vane/gall.hoon b/pkg/arvo/sys/vane/gall.hoon index a71b0dd8a..65fc1b266 100644 --- a/pkg/arvo/sys/vane/gall.hoon +++ b/pkg/arvo/sys/vane/gall.hoon @@ -266,12 +266,22 @@ :: +mo-abet: finalize, reversing moves :: +mo-pass: prepend a standard %pass to the current list of moves :: +mo-give: prepend a standard %give to the current list of moves + :: +mo-talk: build task to print config report or failure trace :: ++ mo-core . ++ mo-abed |=(hun=duct mo-core(hen hun)) ++ mo-abet [(flop moves) gall-payload] ++ mo-pass |=(p=[wire note-arvo] mo-core(moves [[hen pass+p] moves])) ++ mo-give |=(g=gift mo-core(moves [[hen give+g] moves])) + ++ mo-talk + |= rup=(each suss tang) + ^- [wire note-arvo] + :+ /sys/say %d + ^- task:dill + ?- -.rup + %& [%text "gall: {(t q)}ed %{(t p)}":[t=trip p.rup]] + %| [%talk leaf+"gall: failed" (flop p.rup)] + == :: +mo-boot: ask %ford to build us a core for the specified agent. :: ++ mo-boot @@ -349,12 +359,12 @@ =/ ap-core +.wag ?^ maybe-tang =. mo-core old - (mo-give %onto %.n u.maybe-tang) + (mo-pass (mo-talk %.n u.maybe-tang)) :: =. mo-core ap-abet:ap-core =. mo-core (mo-clear-queue dap) =/ =suss [dap %boot now] - (mo-give %onto [%.y suss]) + (mo-pass (mo-talk %.y suss)) :: +mo-subscribe-to-agent-builds: request agent update notices :: :: Also subscribe to our own source path, in case we get reloaded @@ -544,7 +554,7 @@ ++ fail |= =tang ^+ mo-core - =. mo-core (mo-give %onto |+tang) + =. mo-core (mo-pass (mo-talk |+tang)) =/ =case [%da tim] =/ =wire /sys/cor/[dap]/[her]/[desk]/(scot case) (mo-pass wire %c %warp p.beak desk ~ %next %a case /app/[dap]/hoon) @@ -1019,8 +1029,8 @@ :: =/ running (~(put by yokes.state) agent-name current-agent) =/ moves - =/ giver |=(report=(each suss tang) [hen %give %onto report]) - =/ from-suss (turn agent-config giver) + =/ talker |=(report=(each suss tang) [hen %pass (mo-talk report)]) + =/ from-suss (turn agent-config talker) :(weld agent-moves from-suss moves) :: %_ mo-core diff --git a/pkg/arvo/sys/vane/jael.hoon b/pkg/arvo/sys/vane/jael.hoon index ddc225d03..f97f4cc46 100644 --- a/pkg/arvo/sys/vane/jael.hoon +++ b/pkg/arvo/sys/vane/jael.hoon @@ -107,11 +107,8 @@ $>(%wake gift:behn) :: == :: $: %gall :: - $> $? %onto :: - %unto :: - == :: - gift:gall :: - == + $>(%unto gift:gall) :: + == :: == :: -- :: :: :::: @@ -557,10 +554,6 @@ =/ ships (~(get ju ship-sources-reverse.etn) source-id) %- curd =< abet (sources:~(feel su hen now pki etn) ships source) - :: - [%gall %onto *] - ~& [%jael-onto tea hin] - +>.$ :: [%gall %unto *] ?- +>-.hin diff --git a/pkg/arvo/sys/zuse.hoon b/pkg/arvo/sys/zuse.hoon index 8a0056bcc..ee263eee5 100644 --- a/pkg/arvo/sys/zuse.hoon +++ b/pkg/arvo/sys/zuse.hoon @@ -3729,6 +3729,107 @@ ~ (some (~(run by lum) need)) -- ::dejs-soft + :: + ++ klr :: styx/stub engine + =, dill + |% + ++ make :: stub from styx + |= a=styx ^- stub + =| b=stye + %+ reel + |- ^- stub + %- zing %+ turn a + |= a=$@(@t (pair styl styx)) + ?@ a [b (tuba (trip a))]~ + ^$(a q.a, b (styd p.a b)) + :: + |= [a=(pair stye (list @c)) b=stub] + ?~ b [a ~] + ?. =(p.a p.i.b) [a b] + [[p.a (weld q.a q.i.b)] t.b] + :: + ++ styd :: stye from styl + |= [a=styl b=stye] ^+ b :: with inheritance + :+ ?~ p.a p.b + ?~ u.p.a ~ + (~(put in p.b) u.p.a) + (fall p.q.a p.q.b) + (fall q.q.a q.q.b) + :: + ++ lent-char + |= a=stub ^- @ + (roll (lnts-char a) add) + :: + ++ lnts-char :: stub text lengths + |= a=stub ^- (list @) + %+ turn a + |= a=(pair stye (list @c)) + (lent q.a) + :: + ++ brek :: index + incl-len of + |= [a=@ b=(list @)] :: stub pair w/ idx a + =| [c=@ i=@] + |- ^- (unit (pair @ @)) + ?~ b ~ + =. c (add c i.b) + ?: (gte c a) + `[i c] + $(i +(i), b t.b) + :: + ++ pact :: condense stub + |= a=stub + ^- stub + ?~ a ~ + ?~ t.a a + ?. =(p.i.a p.i.t.a) [i.a $(a t.a)] + =. q.i.t.a (weld q.i.a q.i.t.a) + $(a t.a) + :: + ++ slag :: slag stub + |= [a=@ b=stub] + ^- stub + =+ c=(lnts-char b) + =+ i=(brek a c) + ?~ i ~ + =+ r=(^slag +(p.u.i) b) + ?: =(a q.u.i) + r + =+ n=(snag p.u.i b) + :_ r :- p.n + (^slag (sub (snag p.u.i c) (sub q.u.i a)) q.n) + :: + ++ scag :: scag stub + |= [a=@ b=stub] + ^- stub + =+ c=(lnts-char b) + =+ i=(brek a c) + ?~ i b + ?: =(a q.u.i) + (^scag +(p.u.i) b) + %+ welp + (^scag p.u.i b) + =+ n=(snag p.u.i b) + :_ ~ :- p.n + (^scag (sub (snag p.u.i c) (sub q.u.i a)) q.n) + :: + ++ swag :: swag stub + |= [[a=@ b=@] c=stub] + (scag b (slag a c)) + :: + ++ wail :: overlay stub + |= [a=stub b=@ c=stub d=@c] + ^- stub + ;: weld + (scag b a) + :: + =+ e=(lent-char a) + ?: (lte b e) ~ + [*stye (reap (sub b e) d)]~ + :: + c + (slag (add b (lent-char c)) a) + == + -- :: klr -- :: :: :::: ++differ :: (2d) hunt-mcilroy diff --git a/pkg/arvo/ted/aqua/dill.hoon b/pkg/arvo/ted/aqua/dill.hoon index 4d3b7b2e4..7ce9ff073 100644 --- a/pkg/arvo/ted/aqua/dill.hoon +++ b/pkg/arvo/ted/aqua/dill.hoon @@ -17,15 +17,16 @@ %+ roll blits |= [b=blit:dill line=tape] ?- -.b - %lin (tape p.b) + %put (tape p.b) %klr (tape (zing (turn p.b tail))) - %mor ~& "{}: {line}" "" + %nel ~& "{}: {line}" "" %hop line %bel line %clr "" %sag ~& [%save-jamfile-to p.b] line %sav ~& [%save-file-to p.b] line %url ~& [%activate-url p.b] line + %wyp "" == ~? !=(~ last-line) last-line ~ diff --git a/pkg/hs/urbit-king/lib/Urbit/Arvo/Effect.hs b/pkg/hs/urbit-king/lib/Urbit/Arvo/Effect.hs index 5a5782912..6037e0298 100644 --- a/pkg/hs/urbit-king/lib/Urbit/Arvo/Effect.hs +++ b/pkg/hs/urbit-king/lib/Urbit/Arvo/Effect.hs @@ -119,15 +119,25 @@ deriveNoun ''BehnEf data Blit = Bel () | Clr () - | Hop Word64 + | Hop HopTarget | Klr Stub - | Lin [Char] - | Mor () + | Put [Char] + | Nel () | Sag Path Noun | Sav Path Atom | Url Cord + | Wyp () + --TMP backwards compatibility + | Lin [Char] + | Mor () deriving (Eq, Ord) +--NOTE bottom-left-0-based coordinates +data HopTarget + = Col Word64 + | Roc Word64 Word64 -- row, col + deriving (Eq, Ord, Show) + data Deco = DecoBl | DecoBr @@ -205,18 +215,33 @@ instance FromNoun Tint where "w" -> pure TintW t -> fail ("invalid: " <> unpack t) +instance FromNoun HopTarget where + parseNoun = \case + A c -> pure $ Col (fromIntegral c) + C (A r) (A c) -> pure $ Roc (fromIntegral r) (fromIntegral c) + n -> fail ("invalid hop target: " <> show n) + +instance ToNoun HopTarget where + toNoun = \case + Col c -> A (fromIntegral c) + Roc r c -> C (A (fromIntegral r)) (A (fromIntegral c)) + -- Manual instance to not save the noun/atom in Sag/Sav, because these can be -- megabytes and makes king hang. instance Show Blit where show (Bel ()) = "Bel ()" show (Clr ()) = "Clr ()" - show (Hop x) = "Hop " ++ (show x) + show (Hop t) = "Hop " ++ (show t) show (Klr s) = "Klr " ++ (show s) - show (Lin c) = "Lin " ++ (show c) - show (Mor ()) = "Mor ()" + show (Put c) = "Put " ++ (show c) + show (Nel ()) = "Nel ()" show (Sag path _) = "Sag " ++ (show path) show (Sav path _) = "Sav " ++ (show path) show (Url c) = "Url " ++ (show c) + show (Wyp ()) = "Wyp ()" + -- + show (Lin c) = "Lin " ++ (show c) + show (Mor ()) = "Mor ()" {-| %blip -- TODO diff --git a/pkg/hs/urbit-king/lib/Urbit/Arvo/Event.hs b/pkg/hs/urbit-king/lib/Urbit/Arvo/Event.hs index d2f316a53..50ef1ac1f 100644 --- a/pkg/hs/urbit-king/lib/Urbit/Arvo/Event.hs +++ b/pkg/hs/urbit-king/lib/Urbit/Arvo/Event.hs @@ -20,6 +20,7 @@ import Urbit.Arvo.Common (ReOrg(..), reorgThroughNoun) import qualified Crypto.Sign.Ed25519 as Ed import qualified Data.ByteString as BS +import qualified Data.Char as C import qualified Data.ByteString.Char8 as C import qualified Network.HTTP.Types.Method as H @@ -318,19 +319,52 @@ data LegacyBootEvent | Dawn Dawn deriving (Eq, Show) -data ArrowKey = D | L | R | U +data Bolt + = Key Char + | Aro ArrowKey + | Bac () + | Del () + | Hit Word64 Word64 + | Ret () deriving (Eq, Ord, Show) data Belt - = Aro ArrowKey - | Bac () - | Ctl Cord - | Del () - | Met Cord - | Ret () + = Bol Bolt + | Mod Modifier Bolt | Txt Tour deriving (Eq, Ord, Show) +data ArrowKey = D | L | R | U + deriving (Eq, Ord, Show) + +data Modifier = Ctl | Met | Hyp + deriving (Eq, Ord, Show) + +--NOTE required to get the above declarations into reify's type environment +-- see also ghc/ghc#9813 +$(pure []) + +instance FromNoun Bolt where + parseNoun = \case + A c -> pure $ Key $ C.chr $ fromIntegral c + C (A 7955819) _ -> fail "%key not valid bolt tag" + n -> $(deriveFromNounFunc ''Bolt) n + +instance FromNoun Belt where + parseNoun = \case + C (A 7106402) _ -> fail "%bol not valid belt tag" + n -> Bol <$> parseNoun n <|> $(deriveFromNounFunc ''Belt) n + +instance ToNoun Bolt where + toNoun = \case + Key c -> A $ fromIntegral $ C.ord c + n -> $(deriveToNounFunc ''Bolt) n + +instance ToNoun Belt where + toNoun = \case + Bol b -> toNoun b + n -> $(deriveToNounFunc ''Belt) n + data TermEv = TermEvBelt (UD, ()) Belt | TermEvBlew (UD, ()) Word Word @@ -341,7 +375,7 @@ data TermEv deriveNoun ''LegacyBootEvent deriveNoun ''ArrowKey -deriveNoun ''Belt +deriveNoun ''Modifier deriveNoun ''TermEv @@ -392,27 +426,23 @@ instance FromNoun Ev where -- Short Event Names ----------------------------------------------------------- {- - In the case of the user hitting enter, the cause is technically a - terminal event, but we don't display any name because the cause is - really the user. + In the case of user input, the cause is technically a terminal event, + but we don't display any name because the cause is really the user. -} getSpinnerNameForEvent :: Ev -> Maybe Text getSpinnerNameForEvent = \case EvBlip b -> case b of - BlipEvAmes _ -> Just "ames" - BlipEvArvo _ -> Just "arvo" - BlipEvBehn _ -> Just "behn" - BlipEvBoat _ -> Just "boat" - BlipEvHttpClient _ -> Just "iris" - BlipEvHttpServer _ -> Just "eyre" - BlipEvJael _ -> Just "jael" - BlipEvNewt _ -> Just "newt" - BlipEvSync _ -> Just "clay" - BlipEvTerm t | isRet t -> Nothing - BlipEvTerm t -> Just "term" - where - isRet (TermEvBelt _ (Ret ())) = True - isRet _ = False + BlipEvAmes _ -> Just "ames" + BlipEvArvo _ -> Just "arvo" + BlipEvBehn _ -> Just "behn" + BlipEvBoat _ -> Just "boat" + BlipEvHttpClient _ -> Just "iris" + BlipEvHttpServer _ -> Just "eyre" + BlipEvJael _ -> Just "jael" + BlipEvNewt _ -> Just "newt" + BlipEvSync _ -> Just "clay" + BlipEvTerm (TermEvBelt _ _) -> Nothing + BlipEvTerm t -> Just "term" summarizeEvent :: Ev -> Text summarizeEvent ev = diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Pier.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Pier.hs index 24e7bb7ff..a3b0f72a2 100644 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Pier.hs +++ b/pkg/hs/urbit-king/lib/Urbit/Vere/Pier.hs @@ -333,7 +333,7 @@ pier (serf, log) vSlog startedSig injected = do io $ readTVarIO siteSlog >>= ($ s) logOther "serf" (display $ T.strip $ tankToText tank) - let err = atomically . Term.trace muxed . (<> "\r\n") + let err = atomically . Term.trace muxed (bootEvents, startDrivers) <- do env <- ask siz <- atomically $ Term.curDemuxSize demux diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Term.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Term.hs index dc49043fe..ccd4c676d 100644 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Term.hs +++ b/pkg/hs/urbit-king/lib/Urbit/Vere/Term.hs @@ -45,8 +45,8 @@ import qualified Urbit.Vere.Term.Render as T -- | All stateful data in the printing to stdOutput. data LineState = LineState - { lsLine :: Text - , lsCurPos :: Int + { lsLine :: [(Stye, [Char])] + , lsCurPos :: CurPos , lsSpinTimer :: Maybe (Async ()) , lsSpinCause :: Maybe Text , lsSpinFirstRender :: Bool @@ -54,11 +54,19 @@ data LineState = LineState , lsPrevEndTime :: Wen } +data CurPos = CurPos + { row :: Int + , col :: Int + } + -- | A record used in reading data from stdInput. data ReadData = ReadData { rdBuf :: Ptr Word8 , rdEscape :: Bool , rdBracket :: Bool + , rdMouse :: Bool + , rdMouseBut :: Word8 + , rdMouseCol :: Word8 , rdUTF8 :: ByteString , rdUTF8width :: Int } @@ -165,7 +173,8 @@ leftBracket, rightBracket :: Text leftBracket = "«" rightBracket = "»" -_spin_cool_us, _spin_warm_us, _spin_rate_us, _spin_idle_us :: Integral i => i +_spin_fast_us, _spin_cool_us, _spin_warm_us, _spin_rate_us, _spin_idle_us :: Integral i => i +_spin_fast_us = 100000 _spin_cool_us = 500000 _spin_warm_us = 50000 _spin_rate_us = 250000 @@ -201,6 +210,9 @@ localClient doneSignal = fst <$> mkRAcquire start stop -- to the muxing client. putTMVar tsSizeChange ts) + -- start mouse reporting + putStr "\x1b[?9h" + pWriterThread <- asyncBound (writeTerminal tsWriteQueue spinnerMVar tsizeTVar) @@ -217,7 +229,7 @@ localClient doneSignal = fst <$> mkRAcquire start stop tsReadQueue <- newTQueueIO pReaderThread <- asyncBound - (readTerminal tsReadQueue tsWriteQueue (bell tsWriteQueue)) + (readTerminal tsReadQueue tsWriteQueue tsizeTVar (bell tsWriteQueue)) let client = Client { take = Just <$> asum [ readTQueue tsReadQueue <&> ClientTakeBelt, @@ -238,6 +250,9 @@ localClient doneSignal = fst <$> mkRAcquire start stop -- at shutdown, just leak the file descriptor. cancel pWriterThread + -- stop mouse reporting + putStr "\x1b[?9l" + -- inject one final newline, as we're usually on the prompt. putStr "\r\n" @@ -266,31 +281,50 @@ localClient doneSignal = fst <$> mkRAcquire start stop -- Writes data to the terminal. Both the terminal reading, normal logging, -- and effect handling can all emit bytes which go to the terminal. + --TODO blanks, traces and slogs should only be written into the default + -- terminal session. writeTerminal :: TQueue [Term.Ev] -> TMVar () -> TVar TermSize -> RIO e () writeTerminal q spinner termSizeVar = do currentTime <- io $ now - loop (LineState "" 0 Nothing Nothing True 0 currentTime) + loop + termSizeVar + (LineState [] (CurPos 0 0) Nothing Nothing True 0 currentTime) where writeBlank :: LineState -> RIO e LineState - writeBlank ls = putStr "\r\n" $> ls + writeBlank ls = do + TermSize _ height <- readTVarIO termSizeVar + --NOTE hijack creates a blank line + T.hijack (fromIntegral height) $ pure () + pure ls writeTrace :: LineState -> Text -> RIO e LineState writeTrace ls p = do - putStr "\r" - T.clearLine - putStr p - termRefreshLine ls + TermSize _ height <- readTVarIO termSizeVar + T.hijack (fromIntegral height) $ putStr p + pure ls writeSlog :: LineState -> (Atom, Tank) -> RIO e LineState writeSlog ls slog = do - putStr "\r" - T.clearLine - TermSize width _ <- atomically $ readTVar termSizeVar - -- TODO: Ignoring priority for now. Priority changes the color of, - -- and adds a prefix of '>' to, the output. - let lines = fmap unTape $ wash (WashCfg 0 width) $ tankTree $ snd slog - forM lines $ \line -> putStr (line <> "\r\n") - termRefreshLine ls + TermSize width height <- readTVarIO termSizeVar + T.hijack (fromIntegral height) do + let lines = fmap (pref . unTape) $ + wash (WashCfg 0 width) $ tankTree $ snd slog + T.putCsi 'm' styl + forM (intersperse "\n" lines) $ \line -> putStr line + T.putCsi 'm' [0] + pure ls + where + prio = fromIntegral $ fst slog + maxp = 3 + styl + | prio == 3 = [31] + | prio == 2 = [33] + | prio == 1 = [32] + | otherwise = [90] + pref + | prio > 0 && prio <= maxp = + ((replicate prio '>' ++ replicate (1 + maxp - prio) ' ') ++) + | otherwise = id {- Figure out how long to wait to show the spinner. When we @@ -305,7 +339,7 @@ localClient doneSignal = fst <$> mkRAcquire start stop current <- io $ now delay <- pure $ case mTxt of - Nothing -> 0 + Nothing -> _spin_fast_us Just _ -> if (gap current lsPrevEndTime ^. microSecs) < _spin_idle_us then _spin_warm_us @@ -326,34 +360,41 @@ localClient doneSignal = fst <$> mkRAcquire start stop maybe (pure ()) cancel lsSpinTimer -- We do a final flush of the spinner mvar to ensure we don't -- have a lingering signal which will redisplay the spinner after - -- we call termRefreshLine below. + -- we call termRestoreLine below. atomically $ tryTakeTMVar spinner -- If we ever actually ran the spinner display callback, we need -- to force a redisplay of the command prompt. - ls <- if not lsSpinFirstRender || True - then termRefreshLine ls - else pure ls + if not lsSpinFirstRender + then termRestoreLine ls termSizeVar + else pure () endTime <- io $ now pure $ ls { lsSpinTimer = Nothing, lsPrevEndTime = endTime } execEv :: LineState -> Term.Ev -> RIO e LineState execEv ls = \case - Term.Blits bs -> foldM writeBlit ls bs + Term.Blits bs -> foldM (writeBlit termSizeVar) ls bs Term.Trace p -> writeTrace ls (unCord p) Term.Slog s -> writeSlog ls s Term.Blank -> writeBlank ls Term.Spinr (Just txt) -> doSpin ls (unCord <$> txt) Term.Spinr Nothing -> unspin ls - -- TODO What does this do? - spin :: LineState -> RIO e LineState - spin ls@LineState{..} = do + spin :: TVar TermSize -> LineState -> RIO e LineState + spin ts ls@LineState{..} = do let spinner = (spinners !! lsSpinFrame) ++ case lsSpinCause of Nothing -> "" Just str -> leftBracket ++ str ++ rightBracket + --NOTE even after first render, because cursor might have moved... + if row lsCurPos > 0 + then do + TermSize _ h <- readTVarIO ts + T.cursorMove (fromIntegral h - 1) 0 + else + T.cursorRestore + putStr (spinner <> pack (ANSI.cursorBackwardCode (length spinner))) let newFrame = (lsSpinFrame + 1) `mod` length spinners @@ -362,28 +403,35 @@ localClient doneSignal = fst <$> mkRAcquire start stop , lsSpinFrame = newFrame } - loop :: LineState -> RIO e () - loop ls = do + loop :: TVar TermSize -> LineState -> RIO e () + loop ts ls = do join $ atomically $ asum - [ readTQueue q >>= pure . (foldM execEv ls >=> loop) - , takeTMVar spinner >> pure (spin ls >>= loop) + [ readTQueue q >>= pure . (foldM execEv ls >=> loop ts) + , takeTMVar spinner >> pure (spin ts ls >>= loop ts) ] -- Writes an individual blit to the screen - writeBlit :: LineState -> Blit -> RIO e LineState - writeBlit ls = \case + writeBlit :: TVar TermSize -> LineState -> Blit -> RIO e LineState + writeBlit ts ls = \case Bel () -> T.soundBell $> ls Clr () -> do T.clearScreen - termRefreshLine ls - Hop w -> termShowCursor ls (fromIntegral w) - Klr s -> do ls2 <- termShowClear ls - termShowStub ls2 s - Lin c -> do ls2 <- termShowClear ls - termShowLine ls2 (pack c) - Mor () -> termShowMore ls + T.cursorRestore + pure ls + Hop t -> case t of + Col c -> termShowCursor ls ts 0 (fromIntegral c) + Roc r c -> termShowCursor ls ts (fromIntegral r) (fromIntegral c) + Klr s -> termShowStub ls s + Put c -> termShowLine ls (pack c) + Nel () -> termShowNewline ls Sag path noun -> pure ls Sav path atom -> pure ls Url url -> pure ls + Wyp () -> termShowClear ls + -- + Lin c -> do termShowCursor ls ts 0 0 + termShowClear ls + termShowLine ls (pack c) + Mor () -> termShowNewline ls termRenderDeco :: Deco -> Char termRenderDeco = \case @@ -428,55 +476,88 @@ localClient doneSignal = fst <$> mkRAcquire start stop styled = mconcat [escape, styles, "m", tape, escape, "0m"] - -- Displays and sets styled text as the current line + bareStub :: [Char] -> [(Stye, [Char])] + bareStub c = [(Stye (setToHoonSet mempty) TintNull TintNull, c)] + + -- overwrite substring of base with put, starting at index + overwriteStub :: [(Stye, [Char])] -> Int -> [(Stye, [Char])] -> [(Stye, [Char])] + overwriteStub base index put = + scagStub index base + ++ ( let l = lentStub base in + if index <= l then [] + else bareStub $ take (index - l) [' ',' '..] + ) + ++ put + ++ slagStub (index + lentStub put) base + where + lentStub :: [(Stye, [Char])] -> Int + lentStub s = sum $ map (length . snd) s + + scagStub :: Int -> [(Stye, [Char])] -> [(Stye, [Char])] + scagStub 0 _ = [] + scagStub _ [] = [] + scagStub i ((y,c):s) = + (y, take i c) : scagStub (i - min i (length c)) s + + slagStub :: Int -> [(Stye, [Char])] -> [(Stye, [Char])] + slagStub 0 s = s + slagStub _ [] = [] + slagStub i ((y,c):s) + | i > l = slagStub (i - l) s + | otherwise = (y, drop i c) : s + where l = length c + + -- Displays styled text at the cursor termShowStub :: LineState -> Stub -> RIO e LineState - termShowStub ls (Stub s) = do - let visualLength = sum $ fmap (length . snd) s - let outText = pack $ mconcat $ fmap (uncurry termRenderStubSegment) s - putStr outText - pure ls { lsLine = outText, lsCurPos = visualLength } + termShowStub ls@LineState{lsCurPos, lsLine} (Stub s) = do + putStr $ pack $ mconcat $ fmap (uncurry termRenderStubSegment) s + T.cursorRestore + case row lsCurPos of + 0 -> pure ls { lsLine = overwriteStub lsLine (col lsCurPos) s } + _ -> pure ls -- Moves the cursor to the requested position - termShowCursor :: LineState -> Int -> RIO e LineState - termShowCursor ls@LineState{..} {-line pos)-} newPos = do - if newPos < lsCurPos then do - T.cursorLeft (lsCurPos - newPos) - pure ls { lsCurPos = newPos } - else if newPos > lsCurPos then do - T.cursorRight (newPos - lsCurPos) - pure ls { lsCurPos = newPos } - else - pure ls - - -- Moves the cursor left without any mutation of the LineState. Used only - -- in cursor spinning. - _termSpinnerMoveLeft :: Int -> RIO e () - _termSpinnerMoveLeft = T.cursorLeft + termShowCursor :: LineState -> TVar TermSize -> Int -> Int -> RIO e LineState + termShowCursor ls ts row col = do + TermSize _ h <- readTVarIO ts + T.cursorMove (max 0 (fromIntegral h - row - 1)) col + T.cursorSave + pure ls { lsCurPos = CurPos row col } -- Displays and sets the current line termShowLine :: LineState -> Text -> RIO e LineState - termShowLine ls newStr = do + termShowLine ls@LineState{lsCurPos, lsLine} newStr = do putStr newStr - pure ls { lsLine = newStr, lsCurPos = (length newStr) } + T.cursorRestore + case row lsCurPos of + 0 -> pure ls { lsLine = overwriteStub lsLine (col lsCurPos) (bareStub $ unpack newStr) } + _ -> pure ls termShowClear :: LineState -> RIO e LineState - termShowClear ls = do + termShowClear ls@LineState{lsCurPos} = do putStr "\r" T.clearLine - pure ls { lsLine = "", lsCurPos = 0 } + T.cursorRestore + case row lsCurPos of + 0 -> pure ls { lsLine = [] } + _ -> pure ls -- New Current Line - termShowMore :: LineState -> RIO e LineState - termShowMore ls = do + termShowNewline :: LineState -> RIO e LineState + termShowNewline ls@LineState{lsCurPos} = do putStr "\r\n" - pure ls { lsLine = "", lsCurPos = 0 } + case row lsCurPos of + 0 -> pure ls { lsLine = [], lsCurPos = lsCurPos { col = 0 } } + r -> pure ls { lsCurPos = CurPos (r-1) 0 } - -- Redraw the current LineState, maintaining the current curpos - termRefreshLine :: LineState -> RIO e LineState - termRefreshLine ls@LineState{lsCurPos,lsLine} = do - ls <- termShowClear ls - ls <- termShowLine ls lsLine - termShowCursor ls lsCurPos + -- Redraw the bottom LineState, maintaining the current curpos + termRestoreLine :: LineState -> TVar TermSize -> RIO e () + termRestoreLine ls@LineState{lsLine} ts = do + TermSize _ h <- readTVarIO ts + T.cursorMove (fromIntegral h - 1) 0 + T.clearLine + putStr $ pack $ mconcat $ fmap (uncurry termRenderStubSegment) lsLine + T.cursorRestore -- ring my bell bell :: TQueue [Term.Ev] -> RIO e () @@ -491,9 +572,14 @@ localClient doneSignal = fst <$> mkRAcquire start stop -- A better way to do this would be to get some sort of epoll on stdInput, -- since that's kinda closer to what libuv does? readTerminal :: forall e. HasLogFunc e - => TQueue Belt -> TQueue [Term.Ev] -> (RIO e ()) -> RIO e () - readTerminal rq wq bell = - rioAllocaBytes 1 $ \ buf -> loop (ReadData buf False False mempty 0) + => TQueue Belt + -> TQueue [Term.Ev] + -> TVar TermSize + -> RIO e () + -> RIO e () + readTerminal rq wq ts bell = + rioAllocaBytes 1 $ \ buf + -> loop (ReadData buf False False False 0 0 mempty 0) where loop :: ReadData -> RIO e () loop rd@ReadData{..} = do @@ -513,26 +599,41 @@ localClient doneSignal = fst <$> mkRAcquire start stop if rdEscape then if rdBracket then do case c of - 'A' -> sendBelt $ Aro U - 'B' -> sendBelt $ Aro D - 'C' -> sendBelt $ Aro R - 'D' -> sendBelt $ Aro L + 'A' -> sendBelt $ Bol $ Aro U + 'B' -> sendBelt $ Bol $ Aro D + 'C' -> sendBelt $ Bol $ Aro R + 'D' -> sendBelt $ Bol $ Aro L + 'M' -> pure () _ -> bell - loop rd { rdEscape = False, rdBracket = False} + rd <- case c of + 'M' -> pure rd { rdMouse = True } + _ -> pure rd + loop rd { rdEscape = False, rdBracket = False } else if isAsciiLower c then do - sendBelt $ Met $ Cord $ pack [c] - loop rd { rdEscape = False } - else if c == '.' then do - sendBelt $ Met $ Cord "dot" + sendBelt $ Mod Met $ Key c loop rd { rdEscape = False } else if w == 8 || w == 127 then do - sendBelt $ Met $ Cord "bac" + sendBelt $ Mod Met $ Bac () loop rd { rdEscape = False } else if c == '[' || c == '0' then do loop rd { rdBracket = True } else do bell loop rd { rdEscape = False } + else if rdMouse then + if rdMouseBut == 0 then do + loop rd { rdMouseBut = w - 31 } + else if rdMouseCol == 0 then do + loop rd { rdMouseCol = w - 32 } + else do + if rdMouseBut == 1 then do + let rdMouseRow = w - 32 + TermSize _ h <- readTVarIO ts + sendBelt $ Bol $ Hit + (fromIntegral h - fromIntegral rdMouseRow) + (fromIntegral rdMouseCol - 1) + else do pure () + loop rd { rdMouse = False, rdMouseBut = 0, rdMouseCol = 0 } else if rdUTF8width /= 0 then do -- continue reading into the utf8 accumulation buffer rd@ReadData{..} <- pure rd { rdUTF8 = snoc rdUTF8 w } @@ -543,31 +644,31 @@ localClient doneSignal = fst <$> mkRAcquire start stop error "empty utf8 accumulation buffer" Just (c, bytes) | bytes /= rdUTF8width -> error "utf8 character size mismatch?!" - Just (c, bytes) -> sendBelt $ Txt $ Tour $ [c] + Just (c, bytes) -> sendBelt $ Bol $ Key c loop rd { rdUTF8 = mempty, rdUTF8width = 0 } else if w >= 32 && w < 127 then do - sendBelt $ Txt $ Tour $ [c] + sendBelt $ Bol $ Key c loop rd else if w == 0 then do bell loop rd else if w == 8 || w == 127 then do - sendBelt $ Bac () + sendBelt $ Bol $ Bac () loop rd else if w == 13 then do - sendBelt $ Ret () + sendBelt $ Bol $ Ret () loop rd else if w == 3 then do -- ETX (^C) logInfo $ "Ctrl-c interrupt" atomically $ do - writeTQueue wq [Term.Trace "interrupt\r\n"] - writeTQueue rq $ Ctl $ Cord "c" + writeTQueue wq [Term.Trace "interrupt"] + writeTQueue rq $ Mod Ctl $ Key 'c' loop rd else if w <= 26 then do - case pack [BS.w2c (w + 97 - 1)] of - "d" -> atomically doneSignal - c -> do sendBelt $ Ctl $ Cord c + case BS.w2c (w + 97 - 1) of + 'd' -> atomically doneSignal + c -> do sendBelt $ Mod Ctl $ Key c loop rd else if w == 27 then do loop rd { rdEscape = True } @@ -644,7 +745,7 @@ term env (tsize, Client{..}) plan stat serfSIGINT = runTerm atomically take >>= \case Nothing -> pure () Just (ClientTakeBelt b) -> do - when (b == Ctl (Cord "c")) $ do + when (b == Mod Ctl (Key 'c')) $ do io serfSIGINT let beltEv = EvBlip $ BlipEvTerm $ TermEvBelt (UD 1, ()) $ b let beltFailed _ = pure () diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Term/API.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Term/API.hs index 7e65d49e5..d6b6fde60 100644 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Term/API.hs +++ b/pkg/hs/urbit-king/lib/Urbit/Vere/Term/API.hs @@ -22,7 +22,7 @@ import Urbit.TermSize Input Event for terminal driver: %blits -- list of blits from arvo. - %trace -- stderr line from runtime. + %trace -- stderr line from runtime (without trailing newline). %slog -- nock worker logging with priority %blank -- print a blank line %spinr -- Start or stop the spinner diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Logic.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Logic.hs index 770742a68..748b3fa5a 100644 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Logic.hs +++ b/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Logic.hs @@ -39,11 +39,11 @@ data Ev = EvLine Text | EvSlog (Atom, Tank) | EvSpin SpinnerState - | EvMove Word + | EvMove (Word, Word) | EvBell | EvDraw | EvEdit Text - | EvMore + | EvNewl deriving (Show) data Ef @@ -62,7 +62,7 @@ data History data St = St { sHistory :: !(Seq History) , sLine :: !Text - , sCurPos :: !Word + , sCurPos :: !(Word, Word) , sSpinner :: !SpinnerState } deriving (Show) @@ -70,10 +70,10 @@ data St = St -------------------------------------------------------------------------------- init :: St -init = St mempty "" 0 Nothing +init = St mempty "" (0, 0) Nothing {-| - When we process `EvMore`, we need to append a newline to the end of + When we process `EvNewl`, we need to append a newline to the end of the current line. During normal play, the ENTER key inserts the newline for us, so we need to recreate that newline when we rebuild the state for a new terminal connection. @@ -83,15 +83,17 @@ step st@St{..} = \case EvLine t -> st & recordText t EvSlog s -> st & recordSlog s EvSpin s -> st { sSpinner = s } - EvMove w -> st { sCurPos = min w (word $ length sLine) } - EvEdit t -> st { sLine = t, sCurPos = word (length t) } - EvMore -> st { sLine = "", sCurPos = 0 } & recordText (sLine <> "\n") + EvMove p -> st { sCurPos = p } EvBell -> st EvDraw -> st + EvEdit t | (0, _) <- sCurPos -> st { sLine = t } + | otherwise -> st + EvNewl | (0, _) <- sCurPos -> + st { sLine = "", sCurPos = (0, 0) } + & recordText (sLine <> "\n") + | otherwise -> + st { sCurPos = (fst sCurPos - 1, 0) } where - word :: Integral i => i -> Word - word = fromIntegral - recordText :: Text -> St -> St recordText !t st@St{..} = st { sHistory = trim (sHistory |> (HistoryText t)) @@ -111,8 +113,10 @@ drawState :: St -> [Ev] drawState St{..} = hist <> out <> cur <> spin where hist = drawHistory <$> toList sHistory - out = if null sLine then [] else [EvEdit sLine] - cur = if 0 == sCurPos then [] else [EvMove $ fromIntegral $ sCurPos] + out | null sLine = [] + | otherwise = [EvEdit sLine] + cur | (0, _) <- sCurPos = [] + | otherwise = [EvMove sCurPos] spin = maybe [] (singleton . EvSpin . Just) sSpinner drawHistory (HistoryText t) = EvLine t @@ -123,12 +127,13 @@ drawState St{..} = hist <> out <> cur <> spin fromBlit :: Arvo.Blit -> Maybe Ev fromBlit = \case - Arvo.Hop w -> Just $ EvMove $ fromIntegral w - Arvo.Bel () -> Just EvBell - Arvo.Clr () -> Just EvDraw - Arvo.Lin s -> Just $ EvEdit (pack s) - Arvo.Mor () -> Just EvMore - _ -> Nothing + Arvo.Hop (Arvo.Col c) -> Just $ EvMove (0, fromIntegral c) + Arvo.Hop (Arvo.Roc r c) -> Just $ EvMove (fromIntegral r, fromIntegral c) + Arvo.Bel () -> Just EvBell + Arvo.Clr () -> Just EvDraw + Arvo.Put s -> Just $ EvEdit (pack s) + Arvo.Nel () -> Just EvNewl + _ -> Nothing toCause :: Maybe Cord -> SpinnerCause toCause Nothing = User @@ -148,12 +153,12 @@ fromTermEv = \case toTermEv :: Ev -> Term.Ev toTermEv = \case - EvLine "" -> Term.Blank - EvLine t -> Term.Trace (Cord t) - EvSlog s -> Term.Slog s - EvSpin s -> Term.Spinr (fromCause <$> s) - EvMove w -> Term.Blits [Arvo.Hop $ fromIntegral w] - EvBell -> Term.Blits [Arvo.Bel ()] - EvDraw -> Term.Blits [Arvo.Clr ()] - EvEdit t -> Term.Blits [Arvo.Lin $ unpack t] - EvMore -> Term.Blits [Arvo.Mor ()] + EvLine "" -> Term.Blank + EvLine t -> Term.Trace (Cord t) + EvSlog s -> Term.Slog s + EvSpin s -> Term.Spinr (fromCause <$> s) + EvMove (r, c) -> Term.Blits [Arvo.Hop $ Arvo.Roc (fromIntegral r) (fromIntegral c)] + EvBell -> Term.Blits [Arvo.Bel ()] + EvDraw -> Term.Blits [Arvo.Clr ()] + EvEdit t -> Term.Blits [Arvo.Put $ unpack t] + EvNewl -> Term.Blits [Arvo.Nel ()] diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Render.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Render.hs index 3765f9cb2..c3b778f43 100644 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Render.hs +++ b/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Render.hs @@ -4,9 +4,12 @@ module Urbit.Vere.Term.Render ( clearScreen , clearLine - , cursorRight - , cursorLeft , soundBell + , cursorMove + , cursorSave + , cursorRestore + , putCsi + , hijack ) where import ClassyPrelude @@ -25,8 +28,27 @@ clearLine = liftIO $ ANSI.clearLine soundBell :: MonadIO m => m () soundBell = liftIO $ putStr "\a" -cursorLeft :: MonadIO m => Int -> m () -cursorLeft = liftIO . ANSI.cursorBackward +--NOTE top-left-0-based coordinates +cursorMove :: MonadIO m => Int -> Int -> m () +cursorMove r c = liftIO $ ANSI.setCursorPosition r c -cursorRight :: MonadIO m => Int -> m () -cursorRight = liftIO . ANSI.cursorForward +cursorSave :: MonadIO m => m () +cursorSave = liftIO ANSI.saveCursor + +cursorRestore :: MonadIO m => m () +cursorRestore = liftIO ANSI.restoreCursor + +putCsi :: MonadIO m => Char -> [Int] -> m () +putCsi c a = liftIO do + putStr "\x1b[" + putStr $ pack $ mconcat $ intersperse ";" (fmap show a) + putStr $ pack [c] + +hijack :: MonadIO m => Int -> IO () -> m () +hijack h d = liftIO do + putCsi 'r' [1, h-1] -- set scroll region to exclude bottom line + putCsi 'S' [1] -- scroll up one line + cursorMove (h-2) 0 -- move cursor to empty space + d + putCsi 'r' [] -- reset scroll region + cursorRestore -- restory cursor position diff --git a/pkg/interface/package-lock.json b/pkg/interface/package-lock.json index 39a1f4c99d7bbff9730b3aebe548280fd4fbd553..9f6f63c6dd5b1b6323464554449ec93b41db9e35 100644 GIT binary patch literal 1363532 zcmeFaX_Knj(k}Y_{)!#ztG6bgqIe=s#1TQTK@p_U4=V!cmA+Bn#QE=c*kfB-vuf@Y z=dL$mzpJJ+Imjowkt0Wr|NZ~`=RbdWimU(iKmPNV?In6-D60O~|GWKptw*u#d)q6> zFZdU{|JCu;m0>%&c)E)0?vC^@wIe+SwF$5NCRjTV+&u!`>pN>*+m6Lbk|6#c5ESXA9Vb!#%M09P{L7C_=;F=L$Bw`U z@(aA`S7H{s@$X)@{ZKQqlYINW*iulW`jKUc40kq~wZMj|sU${!<*&jiHYnJ&+FNXf ztt=P{aLXHS@Iv8}h2g^5$Wvn$X6k8NAp@V)q`bLa6au>D$8>Yh2+aTaKhIP(eSKig zjt~E5%c3$nOgpjC#RG=aPY8U8A^Ud&mhAud*uCy^rjSc$RwXN<*oe87+zg~4+O3Hu zDMf8unO0j>f(tpJ!PPBqvSgDER1h^!F*8wBH3%%h$HT|JUDpsCMA~=Rg1F zKGv5Xas13{l|zuz2mn{!Q-Kl%0DI|QKq25?2=Y1jA~&O{iHJm@$Bp};#;hq}F@pvk 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%0DK0-=)ERyq8W% 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%0ABqp+DF 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 n6Sl<6|BxCQd9z5Kj=taO$oqy6ON)y0nzkKJ= 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 bxIfcA84l`m>YjI^7o!0F```ca-~aMImqcgt literal 882585 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

m)-o=I(DsV#=^Qeq}rNsYTyCt9~L^`2{T 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%0D(w+DMpc-V4sr8v?EDqV8ZB)zEW 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

Loading...

+ : + + + + + ); +} diff --git a/pkg/interface/webterm/Tab.tsx b/pkg/interface/webterm/Tab.tsx new file mode 100644 index 000000000..0c3f14831 --- /dev/null +++ b/pkg/interface/webterm/Tab.tsx @@ -0,0 +1,44 @@ +import { DEFAULT_SESSION } from './constants'; +import React, { useCallback } from 'react'; +import useTermState from './state'; +import { style } from 'styled-system'; +import api from './api'; +import { pokeTask } from '@urbit/api/term'; + +export const Tab = ( { session, name } ) => { + + const isSelected = useTermState().selected === name; + + const onClick = () => { + console.log('click!', name); + useTermState.getState().set((state) => { + state.selected = name; + state.sessions[name].hasBell = false; + }); + useTermState.getState().sessions[name]?.term?.focus(); + } + + const onDelete = (e) => { + e.stopPropagation(); + api.poke(pokeTask(name, { shut: null })); + useTermState.getState().set(state => { + if (state.selected === name) { + state.selected = DEFAULT_SESSION; + } + state.names = state.names.filter(n => n !== name); + delete state.sessions[name]; + }); + //TODO clean up the subscription + } + + return ( + + ); +}; diff --git a/pkg/interface/webterm/Tabs.tsx b/pkg/interface/webterm/Tabs.tsx new file mode 100644 index 000000000..37d64eed5 --- /dev/null +++ b/pkg/interface/webterm/Tabs.tsx @@ -0,0 +1,36 @@ +import { pokeTask } from '@urbit/api/term'; +import api from './api'; +import React from 'react'; +import useTermState from './state'; +import { Tab } from './Tab'; + +export const Tabs = () => { + const { sessions, names } = useTermState(); + + const onAddClick = () => { + const name = prompt('please entew a session name uwu'); + if (!name) { + return; + } + //TODO name must be @ta + api.poke(pokeTask(name, { open: { term: 'hood', apps: [{ who: '~'+(window as any).ship, app: 'dojo' }] } })); + useTermState.getState().set(state => { + state.names = [name, ...state.names].sort(); + state.selected = name; + state.sessions[name] = null; + }); + + + } + + return ( +
+ { names.map((n, i) => { + return ( + + ); + })} + +
+ ); +}; diff --git a/pkg/interface/webterm/app.tsx b/pkg/interface/webterm/app.tsx index 8b0dd65a6..d7c782f29 100644 --- a/pkg/interface/webterm/app.tsx +++ b/pkg/interface/webterm/app.tsx @@ -1,292 +1,42 @@ /* eslint-disable max-lines */ import React, { - useEffect, - useRef, - useCallback + useCallback, useEffect } from 'react'; -import useTermState from './state'; +import useTermState, { Sessions } from './state'; import { useDark } from './join'; import api from './api'; -import { Terminal, ITerminalOptions, ITheme } from 'xterm'; -import { FitAddon } from 'xterm-addon-fit'; -import { saveAs } from 'file-saver'; - -import { Box, Col, Reset, _dark, _light } from '@tlon/indigo-react'; +import { Reset, _dark, _light } from '@tlon/indigo-react'; import 'xterm/css/xterm.css'; import { - Belt, Blit, Stye, Stub, Tint, Deco, - pokeTask, pokeBelt + scrySessions } from '@urbit/api/term'; -import bel from './lib/bel'; import { ThemeProvider } from 'styled-components'; +import { Tabs } from './Tabs'; +import Buffer from './Buffer'; +import { DEFAULT_SESSION } from './constants'; +import { showSlog } from './lib/blit'; type TermAppProps = { ship: string; } -const makeTheme = (dark: boolean): ITheme => { - let fg, bg: string; - if (dark) { - fg = 'white'; - bg = 'rgb(26,26,26)'; - } else { - fg = 'black'; - bg = 'white'; - } - // TODO indigo colors. - // we can't pluck these from ThemeContext because they have transparency. - // technically xterm supports transparency, but it degrades performance. - return { - foreground: fg, - background: bg, - brightBlack: '#7f7f7f', // NOTE slogs - cursor: fg - }; -}; - -const termConfig: ITerminalOptions = { - logLevel: 'warn', - // - convertEol: true, - // - rows: 24, - cols: 80, - scrollback: 10000, - // - fontFamily: '"Source Code Pro", "Roboto mono", "Courier New", monospace', - fontWeight: 400, - // NOTE theme colors configured dynamically - // - bellStyle: 'sound', - bellSound: bel, - // - // allows text selection by holding modifier (option, or shift) - macOptionClickForcesSelection: true -}; - -const csi = (cmd: string, ...args: number[]) => { - return '\x1b[' + args.join(';') + cmd; -}; - -const tint = (t: Tint) => { - switch (t) { - case null: return '9'; - case 'k': return '0'; - case 'r': return '1'; - case 'g': return '2'; - case 'y': return '3'; - case 'b': return '4'; - case 'm': return '5'; - case 'c': return '6'; - case 'w': return '7'; - default: return `8;2;${t.r%256};${t.g%256};${t.b%256}`; - } -}; - -const stye = (s: Stye) => { - let out = ''; - - // text decorations - // - if (s.deco.length > 0) { - out += s.deco.reduce((decs: number[], deco: Deco) => { - /* eslint-disable max-statements-per-line */ - switch (deco) { - case null: decs.push(0); return decs; - case 'br': decs.push(1); return decs; - case 'un': decs.push(4); return decs; - case 'bl': decs.push(5); return decs; - default: console.log('weird deco', deco); return decs; - } - }, []).join(';'); - } - - // background color - // - if (s.back !== null) { - if (out !== '') { - out += ';'; - } - out += '4'; - out += tint(s.back); - } - - // foreground color - // - if (s.fore !== null) { - if (out !== '') { - out += ';'; - } - out += '3'; - out += tint(s.fore); - } - - if (out === '') { - return out; - } - return '\x1b[' + out + 'm'; -}; - -const showBlit = (term: Terminal, blit: Blit) => { - let out = ''; - - if ('bel' in blit) { - out += '\x07'; - } else if ('clr' in blit) { - term.clear(); - out += csi('u'); - } else if ('hop' in blit) { - if (typeof blit.hop === 'number') { - out += csi('H', term.rows, blit.hop + 1); - } else { - out += csi('H', term.rows - blit.hop.r, blit.hop.c + 1); - } - out += csi('s'); // save cursor position - } else if ('put' in blit) { - out += blit.put.join(''); - out += csi('u'); - } else if ('klr' in blit) { - out += blit.klr.reduce((lin: string, p: Stub) => { - lin += stye(p.stye); - lin += p.text.join(''); - lin += csi('m', 0); - return lin; - }, ''); - out += csi('u'); - } else if ('nel' in blit) { - out += '\n'; - } else if ('sag' in blit || 'sav' in blit) { - const sav = ('sag' in blit) ? blit.sag : blit.sav; - const name = sav.path.split('/').slice(-2).join('.'); - const buff = Buffer.from(sav.file, 'base64'); - const blob = new Blob([buff], { type: 'application/octet-stream' }); - saveAs(blob, name); - } else if ('url' in blit) { - window.open(blit.url); - } else if ('wyp' in blit) { - out += '\r' + csi('K'); - out += csi('u'); - // - } else { - console.log('weird blit', blit); - } - - term.write(out); -}; - -// NOTE should generally only be passed the default terminal session -const showSlog = (term: Terminal, slog: string) => { - // set scroll region to exclude the bottom line, - // scroll up one line, - // move cursor to start of the newly created whitespace, - // set text to grey, - // print the slog, - // restore color, scroll region, and cursor. - // - term.write(csi('r', 1, term.rows - 1) - + csi('S', 1) - + csi('H', term.rows - 1, 1) - + csi('m', 90) - + slog - + csi('m', 0) - + csi('r') - + csi('u')); -}; - -const readInput = (term: Terminal, e: string): Belt[] => { - const belts: Belt[] = []; - let strap = ''; - - while (e.length > 0) { - let c = e.charCodeAt(0); - - // text input - // - if (c >= 32 && c !== 127) { - strap += e[0]; - e = e.slice(1); - continue; - } else if ('' !== strap) { - belts.push({ txt: strap.split('') }); - strap = ''; - } - - // special keys/characters - // - if (0 === c) { - term.write('\x07'); // bel - } else if (8 === c || 127 === c) { - belts.push({ bac: null }); - } else if (13 === c) { - belts.push({ ret: null }); - } else if (c <= 26) { - let k = String.fromCharCode(96 + c); - //NOTE prevent remote shut-downs - if ('d' !== k) { - belts.push({ mod: { mod: 'ctl', key: k } }); - } - } - - // escape sequences - // - if (27 === c) { // ESC - e = e.slice(1); - c = e.charCodeAt(0); - if (91 === c || 79 === c) { // [ or O - e = e.slice(1); - c = e.charCodeAt(0); - /* eslint-disable max-statements-per-line */ - switch (c) { - case 65: belts.push({ aro: 'u' }); break; - case 66: belts.push({ aro: 'd' }); break; - case 67: belts.push({ aro: 'r' }); break; - case 68: belts.push({ aro: 'l' }); break; - // - case 77: { - const m = e.charCodeAt(1) - 31; - if (1 === m) { - const c = e.charCodeAt(2) - 32; - const r = e.charCodeAt(3) - 32; - belts.push({ hit: { r: term.rows - r, c: c - 1 } }); - } - e = e.slice(3); - break; - } - // - default: term.write('\x07'); break; // bel - } - } else if (c >= 97 && c <= 122) { // a <= c <= z - belts.push({ mod: { mod: 'met', key: e[0] } }); - } else if (c === 46) { // . - belts.push({ mod: { mod: 'met', key: '.' } }); - } else if (c === 8 || c === 127) { - belts.push({ mod: { mod: 'met', key: { bac: null } } }); - } else { - term.write('\x07'); break; // bel - } - } - - e = e.slice(1); - } - if ('' !== strap) { - belts.push({ txt: strap.split('') }); - strap = ''; - } - return belts; -}; - export default function TermApp(props: TermAppProps) { - const container = useRef(null); - // TODO allow switching of selected - const { sessions, selected, slogstream, set } = useTermState(); - const session = sessions[selected]; + const { names, selected } = useTermState(); const dark = useDark(); + const initSessions = useCallback(async () => { + const response = await api.scry(scrySessions()); + + useTermState.getState().set((state) => { + state.names = response.sort(); + }); + }, []); + const setupSlog = useCallback(() => { console.log('slog: setting up...'); let available = false; @@ -298,9 +48,10 @@ export default function TermApp(props: TermAppProps) { }; slog.onmessage = (e) => { - const session = useTermState.getState().sessions['']; + const session = useTermState.getState().sessions[DEFAULT_SESSION]; if (!session) { - console.log('default session mia!', 'slog:', slog); + console.log('slog: default session mia!', 'msg:', e.data); + console.log(Object.keys(useTermState.getState().sessions), session); return; } showSlog(session.term, e.data); @@ -319,131 +70,26 @@ export default function TermApp(props: TermAppProps) { } }; - set((state) => { + useTermState.getState().set((state) => { state.slogstream = slog; }); - }, [sessions]); + }, []); - const onInput = useCallback((ses: string, e: string) => { - const term = useTermState.getState().sessions[ses].term; - const belts = readInput(term, e); - belts.map((b) => { - api.poke(pokeBelt(ses, b)); - }); - }, [sessions]); - - const onResize = useCallback(() => { - // TODO debounce, if it ever becomes a problem - session?.fit.fit(); - }, [session]); - - // on-init, open slogstream - // useEffect(() => { - if (!slogstream) { - setupSlog(); - } - window.addEventListener('resize', onResize); - return () => { - // TODO clean up subs? - window.removeEventListener('resize', onResize); - }; - }, [onResize, setupSlog]); - - // on dark mode change, change terminals' theme - // - useEffect(() => { - const theme = makeTheme(dark); - for (const ses in sessions) { - sessions[ses].term.setOption('theme', theme); - } - if (container.current) { - container.current.style.backgroundColor = theme.background || ''; - } - }, [dark, sessions]); - - // on selected change, maybe setup the term, or put it into the container - // - useEffect(() => { - let ses = session; - // initialize terminal - // - if (!ses) { - // set up terminal - // - const term = new Terminal(termConfig); - term.setOption('theme', makeTheme(dark)); - const fit = new FitAddon(); - term.loadAddon(fit); - - // start mouse reporting - // - term.write(csi('?9h')); - - // set up event handlers - // - term.onData(e => onInput(selected, e)); - term.onBinary(e => onInput(selected, e)); - term.onResize((e) => { - api.poke(pokeTask(selected, { blew: { w: e.cols, h: e.rows } })); - }); - - ses = { term, fit }; - - // open subscription - // - api.subscribe({ app: 'herm', path: '/session/'+selected+'/view', - event: (e) => { - const ses = useTermState.getState().sessions[selected]; - if (!ses) { - console.log('on blit: no such session', selected, sessions, useTermState.getState().sessions); - return; - } - showBlit(ses.term, e); - }, - quit: () => { // quit - // TODO show user a message - } - }); - } - - if (container.current && !container.current.contains(ses.term.element || null)) { - ses.term.open(container.current); - ses.fit.fit(); - ses.term.focus(); - } - - set((state) => { - state.sessions[selected] = ses; - }); - - return () => { - // TODO unload term from container - // but term.dispose is too powerful? maybe just empty the container? - }; - }, [set, session, container]); + initSessions(); + setupSlog(); + }, []); return ( <> - - - - + +
+ {names.map(name => { + return ; + })} +
); diff --git a/pkg/interface/webterm/constants.ts b/pkg/interface/webterm/constants.ts new file mode 100644 index 000000000..23cbd3497 --- /dev/null +++ b/pkg/interface/webterm/constants.ts @@ -0,0 +1 @@ +export const DEFAULT_SESSION = ''; diff --git a/pkg/interface/webterm/index.html b/pkg/interface/webterm/index.html index 5eaf05c35..ed7f86111 100644 --- a/pkg/interface/webterm/index.html +++ b/pkg/interface/webterm/index.html @@ -27,6 +27,44 @@ margin: 0; padding: 0; } + + .buffer-container { + height: calc(100% - 33px); + } + + div.tabs { + height: 33px; + display: flex; + flex-flow: row nowrap; + justify-content: flex-start; + padding: 5px 0; + border-bottom: 1px solid black; + } + + div.tabs > * { + margin-left: 5px; + margin-right: 5px; + border: solid 1px black; + padding: 7px; + cursor: pointer; + } + + div.tab { + text-align: center; + /* display: flex; + flex-flow: row nowrap; + align-items: center; + justify-content: space-between; */ + } + + div.tabs > div.selected > a.session-name { + font-weight: bold; + } + + div.tabs > a.delete-session { + padding: 5px; + } + diff --git a/pkg/interface/webterm/lib/blit.ts b/pkg/interface/webterm/lib/blit.ts new file mode 100644 index 000000000..534328433 --- /dev/null +++ b/pkg/interface/webterm/lib/blit.ts @@ -0,0 +1,73 @@ +import { Terminal } from 'xterm'; +import { saveAs } from 'file-saver'; +import { Blit, Stub } from '@urbit/api/term'; +import { stye } from '../lib/stye'; + +export const csi = (cmd: string, ...args: number[]) => { + return '\x1b[' + args.join(';') + cmd; +}; + +export const showBlit = (term: Terminal, blit: Blit) => { + let out = ''; + + if ('bel' in blit) { + out += '\x07'; + } else if ('clr' in blit) { + term.clear(); + out += csi('u'); + } else if ('hop' in blit) { + if (typeof blit.hop === 'number') { + out += csi('H', term.rows, blit.hop + 1); + } else { + out += csi('H', term.rows - blit.hop.r, blit.hop.c + 1); + } + out += csi('s'); // save cursor position + } else if ('put' in blit) { + out += blit.put.join(''); + out += csi('u'); + } else if ('klr' in blit) { + out += blit.klr.reduce((lin: string, p: Stub) => { + lin += stye(p.stye); + lin += p.text.join(''); + lin += csi('m', 0); + return lin; + }, ''); + out += csi('u'); + } else if ('nel' in blit) { + out += '\n'; + } else if ('sag' in blit || 'sav' in blit) { + const sav = ('sag' in blit) ? blit.sag : blit.sav; + const name = sav.path.split('/').slice(-2).join('.'); + const buff = Buffer.from(sav.file, 'base64'); + const blob = new Blob([buff], { type: 'application/octet-stream' }); + saveAs(blob, name); + } else if ('url' in blit) { + window.open(blit.url); + } else if ('wyp' in blit) { + out += '\r' + csi('K'); + out += csi('u'); + // + } else { + console.log('weird blit', blit); + } + + term.write(out); +}; + +export const showSlog = (term: Terminal, slog: string) => { + // set scroll region to exclude the bottom line, + // scroll up one line, + // move cursor to start of the newly created whitespace, + // set text to grey, + // print the slog, + // restore color, scroll region, and cursor. + // + term.write(csi('r', 1, term.rows - 1) + + csi('S', 1) + + csi('H', term.rows - 1, 1) + + csi('m', 90) + + slog + + csi('m', 0) + + csi('r') + + csi('u')); +}; diff --git a/pkg/interface/webterm/lib/stye.ts b/pkg/interface/webterm/lib/stye.ts new file mode 100644 index 000000000..bc2d99b5e --- /dev/null +++ b/pkg/interface/webterm/lib/stye.ts @@ -0,0 +1,60 @@ +import { Deco, Stye, Tint } from '@urbit/api/term'; + +const tint = (t: Tint) => { + switch (t) { + case null: return '9'; + case 'k': return '0'; + case 'r': return '1'; + case 'g': return '2'; + case 'y': return '3'; + case 'b': return '4'; + case 'm': return '5'; + case 'c': return '6'; + case 'w': return '7'; + default: return `8;2;${t.r%256};${t.g%256};${t.b%256}`; + } +}; + +export const stye = (s: Stye) => { + let out = ''; + + // text decorations + // + if (s.deco.length > 0) { + out += s.deco.reduce((decs: number[], deco: Deco) => { + /* eslint-disable max-statements-per-line */ + switch (deco) { + case null: decs.push(0); return decs; + case 'br': decs.push(1); return decs; + case 'un': decs.push(4); return decs; + case 'bl': decs.push(5); return decs; + default: console.log('weird deco', deco); return decs; + } + }, []).join(';'); + } + + // background color + // + if (s.back !== null) { + if (out !== '') { + out += ';'; + } + out += '4'; + out += tint(s.back); + } + + // foreground color + // + if (s.fore !== null) { + if (out !== '') { + out += ';'; + } + out += '3'; + out += tint(s.fore); + } + + if (out === '') { + return out; + } + return '\x1b[' + out + 'm'; +}; diff --git a/pkg/interface/webterm/lib/theme.ts b/pkg/interface/webterm/lib/theme.ts new file mode 100644 index 000000000..6044f1c30 --- /dev/null +++ b/pkg/interface/webterm/lib/theme.ts @@ -0,0 +1,21 @@ +import { ITheme } from 'xterm'; + +export const makeTheme = (dark: boolean): ITheme => { + let fg, bg: string; + if (dark) { + fg = 'white'; + bg = 'rgb(26,26,26)'; + } else { + fg = 'black'; + bg = 'white'; + } + // TODO indigo colors. + // we can't pluck these from ThemeContext because they have transparency. + // technically xterm supports transparency, but it degrades performance. + return { + foreground: fg, + background: bg, + brightBlack: '#7f7f7f', // NOTE slogs + cursor: fg + }; +}; diff --git a/pkg/interface/webterm/state.ts b/pkg/interface/webterm/state.ts index 253e7854f..2392db880 100644 --- a/pkg/interface/webterm/state.ts +++ b/pkg/interface/webterm/state.ts @@ -3,18 +3,22 @@ import { FitAddon } from 'xterm-addon-fit'; import create from 'zustand'; import produce from 'immer'; -type Session = { term: Terminal, fit: FitAddon }; -type Sessions = { [id: string]: Session; } +export type Session = { term: Terminal, fit: FitAddon, hasBell: boolean } | null; +export type Sessions = { [id: string]: Session; } export interface TermState { sessions: Sessions, + names: string[], selected: string, slogstream: null | EventSource, - theme: 'auto' | 'light' | 'dark' -}; + theme: 'auto' | 'light' | 'dark', + //TODO: figure out the type + set: any, +} const useTermState = create((set, get) => ({ sessions: {} as Sessions, + names: [''], selected: '', // empty string is default session slogstream: null, theme: 'auto', diff --git a/pkg/interface/webterm/tsconfig.json b/pkg/interface/webterm/tsconfig.json new file mode 100644 index 000000000..9a8642966 --- /dev/null +++ b/pkg/interface/webterm/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "noFallthroughCasesInSwitch": true, + "noUnusedParameters": false, + "noImplicitReturns": false, + "moduleResolution": "node", + "esModuleInterop": true, + "noUnusedLocals": false, + "noImplicitAny": false, + "noEmit": true, + "target": "ESNext", + "module": "ESNext", + "strict": false, + "strictNullChecks": true, + "jsx": "react", + "baseUrl": "." + }, + "include": [ + "**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} diff --git a/pkg/npm/api/term/lib.ts b/pkg/npm/api/term/lib.ts index 3d0424099..67e14175f 100644 --- a/pkg/npm/api/term/lib.ts +++ b/pkg/npm/api/term/lib.ts @@ -1,5 +1,5 @@ -import { Scry } from '../http-api/src' -import { Poke } from '../http-api/src/types'; +import { Scry } from '../../http-api/src' +import { Poke } from '../../http-api/src/types'; import { Belt, Task, SessionTask } from './types'; export const pokeTask = (session: string, task: Task): Poke => ({ diff --git a/pkg/npm/api/term/types.ts b/pkg/npm/api/term/types.ts index 502df692f..df4767cff 100644 --- a/pkg/npm/api/term/types.ts +++ b/pkg/npm/api/term/types.ts @@ -53,8 +53,8 @@ export type Belt = export type Task = | { belt: Belt } | { blew: { w: number, h: number } } - | { flow: { term: string, apps: Array<{ who: string, app: string }> } } | { hail: null } - | { hook: null } + | { open: { term: string, apps: Array<{ who: string, app: string }> } } + | { shut: null } export type SessionTask = { session: string } & Task From e41263c6532637e641caa51fc23765e3154deb8a Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 2 Mar 2022 22:49:31 -0600 Subject: [PATCH 020/715] dojo: add missing nu-sole-id compatability Forgotten code. --- pkg/arvo/app/dojo.hoon | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pkg/arvo/app/dojo.hoon b/pkg/arvo/app/dojo.hoon index bf0c24dd4..691b30df1 100644 --- a/pkg/arvo/app/dojo.hoon +++ b/pkg/arvo/app/dojo.hoon @@ -1706,14 +1706,16 @@ :: ++ on-arvo |= [=wire =sign-arvo] - ?> ?=([@ *] wire) - =/ =session (~(got by hoc) i.wire) - =/ he-full ~(. he hid i.wire ~ session) + ^- (quip card:agent:gall _..on-init) + ?> ?=([@ @ *] wire) + =/ =id [(slav %p i.wire) i.t.wire] + =/ =session (~(got by hoc) id) + =/ he-full ~(. he hid id ~ session) =^ moves state =< he-abet ?+ +<.sign-arvo ~|([%dojo-bad-take +<.sign-arvo] !!) - %writ (he-writ:he-full t.wire +>.sign-arvo) - %http-response (he-http-response:he-full t.wire +>.sign-arvo) + %writ (he-writ:he-full t.t.wire +>.sign-arvo) + %http-response (he-http-response:he-full t.t.wire +>.sign-arvo) == [moves ..on-init] :: if dojo fails unexpectedly, kill whatever each session is working on From 25a1c79aa3f4dd9fc2ce4ee129bb888274129e50 Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 2 Mar 2022 23:25:38 -0600 Subject: [PATCH 021/715] drum: properly hook up new |link More uncommitted code. --- pkg/arvo/lib/hood/drum.hoon | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pkg/arvo/lib/hood/drum.hoon b/pkg/arvo/lib/hood/drum.hoon index f62143e21..001e07324 100644 --- a/pkg/arvo/lib/hood/drum.hoon +++ b/pkg/arvo/lib/hood/drum.hoon @@ -171,21 +171,22 @@ se-abet:(se-blit-sys bit) :: ++ poke-link :: connect app - |= gyl=gill:gall + |= [ses=@tas gyl=gill:gall] =< se-abet - (se-link gyl) + (se-link:(prep ses) gyl) :: ++ poke-unlink :: disconnect app - |= gyl=gill:gall + |= [ses=@ta gyl=gill:gall] =< se-abet - (se-drop:(se-pull gyl) & gyl) + (se-drop:(se-pull:(prep ses) gyl) & gyl) :: ++ poke-exit :: shutdown |= ~ se-abet:(se-blit-sys `dill-blit:dill`[%qit ~]) :: ++ poke-put :: write file - |= [pax=path txt=@] + |= [pax=path arg=$@(@ [@tas @])] + =^ txt +> ?@(arg [arg +>] [+.arg (prep -.arg)]) se-abet:(se-blit-sys [%sav pax txt]) :: :: ++ poke @@ -368,7 +369,7 @@ [%cru *] (se-dump:(se-text (trip p.bet)) q.bet) [%hey *] +>(mir [0 ~]) :: refresh [%rez *] +>(edg (dec p.bet)) :: resize window - [%yow *] ~&([%no-yow -.bet] +>) + [%yow *] (se-link p.bet) == =+ gul=se-agon ?: |(?=(~ gul) (se-aint u.gul)) From 1a50957950fa9bd972d5e5c00c64428c4f8f9319 Mon Sep 17 00:00:00 2001 From: tomholford Date: Thu, 3 Mar 2022 16:58:48 -0600 Subject: [PATCH 022/715] ux: session ID input validation When creating a new session, validate that it meets the following conditions: - must start with an alphabetical - can be composed of alphanumerics with hyphens - can be length 1 or longer - cannot begin or end with a hyphen --- pkg/interface/webterm/Tabs.tsx | 11 +++++------ pkg/interface/webterm/constants.ts | 10 ++++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/pkg/interface/webterm/Tabs.tsx b/pkg/interface/webterm/Tabs.tsx index 37d64eed5..bf3d32b64 100644 --- a/pkg/interface/webterm/Tabs.tsx +++ b/pkg/interface/webterm/Tabs.tsx @@ -3,29 +3,28 @@ import api from './api'; import React from 'react'; import useTermState from './state'; import { Tab } from './Tab'; +import { SESSION_ID_REGEX } from './constants'; export const Tabs = () => { const { sessions, names } = useTermState(); const onAddClick = () => { const name = prompt('please entew a session name uwu'); - if (!name) { + if (!name || !SESSION_ID_REGEX.test(name) || names.includes(name)) { + console.log('invalid session name:', name); return; } - //TODO name must be @ta - api.poke(pokeTask(name, { open: { term: 'hood', apps: [{ who: '~'+(window as any).ship, app: 'dojo' }] } })); + api.poke(pokeTask(name, { open: { term: 'hood', apps: [{ who: '~' + (window as any).ship, app: 'dojo' }] } })); useTermState.getState().set(state => { state.names = [name, ...state.names].sort(); state.selected = name; state.sessions[name] = null; }); - - } return (
- { names.map((n, i) => { + {names.map((n, i) => { return ( ); diff --git a/pkg/interface/webterm/constants.ts b/pkg/interface/webterm/constants.ts index 23cbd3497..7e173ac64 100644 --- a/pkg/interface/webterm/constants.ts +++ b/pkg/interface/webterm/constants.ts @@ -1 +1,11 @@ export const DEFAULT_SESSION = ''; + +/** + * Session ID validity: + * + * - must start with an alphabetical + * - can be composed of alphanumerics with hyphens + * - can be length 1 or longer + * - cannot begin or end with a hyphen + */ +export const SESSION_ID_REGEX = /(^[a-z]{1}[a-z\d\-]*[a-z\d]{1}$)|(^[a-z]{1}$)/; From fe1ece47d83a35d446722c7bfcc4181468c59a57 Mon Sep 17 00:00:00 2001 From: tomholford Date: Thu, 3 Mar 2022 17:09:38 -0600 Subject: [PATCH 023/715] api: clean up subscriptions on deletion of session On subscribe, track the subcription ID in the Session state. On deletion, unsubscribe using the same ID. --- pkg/interface/webterm/Buffer.tsx | 6 +++--- pkg/interface/webterm/Tab.tsx | 26 +++++++++++++++++++------- pkg/interface/webterm/state.ts | 7 ++++++- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx index d33b2e9ec..ef65c592b 100644 --- a/pkg/interface/webterm/Buffer.tsx +++ b/pkg/interface/webterm/Buffer.tsx @@ -162,7 +162,7 @@ export default function Buffer({ name, selected }: BufferProps) { // term.write(csi('?9h')); - const ses: Session = { term, fit, hasBell: false }; + const ses: Session = { term, fit, hasBell: false, subscriptionId: null }; // set up event handlers // @@ -174,7 +174,7 @@ export default function Buffer({ name, selected }: BufferProps) { // open subscription // - await api.subscribe({ app: 'herm', path: '/session/'+name+'/view', + ses.subscriptionId = await api.subscribe({ app: 'herm', path: '/session/'+name+'/view', event: (e) => { showBlit(ses.term, e); if (e.bel && !selected) { @@ -189,7 +189,7 @@ export default function Buffer({ name, selected }: BufferProps) { console.error('oops quit, pls handle'); } }); - + useTermState.getState().set((state) => { state.sessions[name] = ses; }); diff --git a/pkg/interface/webterm/Tab.tsx b/pkg/interface/webterm/Tab.tsx index 0c3f14831..f55627f6d 100644 --- a/pkg/interface/webterm/Tab.tsx +++ b/pkg/interface/webterm/Tab.tsx @@ -1,16 +1,20 @@ import { DEFAULT_SESSION } from './constants'; import React, { useCallback } from 'react'; -import useTermState from './state'; +import useTermState, { Session } from './state'; import { style } from 'styled-system'; import api from './api'; import { pokeTask } from '@urbit/api/term'; -export const Tab = ( { session, name } ) => { +interface TabProps { + session: Session; + name: string; +} + +export const Tab = ( { session, name }: TabProps ) => { const isSelected = useTermState().selected === name; const onClick = () => { - console.log('click!', name); useTermState.getState().set((state) => { state.selected = name; state.sessions[name].hasBell = false; @@ -18,9 +22,18 @@ export const Tab = ( { session, name } ) => { useTermState.getState().sessions[name]?.term?.focus(); } - const onDelete = (e) => { + const onDelete = useCallback(async (e) => { e.stopPropagation(); - api.poke(pokeTask(name, { shut: null })); + + // clean up subscription + if(session && session.subscriptionId) { + await api.unsubscribe(session.subscriptionId); + } + + // DELETE + await api.poke(pokeTask(name, { shut: null })); + + // remove from zustand useTermState.getState().set(state => { if (state.selected === name) { state.selected = DEFAULT_SESSION; @@ -28,8 +41,7 @@ export const Tab = ( { session, name } ) => { state.names = state.names.filter(n => n !== name); delete state.sessions[name]; }); - //TODO clean up the subscription - } + }, [session]); return (
diff --git a/pkg/interface/webterm/state.ts b/pkg/interface/webterm/state.ts index 2392db880..b6ca56633 100644 --- a/pkg/interface/webterm/state.ts +++ b/pkg/interface/webterm/state.ts @@ -3,7 +3,12 @@ import { FitAddon } from 'xterm-addon-fit'; import create from 'zustand'; import produce from 'immer'; -export type Session = { term: Terminal, fit: FitAddon, hasBell: boolean } | null; +export type Session = { + term: Terminal, + fit: FitAddon, + hasBell: boolean, + subscriptionId: number | null, +} | null; export type Sessions = { [id: string]: Session; } export interface TermState { From 438e6d4df983aec7ab1fe1e5ff5a8e089900200e Mon Sep 17 00:00:00 2001 From: tomholford Date: Thu, 3 Mar 2022 17:10:54 -0600 Subject: [PATCH 024/715] ui: style tabs also rename join --> useDark; clean up extraneous logging statements --- pkg/interface/webterm/{app.tsx => App.tsx} | 10 ++--- pkg/interface/webterm/Buffer.tsx | 11 ++--- pkg/interface/webterm/Tab.tsx | 2 +- pkg/interface/webterm/Tabs.tsx | 2 +- pkg/interface/webterm/index.html | 43 ++++++++++++++----- .../webterm/{join.ts => lib/useDark.ts} | 8 ++-- 6 files changed, 45 insertions(+), 31 deletions(-) rename pkg/interface/webterm/{app.tsx => App.tsx} (91%) rename pkg/interface/webterm/{join.ts => lib/useDark.ts} (75%) diff --git a/pkg/interface/webterm/app.tsx b/pkg/interface/webterm/App.tsx similarity index 91% rename from pkg/interface/webterm/app.tsx rename to pkg/interface/webterm/App.tsx index d7c782f29..9ad1d6185 100644 --- a/pkg/interface/webterm/app.tsx +++ b/pkg/interface/webterm/App.tsx @@ -1,13 +1,12 @@ -/* eslint-disable max-lines */ import React, { useCallback, useEffect } from 'react'; -import useTermState, { Sessions } from './state'; -import { useDark } from './join'; +import useTermState from './state'; +import { useDark } from './lib/useDark'; import api from './api'; -import { Reset, _dark, _light } from '@tlon/indigo-react'; +import { _dark, _light } from '@tlon/indigo-react'; import 'xterm/css/xterm.css'; @@ -83,11 +82,10 @@ export default function TermApp(props: TermAppProps) { return ( <> -
{names.map(name => { - return ; + return ; })}
diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx index ef65c592b..8ef69e2e9 100644 --- a/pkg/interface/webterm/Buffer.tsx +++ b/pkg/interface/webterm/Buffer.tsx @@ -12,8 +12,7 @@ import useTermState from './state'; import React from 'react'; import { Box, Col } from '@tlon/indigo-react'; import { makeTheme } from './lib/theme'; -import { useDark } from './join'; -import { showBlit, csi, showSlog } from './lib/blit'; +import { showBlit, csi } from './lib/blit'; const termConfig: ITerminalOptions = { logLevel: 'warn', @@ -138,11 +137,11 @@ const onInput = (name: string, session: Session, e: string) => { interface BufferProps { name: string, selected: boolean, + dark: boolean, } -export default function Buffer({ name, selected }: BufferProps) { +export default function Buffer({ name, selected, dark }: BufferProps) { const container = useRef(null); - const dark = useDark(); const session: Session = useTermState(s => s.sessions[name]); @@ -210,10 +209,6 @@ export default function Buffer({ name, selected }: BufferProps) { let newContainer = containerRef || container.current; if(session && newContainer) { container.current = newContainer; - console.log('newcont', newContainer); - // session.term.open(newContainer); - } else { - console.log('kaboom', session); } }, [session]); diff --git a/pkg/interface/webterm/Tab.tsx b/pkg/interface/webterm/Tab.tsx index f55627f6d..0813292bd 100644 --- a/pkg/interface/webterm/Tab.tsx +++ b/pkg/interface/webterm/Tab.tsx @@ -44,7 +44,7 @@ export const Tab = ( { session, name }: TabProps ) => { }, [session]); return ( -
+ ); }; diff --git a/pkg/interface/webterm/index.html b/pkg/interface/webterm/index.html index ed7f86111..e2f4a18c2 100644 --- a/pkg/interface/webterm/index.html +++ b/pkg/interface/webterm/index.html @@ -29,32 +29,38 @@ } .buffer-container { - height: calc(100% - 33px); + height: calc(100% - 40px); } div.tabs { - height: 33px; + height: 40px; display: flex; flex-flow: row nowrap; justify-content: flex-start; - padding: 5px 0; + padding: 5px 5px 0 5px; border-bottom: 1px solid black; + background-color: white; } div.tabs > * { margin-left: 5px; margin-right: 5px; border: solid 1px black; - padding: 7px; + padding: 10px; cursor: pointer; } - div.tab { - text-align: center; - /* display: flex; - flex-flow: row nowrap; - align-items: center; - justify-content: space-between; */ + div.tab, button.tab { + margin-bottom: -1px; /** To overlay the selected tab on the tabs container bottom border */ + border-top-left-radius: 5px; + border-top-right-radius: 5px; + font-family: monospace; + font-size: 14px; + line-height: 18px; + } + + div.tabs > div.selected { + border-bottom: white solid 1px; } div.tabs > div.selected > a.session-name { @@ -65,6 +71,23 @@ padding: 5px; } + @media (prefers-color-scheme: dark) { + div.tabs { + background-color: rgb(26, 26, 26); + color: rgba(255, 255, 255, 0.9); + border-bottom-color: rgba(255, 255, 255, 0.9); + } + + div.tab, button.tab { + background-color: rgb(26, 26, 26); + color: rgba(255, 255, 255, 0.9); + border-color: rgba(255, 255, 255, 0.9); + } + + div.tabs > div.selected { + border-bottom: black solid 1px; + } + } diff --git a/pkg/interface/webterm/join.ts b/pkg/interface/webterm/lib/useDark.ts similarity index 75% rename from pkg/interface/webterm/join.ts rename to pkg/interface/webterm/lib/useDark.ts index 957abbd3d..cd9625403 100644 --- a/pkg/interface/webterm/join.ts +++ b/pkg/interface/webterm/lib/useDark.ts @@ -1,6 +1,5 @@ import { useEffect, useState } from 'react'; -import { useTheme } from './settings'; -import useTermState from './state'; +import useTermState from '../state'; export function useDark() { const [osDark, setOsDark] = useState(false); @@ -11,12 +10,11 @@ export function useDark() { setOsDark(e.matches); }; setOsDark(themeWatcher.matches); - themeWatcher.addListener(update); + themeWatcher.addEventListener('change', update); return () => { - themeWatcher.removeListener(update); + themeWatcher.removeEventListener('change', update); } - }, []); const theme = useTermState(s => s.theme); From 87ac253b8d9dd6873129c83a4268623c040c2271 Mon Sep 17 00:00:00 2001 From: tomholford Date: Thu, 3 Mar 2022 18:11:37 -0600 Subject: [PATCH 025/715] ux: default terminal sets correct theme onload also, increase size of Tab click target --- pkg/interface/webterm/Buffer.tsx | 5 +++-- pkg/interface/webterm/Tab.tsx | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx index 8ef69e2e9..dca9d8d71 100644 --- a/pkg/interface/webterm/Buffer.tsx +++ b/pkg/interface/webterm/Buffer.tsx @@ -13,6 +13,7 @@ import React from 'react'; import { Box, Col } from '@tlon/indigo-react'; import { makeTheme } from './lib/theme'; import { showBlit, csi } from './lib/blit'; +import { DEFAULT_SESSION } from './constants'; const termConfig: ITerminalOptions = { logLevel: 'warn', @@ -146,7 +147,7 @@ export default function Buffer({ name, selected, dark }: BufferProps) { const session: Session = useTermState(s => s.sessions[name]); const initSession = useCallback(async (name: string, dark: boolean) => { - console.log('setting up', name); + console.log('setting up', name === DEFAULT_SESSION ? 'default' : name); // set up xterm terminal // @@ -234,7 +235,7 @@ export default function Buffer({ name, selected, dark }: BufferProps) { if (container.current) { container.current.style.backgroundColor = theme.background || ''; } - }, [dark]); + }, [session, dark]); useEffect(() => { if (session && selected && !session.term.isOpen) { diff --git a/pkg/interface/webterm/Tab.tsx b/pkg/interface/webterm/Tab.tsx index 0813292bd..2fac14813 100644 --- a/pkg/interface/webterm/Tab.tsx +++ b/pkg/interface/webterm/Tab.tsx @@ -44,8 +44,8 @@ export const Tab = ( { session, name }: TabProps ) => { }, [session]); return ( -
- +
+ {session?.hasBell ? 'đź”” ' : ''} {name === DEFAULT_SESSION ? 'default' : name} {' '} From 8906d1c17d581ef809bdd21049f255d42b1ca53e Mon Sep 17 00:00:00 2001 From: fang Date: Sat, 5 Mar 2022 18:17:48 -0600 Subject: [PATCH 026/715] dill: move %mor case into $blit This lets us send a single blit around, instead of sending facts for every individual blit in a draw event. --- pkg/arvo/lib/hood/drum.hoon | 10 +++++----- pkg/arvo/sys/lull.hoon | 5 +++-- pkg/arvo/sys/vane/dill.hoon | 7 ++----- pkg/base-dev/lib/dill.hoon | 1 + pkg/interface/webterm/lib/blit.ts | 4 +++- pkg/npm/api/term/types.ts | 3 ++- pkg/urbit/vere/io/term.c | 12 +++++++++++- 7 files changed, 27 insertions(+), 15 deletions(-) diff --git a/pkg/arvo/lib/hood/drum.hoon b/pkg/arvo/lib/hood/drum.hoon index 001e07324..5399edeea 100644 --- a/pkg/arvo/lib/hood/drum.hoon +++ b/pkg/arvo/lib/hood/drum.hoon @@ -122,7 +122,7 @@ =+ (~(gut by bin) ses *source) =* dev - =| moz=(list card:agent:gall) -=| biz=(list dill-blit:dill) +=| biz=(list blit:dill) ::TODO should be per-session |% ++ this . ++ klr klr:format @@ -284,13 +284,13 @@ ^- (list card:agent:gall) ?~ biz (flop moz) :_ (flop moz) - =/ =dill-blit:dill ?~(t.biz i.biz [%mor (flop biz)]) + =/ =blit:dill ?~(t.biz i.biz [%mor (flop biz)]) ::TODO remove /drum after dill cleans up ::TODO but once we remove it, the empty trailing segment of :: /dill/[ses] would prevent outsiders from subscribing :: to the default session... =/ to=(list path) [/dill/[ses] ?~(ses ~[/drum] ~)] - [%give %fact to %dill-blit !>(dill-blit)] + [%give %fact to %dill-blit !>(blit)] :: ++ se-adze :: update connections ^+ . @@ -473,7 +473,7 @@ +>(eel (~(put in eel) gyl)) :: ++ se-blit :: give output - |= bil=dill-blit:dill + |= bil=blit:dill +>(biz [bil biz]) :: ++ se-blit-sys :: output to system @@ -640,7 +640,7 @@ %d ?^ buf.say.inp ta-del ?: =([our.hid %dojo] gyl) - +>(..ta (se-blit qit+~)) :: quit pier + +>(..ta (se-blit-sys %qit ~)) :: quit pier +>(..ta (se-klin gyl)) :: unlink app %e +>(pos.inp (lent buf.say.inp)) %f (ta-aro %r) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index d89745182..32a1de2c5 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -1088,8 +1088,9 @@ [%clr ~] :: clear the screen [%hop p=$@(@ud [r=@ud c=@ud])] :: set cursor col/pos [%klr p=stub] :: put styled - [%put p=(list @c)] :: put text at cursor + [%mor p=(list blit)] :: multiple blits [%nel ~] :: newline + [%put p=(list @c)] :: put text at cursor [%sag p=path q=*] :: save to jamfile [%sav p=path q=@] :: save to file [%url p=@t] :: activate url @@ -1099,12 +1100,12 @@ $% belt :: client input [%cru p=@tas q=(list tank)] :: echo error [%hey ~] :: refresh + ::TODO inconsistent with %hit and %hop [%rez p=@ud q=@ud] :: resize, cols, rows [%yow p=gill:gall] :: connect to app == :: +$ dill-blit :: arvo output $% blit :: client output - [%mor p=(list dill-blit)] :: multiple blits [%qit ~] :: close console == :: +$ flog :: sent to %dill diff --git a/pkg/arvo/sys/vane/dill.hoon b/pkg/arvo/sys/vane/dill.hoon index e2c1e4d2e..afb827c32 100644 --- a/pkg/arvo/sys/vane/dill.hoon +++ b/pkg/arvo/sys/vane/dill.hoon @@ -178,13 +178,10 @@ ++ from :: receive blit |= bit=dill-blit ^+ +> - ?: ?=(%mor -.bit) - |- ^+ +>.^$ - ?~ p.bit +>.^$ - $(p.bit t.p.bit, +>.^$ ^$(bit i.p.bit)) ?: ?=(%qit -.bit) (dump %logo ~) - (done %blit [bit ~]) + ::TODO so why is this a (list blit) again? + (done %blit bit ~) :: ++ sponsor ^- ship diff --git a/pkg/base-dev/lib/dill.hoon b/pkg/base-dev/lib/dill.hoon index d4cecdf14..d3592c07d 100644 --- a/pkg/base-dev/lib/dill.hoon +++ b/pkg/base-dev/lib/dill.hoon @@ -18,6 +18,7 @@ %nel b+& %url s+p.blit %wyp b+& + %mor a+(turn p.blit ^blit) :: %sag %- pairs diff --git a/pkg/interface/webterm/lib/blit.ts b/pkg/interface/webterm/lib/blit.ts index 534328433..5285675f1 100644 --- a/pkg/interface/webterm/lib/blit.ts +++ b/pkg/interface/webterm/lib/blit.ts @@ -10,7 +10,9 @@ export const csi = (cmd: string, ...args: number[]) => { export const showBlit = (term: Terminal, blit: Blit) => { let out = ''; - if ('bel' in blit) { + if ('mor' in blit) { + return blit.mor.map(b => showBlit(term, b)); + } else if ('bel' in blit) { out += '\x07'; } else if ('clr' in blit) { term.clear(); diff --git a/pkg/npm/api/term/types.ts b/pkg/npm/api/term/types.ts index df4767cff..362973f31 100644 --- a/pkg/npm/api/term/types.ts +++ b/pkg/npm/api/term/types.ts @@ -27,8 +27,9 @@ export type Blit = | { clr: null } // clear the screen | { hop: number | { r: number, c: number } } // set cursor col/pos | { klr: Stub[] } // put styled - | { put: string[] } // put text at cursor + | { mor: Blit[] } // multiple blits | { nel: null } // newline + | { put: string[] } // put text at cursor | { sag: { path: string, file: string } } // save to jamfile | { sav: { path: string, file: string } } // save to file | { url: string } // activate url diff --git a/pkg/urbit/vere/io/term.c b/pkg/urbit/vere/io/term.c index e2b6376ca..ba5775cbd 100644 --- a/pkg/urbit/vere/io/term.c +++ b/pkg/urbit/vere/io/term.c @@ -1353,7 +1353,17 @@ _term_ef_blit(u3_utty* uty_u, _term_it_show_tour(uty_u, u3k(u3t(blt))); } break; - case c3__mor: //TMP backwards compatibility + case c3__mor: { + if (u3_nul != u3t(blt)) { + u3_noun bis = u3t(blt); + while (u3_nul != bis) { + _term_ef_blit(uty_u, u3k(u3h(bis))); + bis = u3t(bis); + } + break; + } + //TMP fall through to nel for backwards compatibility + } case c3__nel: { _term_it_show_nel(uty_u); } break; From 8d9a59bfe4f67f7eeeb144c4580b7713e8d1d4ff Mon Sep 17 00:00:00 2001 From: tomholford Date: Wed, 9 Mar 2022 16:14:06 -0600 Subject: [PATCH 027/715] devex: eslint config --- pkg/interface/webterm/.eslintrc.js | 26 +++++++++++++++++++----- pkg/interface/webterm/package-lock.json | Bin 1275816 -> 1283742 bytes pkg/interface/webterm/package.json | 9 +++++--- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/pkg/interface/webterm/.eslintrc.js b/pkg/interface/webterm/.eslintrc.js index 66d65c291..8f36013ed 100644 --- a/pkg/interface/webterm/.eslintrc.js +++ b/pkg/interface/webterm/.eslintrc.js @@ -1,7 +1,23 @@ -const config = { +module.exports = exports = { "rules": { - "spaced-comment": false, - } + "spaced-comment": 0, + }, + "extends": [ + "eslint:recommended", + "plugin:import/errors", + "plugin:react/recommended", + ], + "settings": { + "react": { + "version": "detect" + }, + "import/resolver": { + typescript: {} // this loads /tsconfig.json to eslint + }, + }, + "env": { + "browser": true, + "es6": true + }, + "plugins": ["import", "react-hooks"] } - -export default config; diff --git a/pkg/interface/webterm/package-lock.json b/pkg/interface/webterm/package-lock.json index 2e42a0ff018e73a5cc473e825008d4b7061dc56e..902930d988df8539a038394474507620face3d54 100644 GIT binary patch delta 7666 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 H9_PORH@`58 delta 5033 zcmdUyX^b1?8OP-vd+qi5&SrD%Cc8OSDVx}1dwh|!iO09c_xdg*@%mV=?_P>G{0pn{s+stGhzptBB12$kATr0EC0 z8olpp`I+bV|9^hwu;i&IPdLNhd zi(k`*^Q=1_1ftAVLFKNlZdh@@U^)D>%w83mNT!QQqJW2VNka`E4OI0Cwa-V?2~|E< zOvkWg z-3dE+JsaTYmagS6aERLr!>5FD_;H!v2M2#CmBNV^xO?bhv92c&cua>3Kxi8Wn~#kH zuTBfZoMNJ)SP#m(yA~qMBgj{Y*9L2bI64(8x2pCjE!t@K$0L?h)L|h_O}iCsw-S*| zscfiDMbjR8BhxOZ@p!d8QM65s>#ef+@b;3QCs>HMT-PNCMfT1hW z6>xSRR|K=qb2W%^A;mD9*F z=Gp%p@#;|Cn05rQWS-KbJuVLwBC>@dN#&J_U?AS`mt)CfNgMQ{$+2)Mqs&j?Xiztr zicw+0;EuR;g;9k@9Z~u9Zk0*C*J2w;Ihya-{+5AXN!Fxd1V!i9I4wt%@l(IPgp zuL0wutkoeOmNO8_l)Y??w#*(Msxgw2t)$b^a0InkQg6-1h2t`Sq?jO+*+ikx`B6-c?)LN5uyYRKgZwi@wM5+s0qd-q&Z_OK zI=F8RxucV8mI5SCGOx6Akf((inP>#wo8kAv8JTDsEN8RjF#EJ{Dfm?UbuhG%Jp%hb zLApC%q}_Vs#9QIIe~j=(z3oC;pD?Ja(QI;R zG-`~-_2Z7JDy5yoEZJ15q_s52QB)CX5_x$4C}$YZ-*gYc#!H9{(y#Hv@Y3_rLD;d4 zmxEa@yL)=?6@=bD zH#ImM(8$&XEslDTRD0EhTs@?%mq~>avnZ#`fmR0h)UvsDM&TuLg?6erVVNxYsi{)I zjYS%|&?uGmdYtaIrKF4mEGVH*Whd3CurV47s(>{nS`6r~kkzpHA~Pb`i?Tj=_vZpJ zJdPnM@VK9alF?Q(*#Jk!i*3m0Ybr*~8w6CTg^5bG3lg=JwfB8EP^W zKneaIL9b5uB;dBv0&0w2}CU3g1t1AjM$5Ktmd_a+I6BiRvPNLXtFi^KEiJ{FFwTF>T0_4nH`{YvR!?qy^#>|DZ3 z>H}{vGcmhI(hYmLJ-s8>tbnO!ow1qHguGHKlV!49Nz1RDt;e8B2uFf(O*|3xqV+}{ zb*ow_g%)qCtCciSaS(s=Dm9_-lE+DUY?hW=%>HP2*l~&Q>di<8g)2jw{Dd z(}WH4XlhEE!K1cxIOIApA$rEXhfWCpFx-0&g1rg@zbEqw8?>?g48Bd&0|oa|vfe7cce`wVJ0Arx_8XP=1kzlFV%Pw=&{=_0b|{}lH6Kypwx0Ka=mD22m!OPn-A za6K&g@^aAt3pRfu5yC5%5FYG!PRg42nq_ea<3zgnwI-+qRXxD>~EkHFEp=v#dq*-9E{I)-8cHFrHv0dY;;7hT7(= zw+*n}@DY}N_Z)9A?BGjpS3;W?ZxAn(+HNMas}s=)oW3BD3T`Ewb%gplU0h8eU0x{t zo97#B7W!7$3?6gHR(%uA7SqSm(pP?e`=i-aM7W;4|H@|T=*jQNb`jG@9+uHZ9$qlp F^DpHKxuF06 diff --git a/pkg/interface/webterm/package.json b/pkg/interface/webterm/package.json index e859b4825..856b29eed 100644 --- a/pkg/interface/webterm/package.json +++ b/pkg/interface/webterm/package.json @@ -36,7 +36,7 @@ "@types/styled-system": "^5.1.10", "@typescript-eslint/eslint-plugin": "^4.15.0", "@typescript-eslint/parser": "^4.24.0", - "@urbit/eslint-config": "^1.0.0", + "@urbit/eslint-config": "^1.0.3", "@welldone-software/why-did-you-render": "^6.1.0", "babel-eslint": "^10.1.0", "babel-jest": "^26.6.3", @@ -45,7 +45,9 @@ "clean-webpack-plugin": "^3.0.0", "cross-env": "^7.0.3", "eslint": "^7.26.0", - "eslint-plugin-react": "^7.22.0", + "eslint-import-resolver-typescript": "^2.5.0", + "eslint-plugin-import": "^2.25.4", + "eslint-plugin-react-hooks": "^4.3.0", "file-loader": "^6.2.0", "html-webpack-plugin": "^4.5.1", "husky": "^6.0.0", @@ -58,7 +60,8 @@ "webpack-dev-server": "^3.11.2" }, "scripts": { - "lint": "eslint ./src/**/*.{ts,tsx}", + "lint": "eslint ./**/*.{ts,tsx}", + "lint-fix": "eslint --fix ./**/*.{ts,tsx}", "lint-file": "eslint", "tsc": "tsc", "tsc:watch": "tsc --watch", From e7e5c6340977abf15831f07831ac24e1ad69edd3 Mon Sep 17 00:00:00 2001 From: tomholford Date: Wed, 9 Mar 2022 16:15:24 -0600 Subject: [PATCH 028/715] ux: support `agent!session-name` syntax When adding a session, using this special syntax will create a new session for the indicated agent. E.g., `book!my-session` opens a new session for the %book agent. --- pkg/interface/webterm/Tabs.tsx | 21 ++------ pkg/interface/webterm/constants.ts | 15 ++++++ pkg/interface/webterm/lib/useAddSession.ts | 59 ++++++++++++++++++++++ 3 files changed, 77 insertions(+), 18 deletions(-) create mode 100644 pkg/interface/webterm/lib/useAddSession.ts diff --git a/pkg/interface/webterm/Tabs.tsx b/pkg/interface/webterm/Tabs.tsx index e98c38d3f..09751537a 100644 --- a/pkg/interface/webterm/Tabs.tsx +++ b/pkg/interface/webterm/Tabs.tsx @@ -1,26 +1,11 @@ -import { pokeTask } from '@urbit/api/term'; -import api from './api'; import React from 'react'; import useTermState from './state'; import { Tab } from './Tab'; -import { SESSION_ID_REGEX } from './constants'; +import { useAddSession } from './lib/useAddSession'; export const Tabs = () => { const { sessions, names } = useTermState(); - - const onAddClick = () => { - const name = prompt('please entew a session name uwu'); - if (!name || !SESSION_ID_REGEX.test(name) || names.includes(name)) { - console.log('invalid session name:', name); - return; - } - api.poke(pokeTask(name, { open: { term: 'hood', apps: [{ who: '~' + (window as any).ship, app: 'dojo' }] } })); - useTermState.getState().set(state => { - state.names = [name, ...state.names].sort(); - state.selected = name; - state.sessions[name] = null; - }); - } + const { addSession } = useAddSession(); return (
@@ -29,7 +14,7 @@ export const Tabs = () => { ); })} - +
); }; diff --git a/pkg/interface/webterm/constants.ts b/pkg/interface/webterm/constants.ts index 7e173ac64..cd80b9aa2 100644 --- a/pkg/interface/webterm/constants.ts +++ b/pkg/interface/webterm/constants.ts @@ -9,3 +9,18 @@ export const DEFAULT_SESSION = ''; * - cannot begin or end with a hyphen */ export const SESSION_ID_REGEX = /(^[a-z]{1}[a-z\d\-]*[a-z\d]{1}$)|(^[a-z]{1}$)/; + +/** + * Open a session with a given agent using `[agent]![session_name] + * + * For example: + * ``` + * book!my-session + * ``` + * + * This will create a new session in webterm for the `%book` agent. + * + * Note that the second capture group after the ! is composed of the session ID + * regex above. + */ +export const AGENT_SESSION_REGEX = /^([a-z]{4})\!(([a-z]{1}[a-z\d\-]*[a-z\d]{1}$)|(^[a-z]{1}))/; diff --git a/pkg/interface/webterm/lib/useAddSession.ts b/pkg/interface/webterm/lib/useAddSession.ts new file mode 100644 index 000000000..5f06d5c8d --- /dev/null +++ b/pkg/interface/webterm/lib/useAddSession.ts @@ -0,0 +1,59 @@ +import { AGENT_SESSION_REGEX, SESSION_ID_REGEX } from '../constants'; +import useTermState from '../state'; +import api from '../api'; +import { pokeTask } from '@urbit/api/term'; +import { useCallback } from 'react'; + +export const useAddSession = () => { + const { names } = useTermState(); + + const addSession = useCallback(async () => { + let agent = 'hood'; // default agent + let sessionName: string; + + const userInput = prompt('please entew a session name uwu'); + // user canceled or did not enter a value + if (!userInput) { + return; + } + + // check for custom agent session syntax + if (AGENT_SESSION_REGEX.test(userInput)) { + const match = AGENT_SESSION_REGEX.exec(userInput); + if (!match) { + return; + } + agent = match[1]; + sessionName = match[2]; + // else, use the default session creation regex + } else if (SESSION_ID_REGEX.test(userInput)) { + const match = SESSION_ID_REGEX.exec(userInput); + if (!match) { + return; + } + sessionName = match[1]; + } else { + return; + } + + // avoid nil or duplicate sessions + if(!sessionName || names.includes(sessionName)) { + return; + } + + try { + await api.poke(pokeTask(sessionName, { open: { term: agent, apps: [{ who: '~' + (window as any).ship, app: 'dojo' }] } })); + useTermState.getState().set((state) => { + state.names = [sessionName, ...state.names].sort(); + state.selected = sessionName; + state.sessions[sessionName] = null; + }); + } catch (error) { + console.log('unable to create session:', error); + } + }, [names]); + + return { + addSession + }; +}; From ee492e6f8309cbba3d77dbd7fd258764f5d99679 Mon Sep 17 00:00:00 2001 From: tomholford Date: Wed, 9 Mar 2022 16:25:10 -0600 Subject: [PATCH 029/715] devex: cleaning up lint issues --- pkg/interface/webterm/App.tsx | 12 ++++-------- pkg/interface/webterm/Buffer.tsx | 19 +++++++++---------- pkg/interface/webterm/Tab.tsx | 6 ++---- pkg/interface/webterm/constants.ts | 14 +++++++------- pkg/interface/webterm/lib/useDark.ts | 2 +- pkg/interface/webterm/state.ts | 6 ++++-- 6 files changed, 27 insertions(+), 32 deletions(-) diff --git a/pkg/interface/webterm/App.tsx b/pkg/interface/webterm/App.tsx index 9ad1d6185..9ce3b0c00 100644 --- a/pkg/interface/webterm/App.tsx +++ b/pkg/interface/webterm/App.tsx @@ -20,11 +20,7 @@ import Buffer from './Buffer'; import { DEFAULT_SESSION } from './constants'; import { showSlog } from './lib/blit'; -type TermAppProps = { - ship: string; -} - -export default function TermApp(props: TermAppProps) { +export default function TermApp() { const { names, selected } = useTermState(); const dark = useDark(); @@ -41,7 +37,7 @@ export default function TermApp(props: TermAppProps) { let available = false; const slog = new EventSource('/~_~/slog', { withCredentials: true }); - slog.onopen = (e) => { + slog.onopen = () => { console.log('slog: opened stream'); available = true; }; @@ -84,8 +80,8 @@ export default function TermApp(props: TermAppProps) {
- {names.map(name => { - return ; + {names.map((name) => { + return ; })}
diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx index dca9d8d71..063019ed2 100644 --- a/pkg/interface/webterm/Buffer.tsx +++ b/pkg/interface/webterm/Buffer.tsx @@ -62,7 +62,7 @@ const readInput = (term: Terminal, e: string): Belt[] => { } else if (13 === c) { belts.push({ ret: null }); } else if (c <= 26) { - let k = String.fromCharCode(96 + c); + const k = String.fromCharCode(96 + c); //NOTE prevent remote shut-downs if ('d' !== k) { belts.push({ mod: { mod: 'ctl', key: k } }); @@ -178,7 +178,7 @@ export default function Buffer({ name, selected, dark }: BufferProps) { event: (e) => { showBlit(ses.term, e); if (e.bel && !selected) { - useTermState.getState().set(state => { + useTermState.getState().set((state) => { state.sessions[name].hasBell = true; }); } @@ -189,7 +189,7 @@ export default function Buffer({ name, selected, dark }: BufferProps) { console.error('oops quit, pls handle'); } }); - + useTermState.getState().set((state) => { state.sessions[name] = ses; }); @@ -207,7 +207,7 @@ export default function Buffer({ name, selected, dark }: BufferProps) { // on selected change, maybe setup the term, or put it into the container // const setContainer = useCallback((containerRef: HTMLDivElement | null) => { - let newContainer = containerRef || container.current; + const newContainer = containerRef || container.current; if(session && newContainer) { container.current = newContainer; } @@ -216,7 +216,6 @@ export default function Buffer({ name, selected, dark }: BufferProps) { // on-init, open slogstream and fetch existing sessions // useEffect(() => { - window.addEventListener('resize', onResize(session)); return () => { @@ -239,10 +238,10 @@ export default function Buffer({ name, selected, dark }: BufferProps) { useEffect(() => { if (session && selected && !session.term.isOpen) { - session!.term.open(container.current); - session!.fit.fit(); - session!.term.focus(); - session!.term.isOpen = true; + session.term.open(container.current); + session.fit.fit(); + session.term.focus(); + session.term.isOpen = true; } }, [selected, session]); @@ -256,7 +255,7 @@ export default function Buffer({ name, selected, dark }: BufferProps) { bg='white' fontFamily='mono' overflow='hidden' - style={selected ? {} : {display: 'none'}} + style={selected ? {} : { display: 'none' }} > { - const isSelected = useTermState().selected === name; const onClick = () => { @@ -20,7 +18,7 @@ export const Tab = ( { session, name }: TabProps ) => { state.sessions[name].hasBell = false; }); useTermState.getState().sessions[name]?.term?.focus(); - } + }; const onDelete = useCallback(async (e) => { e.stopPropagation(); @@ -34,7 +32,7 @@ export const Tab = ( { session, name }: TabProps ) => { await api.poke(pokeTask(name, { shut: null })); // remove from zustand - useTermState.getState().set(state => { + useTermState.getState().set((state) => { if (state.selected === name) { state.selected = DEFAULT_SESSION; } diff --git a/pkg/interface/webterm/constants.ts b/pkg/interface/webterm/constants.ts index cd80b9aa2..61c11b13c 100644 --- a/pkg/interface/webterm/constants.ts +++ b/pkg/interface/webterm/constants.ts @@ -2,25 +2,25 @@ export const DEFAULT_SESSION = ''; /** * Session ID validity: - * + * * - must start with an alphabetical * - can be composed of alphanumerics with hyphens * - can be length 1 or longer * - cannot begin or end with a hyphen */ -export const SESSION_ID_REGEX = /(^[a-z]{1}[a-z\d\-]*[a-z\d]{1}$)|(^[a-z]{1}$)/; +export const SESSION_ID_REGEX = /(^[a-z]{1}[a-z\d-]*[a-z\d]{1}$)|(^[a-z]{1}$)/; /** * Open a session with a given agent using `[agent]![session_name] - * + * * For example: * ``` * book!my-session * ``` - * + * * This will create a new session in webterm for the `%book` agent. - * - * Note that the second capture group after the ! is composed of the session ID + * + * Note that the second capture group after the ! is composed of the session ID * regex above. */ -export const AGENT_SESSION_REGEX = /^([a-z]{4})\!(([a-z]{1}[a-z\d\-]*[a-z\d]{1}$)|(^[a-z]{1}))/; +export const AGENT_SESSION_REGEX = /^([a-z]{4})!(([a-z]{1}[a-z\d-]*[a-z\d]{1}$)|(^[a-z]{1}))/; diff --git a/pkg/interface/webterm/lib/useDark.ts b/pkg/interface/webterm/lib/useDark.ts index cd9625403..ddd9c10ae 100644 --- a/pkg/interface/webterm/lib/useDark.ts +++ b/pkg/interface/webterm/lib/useDark.ts @@ -14,7 +14,7 @@ export function useDark() { return () => { themeWatcher.removeEventListener('change', update); - } + }; }, []); const theme = useTermState(s => s.theme); diff --git a/pkg/interface/webterm/state.ts b/pkg/interface/webterm/state.ts index b6ca56633..e481e36e5 100644 --- a/pkg/interface/webterm/state.ts +++ b/pkg/interface/webterm/state.ts @@ -3,8 +3,8 @@ import { FitAddon } from 'xterm-addon-fit'; import create from 'zustand'; import produce from 'immer'; -export type Session = { - term: Terminal, +export type Session = { + term: Terminal, fit: FitAddon, hasBell: boolean, subscriptionId: number | null, @@ -21,12 +21,14 @@ export interface TermState { set: any, } +// eslint-disable-next-line no-unused-vars const useTermState = create((set, get) => ({ sessions: {} as Sessions, names: [''], selected: '', // empty string is default session slogstream: null, theme: 'auto', + // eslint-disable-next-line no-unused-vars set: (f: (draft: TermState) => void) => { set(produce(f)); } From 200b504c4e19ac76eada25fa48844d0dc2b9ce9c Mon Sep 17 00:00:00 2001 From: tomholford Date: Thu, 10 Mar 2022 00:03:27 -0600 Subject: [PATCH 030/715] api: resubscribe after clog --- pkg/interface/webterm/Buffer.tsx | 37 +++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx index 063019ed2..eecadb9f1 100644 --- a/pkg/interface/webterm/Buffer.tsx +++ b/pkg/interface/webterm/Buffer.tsx @@ -174,21 +174,34 @@ export default function Buffer({ name, selected, dark }: BufferProps) { // open subscription // - ses.subscriptionId = await api.subscribe({ app: 'herm', path: '/session/'+name+'/view', - event: (e) => { - showBlit(ses.term, e); - if (e.bel && !selected) { + const initSubscription = async () => { + const subscriptionId = await api.subscribe({ + app: 'herm', path: '/session/' + name + '/view', + event: (e) => { + showBlit(ses.term, e); + if (e.bel && !selected) { + useTermState.getState().set((state) => { + state.sessions[name].hasBell = true; + }); + } + //TODO should handle %bye on this higher level though, for deletion + }, + err: (e, id) => { + console.log(`subscription error, id ${id}:`, e); + }, + quit: async () => { // quit + console.error('oops quit, reconnecting...'); + const newSubscriptionId = await initSubscription(); useTermState.getState().set((state) => { - state.sessions[name].hasBell = true; + state.sessions[name].subscriptionId = newSubscriptionId; }); } - //TODO should handle %bye on this higher level though, for deletion - }, - quit: () => { // quit - // TODO show user a message - console.error('oops quit, pls handle'); - } - }); + }); + + return subscriptionId; + }; + + ses.subscriptionId = await initSubscription(); useTermState.getState().set((state) => { state.sessions[name] = ses; From bf0f4e97c999256d1fcd2deaa12e452265a8bd93 Mon Sep 17 00:00:00 2001 From: tomholford Date: Thu, 10 Mar 2022 22:54:30 -0600 Subject: [PATCH 031/715] api: exponential backoff when resubscribing Use the new `lib/retry` to attempt to reconnect when clogged. If unsucessful after 5 attempts, stop retrying and log an error. --- pkg/interface/webterm/Buffer.tsx | 15 +++++++++--- pkg/interface/webterm/constants.ts | 2 +- pkg/interface/webterm/lib/retry.ts | 39 ++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 pkg/interface/webterm/lib/retry.ts diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx index eecadb9f1..f24d08bd4 100644 --- a/pkg/interface/webterm/Buffer.tsx +++ b/pkg/interface/webterm/Buffer.tsx @@ -14,6 +14,7 @@ import { Box, Col } from '@tlon/indigo-react'; import { makeTheme } from './lib/theme'; import { showBlit, csi } from './lib/blit'; import { DEFAULT_SESSION } from './constants'; +import { retry } from './lib/retry'; const termConfig: ITerminalOptions = { logLevel: 'warn', @@ -191,10 +192,16 @@ export default function Buffer({ name, selected, dark }: BufferProps) { }, quit: async () => { // quit console.error('oops quit, reconnecting...'); - const newSubscriptionId = await initSubscription(); - useTermState.getState().set((state) => { - state.sessions[name].subscriptionId = newSubscriptionId; - }); + try { + const newSubscriptionId = await retry(initSubscription, () => { + console.log('attempting to reconnect ...'); + }, 5); + useTermState.getState().set((state) => { + state.sessions[name].subscriptionId = newSubscriptionId; + }); + } catch (error) { + console.log('unable to reconnect', error); + } } }); diff --git a/pkg/interface/webterm/constants.ts b/pkg/interface/webterm/constants.ts index 61c11b13c..a96349bc1 100644 --- a/pkg/interface/webterm/constants.ts +++ b/pkg/interface/webterm/constants.ts @@ -11,7 +11,7 @@ export const DEFAULT_SESSION = ''; export const SESSION_ID_REGEX = /(^[a-z]{1}[a-z\d-]*[a-z\d]{1}$)|(^[a-z]{1}$)/; /** - * Open a session with a given agent using `[agent]![session_name] + * Open a session with a given agent using `[agent]![session_name]` * * For example: * ``` diff --git a/pkg/interface/webterm/lib/retry.ts b/pkg/interface/webterm/lib/retry.ts new file mode 100644 index 000000000..dea78b0b2 --- /dev/null +++ b/pkg/interface/webterm/lib/retry.ts @@ -0,0 +1,39 @@ +/** + * Wait for the given milliseconds + * @param {number} milliseconds The given time to wait + * @returns {Promise} A fulfiled promise after the given time has passed + */ + function waitFor(milliseconds) { + return new Promise(resolve => setTimeout(resolve, milliseconds)); +} + +/** + * Execute a promise and retry with exponential backoff + * based on the maximum retry attempts it can perform + * @param {Promise} promise promise to be executed + * @param {function} onRetry callback executed on every retry + * @param {number} maxRetries The maximum number of retries to be attempted + * @returns {Promise} The result of the given promise passed in + */ +export function retry(promise, onRetry, maxRetries) { + async function retryWithBackoff(retries) { + try { + if (retries > 0) { + const timeToWait = 2 ** retries * 100; + console.log(`waiting for ${timeToWait}ms...`); + await waitFor(timeToWait); + } + return await promise(); + } catch (e) { + if (retries < maxRetries) { + onRetry(); + return retryWithBackoff(retries + 1); + } else { + console.warn('Max retries reached. Bubbling the error up'); + throw e; + } + } + } + + return retryWithBackoff(0); +} From cdaf23a184c8aa538974a38e3bd0ce76e659e959 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Fri, 25 Feb 2022 15:51:22 -0500 Subject: [PATCH 032/715] hoon: prefix and postfix doccords for ++ and +$ there's a stub for +* but its not working yet --- pkg/arvo/sys/hoon.hoon | 80 ++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index 566010fbe..edc9572b3 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -13226,45 +13226,65 @@ :: ++ boog !: :: core arms %+ knee [p=*term q=*hoon] |. ~+ + %+ cook + |= [a=whit b=term c=whit d=hoon] + =+ e=(glom a c) + ?~ boy.e + [b d] + [b [%note [%help ~ [p.u.boy.e q.u.boy.e]] d]] ;~ pose - ;~ pfix (jest '++') - ;~ plug - ;~(pfix gap ;~(pose (cold %$ buc) sym)) - ;~(pfix gap loaf) + ;~ plug + apex:docs + ;~ pfix (jest '++') + ;~ plug + ;~(pfix gap ;~(pose (cold %$ buc) sym)) + apse:docs + ;~(pfix gap loaf) + == == == :: %+ cook - |= [b=term d=spec] - [b [%ktcl [%name b d]]] - ;~ pfix (jest '+$') - ;~ plug - ;~(pfix gap sym) - ;~(pfix gap loan) + |= [a=whit b=term c=whit d=spec] + [a b c [%ktcl [%name b d]]] + ;~ plug + apex:docs + ;~ pfix (jest '+$') + ;~ plug + ;~(pfix gap sym) + apse:docs + ;~(pfix gap loan) + == == == :: %+ cook - |= [b=term c=(list term) e=spec] - ^- [term hoon] - :- b - :+ %brtr - :- %bccl - =- ?>(?=(^ -) -) - :: for each .term in .c, produce $=(term $~(* $-(* *))) - :: ie {term}=mold - :: - %+ turn c - |= =term - ^- spec - =/ tar [%base %noun] - [%bcts term [%bcsg tar [%bchp tar tar]]] - [%ktcl [%made [b c] e]] - ;~ pfix (jest '+*') - ;~ plug - ;~(pfix gap sym) - ;~(pfix gap (ifix [sel ser] (most ace sym))) - ;~(pfix gap loan) + |= [a=whit b=term d=hoon] + [a b *whit d] + ;~ plug + apex:docs :: this doesn't work, not sure why yet + %+ cook + |= [b=term c=(list term) e=spec] + ^- [term hoon] + :- b + :+ %brtr + :- %bccl + =- ?>(?=(^ -) -) + :: for each .term in .c, produce $=(term $~(* $-(* *))) + :: ie {term}=mold + :: + %+ turn c + |= =term + ^- spec + =/ tar [%base %noun] + [%bcts term [%bcsg tar [%bchp tar tar]]] + [%ktcl [%made [b c] e]] + ;~ pfix (jest '+*') + ;~ plug + ;~(pfix gap sym) + ;~(pfix gap (ifix [sel ser] (most ace sym))) + ;~(pfix gap loan) + == == == == From 336817d5bc318204fb86640cf551ae2a9ac63e3c Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Fri, 25 Feb 2022 15:52:23 -0500 Subject: [PATCH 033/715] hoon: doccords for core chapters this populates the $what in $tome --- pkg/arvo/sys/hoon.hoon | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index edc9572b3..d6f8f31ca 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -13336,31 +13336,32 @@ ++ wisp !: :: core tail ?. tol fail %+ cook - |= a=(list (pair term (map term hoon))) + |= a=(list [wit=whit wap=(pair term (map term hoon))]) ^- (map term tome) =< p |- ^- (pair (map term tome) (map term hoon)) ?~ a [~ ~] =/ mor $(a t.a) - =. q.i.a - %- ~(urn by q.i.a) + =. q.wap.i.a + %- ~(urn by q.wap.i.a) |= b=(pair term hoon) ^+ +.b + :: tests for duplicate arms between two chapters ?. (~(has by q.mor) p.b) +.b [%eror (weld "duplicate arm: +" (trip p.b))] - :_ (~(uni by q.mor) q.i.a) + :_ (~(uni by q.mor) q.wap.i.a) %+ ~(put by p.mor) - p.i.a - :- *what - ?. (~(has by p.mor) p.i.a) - q.i.a - [[%$ [%eror (weld "duplicate chapter: |" (trip p.i.a))]] ~ ~] + p.wap.i.a + :- boy.wit.i.a :: body of the whit set as the what + ?. (~(has by p.mor) p.wap.i.a) + q.wap.i.a + [[%$ [%eror (weld "duplicate chapter: |" (trip p.wap.i.a))]] ~ ~] :: ;~ pose dun ;~ sfix ;~ pose - (most muck ;~(pfix (jest '+|') ;~(pfix gap whip))) - ;~(plug (stag %$ whap) (easy ~)) + (most muck ;~(plug apex:docs ;~(pfix (jest '+|') ;~(pfix gap whip)))) + ;~(plug (stag *whit (stag %$ whap)) (easy ~)) == gap dun From 0a3ec9a92d1d5cffe243006c3b0e2c3877d1739f Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Tue, 1 Mar 2022 16:35:47 -0500 Subject: [PATCH 034/715] hoon: doccords cleanup %note tag for +boog --- pkg/arvo/sys/hoon.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index d6f8f31ca..fd6c0fe30 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -13231,7 +13231,7 @@ =+ e=(glom a c) ?~ boy.e [b d] - [b [%note [%help ~ [p.u.boy.e q.u.boy.e]] d]] + [b [%note help+`[u.boy.e] d]] ;~ pose ;~ plug apex:docs From 41a796d2d1465d934edd9cb7305a274bb813b72f Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 10 Mar 2022 01:40:02 +0100 Subject: [PATCH 035/715] hoon: hook up $+ for shorthand type rendering Too often when dealing with big types the compiler traces and other such outputs become hard to read. Wrapping a type as $+(shorthand big-type) will now print #shorthand in place of the type. --- pkg/arvo/app/dojo.hoon | 4 +++- pkg/arvo/sys/hoon.hoon | 21 +++++++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/pkg/arvo/app/dojo.hoon b/pkg/arvo/app/dojo.hoon index 938d9f25a..b127a3ce0 100644 --- a/pkg/arvo/app/dojo.hoon +++ b/pkg/arvo/app/dojo.hoon @@ -679,7 +679,9 @@ [%face ^] a(q $(a q.a)) [%cell ^] a(p $(a p.a), q $(a q.a)) [%fork *] a(p (silt (turn ~(tap in p.a) |=(b=type ^$(a b))))) - [%hint *] !! + [%hint *] ?. ?=(%know -.q.p.a) $(a q.a) + ?@ p.q.p.a [(cat 3 '#' mark.p.q.p.a)]~ + [(rap 3 '#' auth.p.q.p.a (spat type.p.q.p.a) ~)]~ [%core ^] `wain`/core [%hold *] a(p $(a p.a)) == diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index fd6c0fe30..ec4a6fa26 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -7781,7 +7781,7 @@ [%bcgl *] $(mod q.mod) [%bcgr *] $(mod q.mod) [%bckt *] $(mod q.mod) - [%bcls *] $(mod q.mod) + [%bcls *] [%note [%know p.mod] $(mod q.mod)] [%bcmc *] :: borrow sample :: [%tsgl [%$ 6] p.mod] @@ -7832,7 +7832,7 @@ [%bchp *] (decorate (function:clear p.mod q.mod)) [%bcmc *] (decorate (home [%tsgl [%limb %$] p.mod])) [%bcsg *] [%ktls example(mod q.mod) (home p.mod)] - [%bcls *] (decorate example(mod q.mod)) + [%bcls *] (decorate [%note [%know p.mod] example(mod q.mod)]) [%bcts *] (decorate [%ktts p.mod example:clear(mod q.mod)]) [%bcdt *] (decorate (home (interface %gold p.mod q.mod))) [%bcfs *] (decorate (home (interface %iron p.mod q.mod))) @@ -8189,7 +8189,7 @@ relative:clear(mod q.mod) relative:clear(mod p.mod) :: - [%bcls *] relative(mod q.mod) + [%bcls *] [%note [%know p.mod] relative(mod q.mod)] [%bcdt *] (decorate (home (interface %gold p.mod q.mod))) [%bcfs *] (decorate (home (interface %iron p.mod q.mod))) [%bczp *] (decorate (home (interface %lead p.mod q.mod))) @@ -10914,6 +10914,7 @@ [%stop p=@ud] :: [%tree p=term q=wine] :: [%unit p=term q=wine] :: + [%name p=stud q=wine] :: == :: -- |_ sut=type @@ -11004,6 +11005,11 @@ [%unit *] =^ cox gid $(q.ham q.q.ham) :_(gid [%rose [" " (weld (trip p.q.ham) "(") ")"] cox ~]) + :: + [%name *] + :_ gid + ?@ p.q.ham (cat 3 '#' mark.p.q.ham) + (rap 3 '#' auth.p.q.ham (spat type.p.q.ham) ~) == -- :: @@ -11191,6 +11197,9 @@ ?~ wal ~ [~ %rose [[' ' ~] ['[' ~] [']' ~]] [%leaf '~' ~] u.wal ~] + :: + [%name *] + $(q.ham q.q.ham) == :: ++ doge @@ -11295,7 +11304,9 @@ == :: [%hint *] - $(sut q.sut) + =+ yad=$(sut q.sut) + ?. ?=(%know -.q.p.sut) yad + [p.yad [%name p.q.p.sut q.yad]] :: [%face *] =+ yad=$(sut q.sut) @@ -13010,6 +13021,7 @@ ['=' (rune tis %bcts exqg)] ['?' (rune wut %bcwt exqs)] [';' (rune mic %bcmc expa)] + ['+' (rune lus %bcls exqg)] == == :- '%' @@ -13080,6 +13092,7 @@ ['-' (stag %ktcl (rune hep %bchp exqb))] ['=' (stag %ktcl (rune tis %bcts exqg))] ['?' (stag %ktcl (rune wut %bcwt exqs))] + ['+' (stag %ktcl (rune lus %bcls exqg))] ['.' (rune dot %kttr exqa)] [',' (rune com %ktcl exqa)] == From f08b613416f9da8529ca4188b16a2e67bc332f08 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Mon, 14 Mar 2022 17:00:04 -0400 Subject: [PATCH 036/715] hoon: populate label for %brcn doccords This changes the parser for +tall so that it looks before and after a hoon for doccords, and then extracts a label for %brcn if it exists. +wrap will be used to annotating most hoons, but this commit only covers %brcn --- pkg/arvo/sys/hoon.hoon | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index ec4a6fa26..6e6bacc7e 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -8207,6 +8207,21 @@ == |_ gen=hoon :: + :: This door takes in a whit and annotates gen as appropriate + ++ docs-engine + |_ wit=whit + :: + ++ apply-whit + ^- hoon + ?: =([~ ~ ~ ~] wit) + gen + ?+ gen gen + :: + [%brcn *] + [%brcn lab.wit q.gen] + == + -- + :: ++ grip |= =skin =| rel=wing @@ -13673,9 +13688,26 @@ [%spec spec %base %noun] wyde == + :: + :: +wrap is for tagging arbitrary hoons. This is where most of the doccords + :: logic lives - the modifications to +boog and +wisp are for tagging arms + :: and chapter labels, while +wrap handles hoons inside of arms and cores. + ++ wrap + |* fel=rule + %+ cook + |= [a=whit b=hoon c=whit] + ^- hoon + ~(apply-whit ~(docs-engine ap b) (glom a c)) + :: + ;~ plug + apex:docs + fel + apse:docs + == + :: ++ tall :: full tall form %+ knee *hoon - |.(~+((wart ;~(pose expression:(norm &) long lute apex:(sail &))))) + |.(~+((wart (wrap ;~(pose expression:(norm &) long lute apex:(sail &)))))) ++ till :: mold tall form %+ knee *spec |.(~+((wert ;~(pose structure:(norm &) scad)))) From 0dc3498a6f2b0bbc63b367031720e56a5221d76d Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Mon, 14 Mar 2022 17:08:49 -0400 Subject: [PATCH 037/715] hoon: change %brdt AST to support doccords label --- pkg/arvo/sys/hoon.hoon | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index 6e6bacc7e..81bef0a17 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -6440,7 +6440,7 @@ [%brcb p=spec q=alas r=(map term tome)] :: |_ [%brcl p=hoon q=hoon] :: |: [%brcn p=(unit term) q=(map term tome)] :: |% - [%brdt p=hoon] :: |. + [%brdt p=(unit term) q=hoon] :: |. [%brkt p=hoon q=(map term tome)] :: |^ [%brhp p=hoon] :: |- [%brsg p=spec q=hoon] :: |~ @@ -8213,12 +8213,16 @@ :: ++ apply-whit ^- hoon + :: if wit is empty, just return the hoon ?: =([~ ~ ~ ~] wit) gen ?+ gen gen :: [%brcn *] - [%brcn lab.wit q.gen] + [%brcn lab.wit q.gen] :: populate (unit term) with lab.wit + :: + [%brdt *] + [%brdt lab.wit q.gen] == -- :: @@ -8439,10 +8443,10 @@ |= =hoon ?~ q.gen hoon [%tstr [p.i.q.gen ~] q.i.q.gen $(q.gen t.q.gen)] - [%brcl *] [%tsls p.gen [%brdt q.gen]] - [%brdt *] :+ %brcn ~ + [%brcl *] [%tsls p.gen [%brdt ~ q.gen]] ::TODO ~ added when modifying %brdt, change to be appropriate docs + [%brdt *] :+ %brcn p.gen :: (docs) ~ changed to p.gen. builds a |% with an arm named $ =- [[%$ ~ -] ~ ~] - (~(put by *(map term hoon)) %$ p.gen) + (~(put by *(map term hoon)) %$ q.gen) [%brkt *] :+ %tsgl [%limb %$] :+ %brcn ~ =+ zil=(~(get by q.gen) %$) @@ -8451,7 +8455,7 @@ [*what [[%$ p.gen] ~ ~]] %+ ~(put by q.gen) %$ [p.u.zil (~(put by q.u.zil) %$ p.gen)] - [%brhp *] [%tsgl [%limb %$] [%brdt p.gen]] + [%brhp *] [%tsgl [%limb %$] [%brdt ~ p.gen]] :: TODO ~ added when modifying %brdt. change to appropriate docs [%brsg *] [%ktbr [%brts p.gen q.gen]] [%brtr *] :+ %tsls [%kttr p.gen] :+ %brpt ~ @@ -8460,7 +8464,7 @@ [%brts *] :+ %brcb p.gen =- [~ [[%$ ~ -] ~ ~]] (~(put by *(map term hoon)) %$ q.gen) - [%brwt *] [%ktwt %brdt p.gen] + [%brwt *] [%ktwt %brdt ~ p.gen] :: TODO ~ added when modifying %brdt. change to appropriate docs :: [%clkt *] [p.gen q.gen r.gen s.gen] [%clls *] [p.gen q.gen r.gen] @@ -8521,10 +8525,10 @@ :- %mean =+ fek=~(feck ap p.gen) ?^ fek [%rock %tas u.fek] - [%brdt [%cncl [%limb %cain] [%zpgr [%tsgr [%$ 3] p.gen]] ~]] + [%brdt ~ [%cncl [%limb %cain] [%zpgr [%tsgr [%$ 3] p.gen]] ~]] :: (doccords) added ~ for %brdt q.gen :: - [%sgcb *] [%sggr [%mean [%brdt p.gen]] q.gen] + [%sgcb *] [%sggr [%mean [%brdt ~ p.gen]] q.gen] :: (doccords) added ~ for %brdt [%sgcn *] :+ %sggl :- %fast @@ -8622,7 +8626,7 @@ :+ %tsgl :: [%wing [%| 0 ~] [%& 6] ~] :: [%limb %b] :: - :- %brdt :: |. + :+ %brdt ~ :: |. (doccords) added ~ for %brdt :^ %cnls :: %+ [%tsgr [%limb %v] p.gen] :: =>(v {p.gen}) [%cncl [%limb %b] [%limb %c] ~] :: (b c) @@ -13080,7 +13084,7 @@ ['%' (runo cen %brcn ~ expe)] ['@' (runo pat %brpt ~ expe)] [':' (rune col %brcl expb)] - ['.' (rune dot %brdt expa)] + ['.' (runo dot %brdt ~ expa)] ['-' (rune hep %brhp expa)] ['^' (rune ket %brkt expx)] ['~' (rune sig %brsg exqc)] From 643700546f2d1ecf00bd33e5b3c726b18a51c980 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Mon, 14 Mar 2022 17:09:41 -0400 Subject: [PATCH 038/715] hoon: populate %brpt doccords label --- pkg/arvo/sys/hoon.hoon | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index 81bef0a17..8307566eb 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -8220,6 +8220,9 @@ :: [%brcn *] [%brcn lab.wit q.gen] :: populate (unit term) with lab.wit + :: + [%brpt *] + [%brpt lab.wit q.gen] :: populate (unit term) with lab.wit :: [%brdt *] [%brdt lab.wit q.gen] From 586c2da857b7ce56e55c73bcd235cfa8c0e69427 Mon Sep 17 00:00:00 2001 From: fang Date: Tue, 15 Mar 2022 01:24:16 +0100 Subject: [PATCH 039/715] webterm: improve session creation regexes Trailing dashes are, in fact, allowed. As are numerics in the agent name. --- pkg/interface/webterm/constants.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/interface/webterm/constants.ts b/pkg/interface/webterm/constants.ts index a96349bc1..deaf08db6 100644 --- a/pkg/interface/webterm/constants.ts +++ b/pkg/interface/webterm/constants.ts @@ -6,9 +6,8 @@ export const DEFAULT_SESSION = ''; * - must start with an alphabetical * - can be composed of alphanumerics with hyphens * - can be length 1 or longer - * - cannot begin or end with a hyphen */ -export const SESSION_ID_REGEX = /(^[a-z]{1}[a-z\d-]*[a-z\d]{1}$)|(^[a-z]{1}$)/; +export const SESSION_ID_REGEX = /(^[a-z]{1}[a-z\d-]*$)/; /** * Open a session with a given agent using `[agent]![session_name]` @@ -23,4 +22,4 @@ export const SESSION_ID_REGEX = /(^[a-z]{1}[a-z\d-]*[a-z\d]{1}$)|(^[a-z]{1}$)/; * Note that the second capture group after the ! is composed of the session ID * regex above. */ -export const AGENT_SESSION_REGEX = /^([a-z]{4})!(([a-z]{1}[a-z\d-]*[a-z\d]{1}$)|(^[a-z]{1}))/; +export const AGENT_SESSION_REGEX = /^([a-z]{1}[a-z\d-]*)!([a-z]{1}[a-z\d-]*$)/; From 0d2c135959e1c634f8c69c4a45390005c0fb8d89 Mon Sep 17 00:00:00 2001 From: fang Date: Tue, 15 Mar 2022 01:34:19 +0100 Subject: [PATCH 040/715] webterm: small cleanup, comments Also includes a more-sane prompt() description. --- pkg/interface/webterm/Buffer.tsx | 2 +- pkg/interface/webterm/constants.ts | 1 + pkg/interface/webterm/lib/useAddSession.ts | 11 ++++++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx index f24d08bd4..067fd0cf9 100644 --- a/pkg/interface/webterm/Buffer.tsx +++ b/pkg/interface/webterm/Buffer.tsx @@ -191,7 +191,7 @@ export default function Buffer({ name, selected, dark }: BufferProps) { console.log(`subscription error, id ${id}:`, e); }, quit: async () => { // quit - console.error('oops quit, reconnecting...'); + console.error('quit, reconnecting...'); try { const newSubscriptionId = await retry(initSubscription, () => { console.log('attempting to reconnect ...'); diff --git a/pkg/interface/webterm/constants.ts b/pkg/interface/webterm/constants.ts index deaf08db6..66d4b0ecc 100644 --- a/pkg/interface/webterm/constants.ts +++ b/pkg/interface/webterm/constants.ts @@ -1,4 +1,5 @@ export const DEFAULT_SESSION = ''; +export const DEFAULT_HANDLER = 'hood'; /** * Session ID validity: diff --git a/pkg/interface/webterm/lib/useAddSession.ts b/pkg/interface/webterm/lib/useAddSession.ts index 5f06d5c8d..f25c13b2b 100644 --- a/pkg/interface/webterm/lib/useAddSession.ts +++ b/pkg/interface/webterm/lib/useAddSession.ts @@ -1,4 +1,8 @@ -import { AGENT_SESSION_REGEX, SESSION_ID_REGEX } from '../constants'; +import { + DEFAULT_HANDLER, + AGENT_SESSION_REGEX, + SESSION_ID_REGEX +} from '../constants'; import useTermState from '../state'; import api from '../api'; import { pokeTask } from '@urbit/api/term'; @@ -8,10 +12,10 @@ export const useAddSession = () => { const { names } = useTermState(); const addSession = useCallback(async () => { - let agent = 'hood'; // default agent + let agent = DEFAULT_HANDLER; let sessionName: string; - const userInput = prompt('please entew a session name uwu'); + const userInput = prompt('Please enter an alpha-numeric session name.'); // user canceled or did not enter a value if (!userInput) { return; @@ -42,6 +46,7 @@ export const useAddSession = () => { } try { + //TODO eventually, customizable app pre-linking? await api.poke(pokeTask(sessionName, { open: { term: agent, apps: [{ who: '~' + (window as any).ship, app: 'dojo' }] } })); useTermState.getState().set((state) => { state.names = [sessionName, ...state.names].sort(); From 6256a0a6647fd20b4b03c57eaa4c8a2cded3c0cd Mon Sep 17 00:00:00 2001 From: tomholford Date: Tue, 15 Mar 2022 11:16:44 -0600 Subject: [PATCH 041/715] ux: inform user when session input is invalid Show a helpful error message via `alert` instead of failing silently. --- pkg/interface/webterm/lib/useAddSession.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/interface/webterm/lib/useAddSession.ts b/pkg/interface/webterm/lib/useAddSession.ts index f25c13b2b..b740ebcc4 100644 --- a/pkg/interface/webterm/lib/useAddSession.ts +++ b/pkg/interface/webterm/lib/useAddSession.ts @@ -18,6 +18,7 @@ export const useAddSession = () => { const userInput = prompt('Please enter an alpha-numeric session name.'); // user canceled or did not enter a value if (!userInput) { + alert('A valid name is required to create a new session'); return; } @@ -25,6 +26,7 @@ export const useAddSession = () => { if (AGENT_SESSION_REGEX.test(userInput)) { const match = AGENT_SESSION_REGEX.exec(userInput); if (!match) { + alert('Invalid format. Valid syntax: agent!session-name'); return; } agent = match[1]; @@ -33,15 +35,18 @@ export const useAddSession = () => { } else if (SESSION_ID_REGEX.test(userInput)) { const match = SESSION_ID_REGEX.exec(userInput); if (!match) { + alert('Invalid format. Valid syntax: session-name'); return; } sessionName = match[1]; } else { + alert('Invalid format. Valid syntax: session-name'); return; } - // avoid nil or duplicate sessions - if(!sessionName || names.includes(sessionName)) { + // prevent duplicate sessions + if(names.includes(sessionName)) { + alert(`Session name must be unique ("${sessionName}" already in use)`); return; } From 1c72ff610312af50d1b3f4058674c6e7a10a249b Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Wed, 16 Mar 2022 12:12:39 -0400 Subject: [PATCH 042/715] Revert "hoon: change %brdt AST to support doccords label" This reverts commit 0dc3498a6f2b0bbc63b367031720e56a5221d76d. --- pkg/arvo/sys/hoon.hoon | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index 8307566eb..b4ef91597 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -6440,7 +6440,7 @@ [%brcb p=spec q=alas r=(map term tome)] :: |_ [%brcl p=hoon q=hoon] :: |: [%brcn p=(unit term) q=(map term tome)] :: |% - [%brdt p=(unit term) q=hoon] :: |. + [%brdt p=hoon] :: |. [%brkt p=hoon q=(map term tome)] :: |^ [%brhp p=hoon] :: |- [%brsg p=spec q=hoon] :: |~ @@ -8213,12 +8213,12 @@ :: ++ apply-whit ^- hoon - :: if wit is empty, just return the hoon ?: =([~ ~ ~ ~] wit) gen ?+ gen gen :: [%brcn *] +<<<<<<< HEAD [%brcn lab.wit q.gen] :: populate (unit term) with lab.wit :: [%brpt *] @@ -8226,6 +8226,9 @@ :: [%brdt *] [%brdt lab.wit q.gen] +======= + [%brcn lab.wit q.gen] +>>>>>>> parent of 0dc3498a6f (hoon: change %brdt AST to support doccords label) == -- :: @@ -8446,10 +8449,10 @@ |= =hoon ?~ q.gen hoon [%tstr [p.i.q.gen ~] q.i.q.gen $(q.gen t.q.gen)] - [%brcl *] [%tsls p.gen [%brdt ~ q.gen]] ::TODO ~ added when modifying %brdt, change to be appropriate docs - [%brdt *] :+ %brcn p.gen :: (docs) ~ changed to p.gen. builds a |% with an arm named $ + [%brcl *] [%tsls p.gen [%brdt q.gen]] + [%brdt *] :+ %brcn ~ =- [[%$ ~ -] ~ ~] - (~(put by *(map term hoon)) %$ q.gen) + (~(put by *(map term hoon)) %$ p.gen) [%brkt *] :+ %tsgl [%limb %$] :+ %brcn ~ =+ zil=(~(get by q.gen) %$) @@ -8458,7 +8461,7 @@ [*what [[%$ p.gen] ~ ~]] %+ ~(put by q.gen) %$ [p.u.zil (~(put by q.u.zil) %$ p.gen)] - [%brhp *] [%tsgl [%limb %$] [%brdt ~ p.gen]] :: TODO ~ added when modifying %brdt. change to appropriate docs + [%brhp *] [%tsgl [%limb %$] [%brdt p.gen]] [%brsg *] [%ktbr [%brts p.gen q.gen]] [%brtr *] :+ %tsls [%kttr p.gen] :+ %brpt ~ @@ -8467,7 +8470,7 @@ [%brts *] :+ %brcb p.gen =- [~ [[%$ ~ -] ~ ~]] (~(put by *(map term hoon)) %$ q.gen) - [%brwt *] [%ktwt %brdt ~ p.gen] :: TODO ~ added when modifying %brdt. change to appropriate docs + [%brwt *] [%ktwt %brdt p.gen] :: [%clkt *] [p.gen q.gen r.gen s.gen] [%clls *] [p.gen q.gen r.gen] @@ -8528,10 +8531,10 @@ :- %mean =+ fek=~(feck ap p.gen) ?^ fek [%rock %tas u.fek] - [%brdt ~ [%cncl [%limb %cain] [%zpgr [%tsgr [%$ 3] p.gen]] ~]] :: (doccords) added ~ for %brdt + [%brdt [%cncl [%limb %cain] [%zpgr [%tsgr [%$ 3] p.gen]] ~]] q.gen :: - [%sgcb *] [%sggr [%mean [%brdt ~ p.gen]] q.gen] :: (doccords) added ~ for %brdt + [%sgcb *] [%sggr [%mean [%brdt p.gen]] q.gen] [%sgcn *] :+ %sggl :- %fast @@ -8629,7 +8632,7 @@ :+ %tsgl :: [%wing [%| 0 ~] [%& 6] ~] :: [%limb %b] :: - :+ %brdt ~ :: |. (doccords) added ~ for %brdt + :- %brdt :: |. :^ %cnls :: %+ [%tsgr [%limb %v] p.gen] :: =>(v {p.gen}) [%cncl [%limb %b] [%limb %c] ~] :: (b c) @@ -13087,7 +13090,7 @@ ['%' (runo cen %brcn ~ expe)] ['@' (runo pat %brpt ~ expe)] [':' (rune col %brcl expb)] - ['.' (runo dot %brdt ~ expa)] + ['.' (rune dot %brdt expa)] ['-' (rune hep %brhp expa)] ['^' (rune ket %brkt expx)] ['~' (rune sig %brsg exqc)] From ff81189823098c15fdb0deca5e8daea8043962af Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Wed, 16 Mar 2022 12:13:39 -0400 Subject: [PATCH 043/715] hoon: doccords %brdt cleanup revert --- pkg/arvo/sys/hoon.hoon | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index b4ef91597..44ee27616 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -8218,17 +8218,11 @@ ?+ gen gen :: [%brcn *] -<<<<<<< HEAD [%brcn lab.wit q.gen] :: populate (unit term) with lab.wit :: [%brpt *] [%brpt lab.wit q.gen] :: populate (unit term) with lab.wit :: - [%brdt *] - [%brdt lab.wit q.gen] -======= - [%brcn lab.wit q.gen] ->>>>>>> parent of 0dc3498a6f (hoon: change %brdt AST to support doccords label) == -- :: From c01732de1608702a775d2d4a8f1e0c38b770d1f2 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Wed, 16 Mar 2022 13:05:58 -0400 Subject: [PATCH 044/715] hoon: doccords wrap bar runes with %notes this changes the parser to take any bar runes surrounded by formal comments and wraps them with %note tags containing those comments --- pkg/arvo/sys/hoon.hoon | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index 44ee27616..531d89fcb 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -8216,13 +8216,22 @@ ?: =([~ ~ ~ ~] wit) gen ?+ gen gen + :: + $? [%brbc *] [%brcb *] [%brcl *] [%brdt *] [%brkt *] + [%brhp *] [%brsg *] [%brtr *] [%brts *] [%brwt *] == + ?~ boy.wit + gen + [%note help+`u.boy.wit gen] :: [%brcn *] - [%brcn lab.wit q.gen] :: populate (unit term) with lab.wit + ?~ boy.wit + [%brcn lab.wit q.gen] + [%note help+`u.boy.wit [%brcn lab.wit q.gen]] :: [%brpt *] - [%brpt lab.wit q.gen] :: populate (unit term) with lab.wit - :: + ?~ boy.wit + [%brcn lab.wit q.gen] + [%note help+`u.boy.wit [%brpt lab.wit q.gen]] == -- :: From 2fa0bd364479da9c5b2415e9492dfd9d7fd9a345 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Wed, 16 Mar 2022 13:43:55 -0400 Subject: [PATCH 045/715] squash! hoon: doccords wrap bar runes with %notes --- pkg/arvo/sys/hoon.hoon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index 531d89fcb..c962ec606 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -8217,8 +8217,8 @@ gen ?+ gen gen :: - $? [%brbc *] [%brcb *] [%brcl *] [%brdt *] [%brkt *] - [%brhp *] [%brsg *] [%brtr *] [%brts *] [%brwt *] == + $? [%brbc *] [%brcb *] [%brcl *] [%brdt *] [%brkt *] + [%brhp *] [%brsg *] [%brtr *] [%brts *] [%brwt *] == ?~ boy.wit gen [%note help+`u.boy.wit gen] From 37580fa7221ff727c61a09e2b39364144e3f9f6f Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Fri, 18 Mar 2022 17:03:02 -0400 Subject: [PATCH 046/715] hoon: doccords for tisfas wraps the skin in tisface with a %help skin --- pkg/arvo/sys/hoon.hoon | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index c962ec606..35f4bb258 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -8216,7 +8216,7 @@ ?: =([~ ~ ~ ~] wit) gen ?+ gen gen - :: + :: bar runes $? [%brbc *] [%brcb *] [%brcl *] [%brdt *] [%brkt *] [%brhp *] [%brsg *] [%brtr *] [%brts *] [%brwt *] == ?~ boy.wit @@ -8232,6 +8232,13 @@ ?~ boy.wit [%brcn lab.wit q.gen] [%note help+`u.boy.wit [%brpt lab.wit q.gen]] + :: + :: tis runes + [%tsfs *] + ?~ boy.wit + gen + [%tsfs [%help `u.boy.wit p.gen] q.gen r.gen] +:: [%tsfs help+`u.boy.wit p.gen q.gen r.gen] == -- :: From e50635babd25fbabf70fa88183c835d2ed204bfb Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Fri, 18 Mar 2022 18:22:26 -0400 Subject: [PATCH 047/715] hoon: doccords wrap %rock %sand %wing %knit %bust wraps them in %note hoons --- pkg/arvo/sys/hoon.hoon | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index 35f4bb258..42d15e896 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -8215,10 +8215,18 @@ ^- hoon ?: =([~ ~ ~ ~] wit) gen + |^ ?+ gen gen + :: non-recursive hoons + :: %knit can contain hoons, but since its supposed to be printed as a + :: string, I think I can ignore the recursion? + $? [%rock *] [%sand *] [%wing *] [%knit *] [%bust *] == + wrap-boy + :: :: bar runes $? [%brbc *] [%brcb *] [%brcl *] [%brdt *] [%brkt *] [%brhp *] [%brsg *] [%brtr *] [%brts *] [%brwt *] == + :: TODO: handle recursion ?~ boy.wit gen [%note help+`u.boy.wit gen] @@ -8240,6 +8248,11 @@ [%tsfs [%help `u.boy.wit p.gen] q.gen r.gen] :: [%tsfs help+`u.boy.wit p.gen q.gen r.gen] == + :: + ++ wrap-boy + ?~ boy.wit gen + [%note help+`u.boy.wit gen] + -- -- :: ++ grip From 01de5a06b0aebe797570e4f137ee2b3e1eb24c18 Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 25 Mar 2022 13:45:29 +0100 Subject: [PATCH 048/715] term: consistently use x/y coordinate ordering %rez has always used "width & height". Certainly, "x & y" is more standard than "row & column". As such, we settle on making %hop and %hit respect the more natural ordering. This change is safe because these interfaces haven't made it to livenet yet. --- pkg/arvo/lib/hood/drum.hoon | 8 ++++---- pkg/arvo/mar/dill/blit.hoon | 2 +- pkg/arvo/sys/lull.hoon | 5 ++--- pkg/base-dev/lib/dill.hoon | 4 ++-- pkg/interface/webterm/Buffer.tsx | 2 +- pkg/interface/webterm/lib/blit.ts | 2 +- pkg/npm/api/term/types.ts | 4 ++-- pkg/urbit/vere/io/term.c | 8 +++++--- 8 files changed, 18 insertions(+), 17 deletions(-) diff --git a/pkg/arvo/lib/hood/drum.hoon b/pkg/arvo/lib/hood/drum.hoon index 5399edeea..39ceb90db 100644 --- a/pkg/arvo/lib/hood/drum.hoon +++ b/pkg/arvo/lib/hood/drum.hoon @@ -685,13 +685,13 @@ (ta-hom %del pos.inp) :: ++ ta-hit :: hear click - |= [r=@ud c=@ud] + |= [x=@ud y=@ud] ^+ +> - ?. =(0 r) +> + ?. =(0 y) +> =/ pol=@ud (lent-char:klr (make:klr cad.pom)) - ?: (lth c pol) +>.$ - +>.$(pos.inp (min (sub c pol) (lent buf.say.inp))) + ?: (lth x pol) +>.$ + +>.$(pos.inp (min (sub x pol) (lent buf.say.inp))) :: ++ ta-erl :: hear local error |= pos=@ud diff --git a/pkg/arvo/mar/dill/blit.hoon b/pkg/arvo/mar/dill/blit.hoon index 5ec9b08cb..3ba85e3dc 100644 --- a/pkg/arvo/mar/dill/blit.hoon +++ b/pkg/arvo/mar/dill/blit.hoon @@ -21,7 +21,7 @@ %mor [%a (turn p.dib |=(a=dill-blit:dill json(dib a)))] %hop %+ frond %hop ?@ p.dib (numb p.dib) - (pairs 'r'^(numb r.p.dib) 'c'^(numb c.p.dib) ~) + (pairs 'x'^(numb x.p.dib) 'y'^(numb y.p.dib) ~) %put (frond -.dib (tape (tufa p.dib))) ?(%bel %clr) (frond %act %s -.dib) == diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 32a1de2c5..3caace4f6 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -1080,13 +1080,13 @@ $% [%aro p=?(%d %l %r %u)] :: arrow key [%bac ~] :: true backspace [%del ~] :: true delete - [%hit r=@ud c=@ud] :: mouse click + [%hit x=@ud y=@ud] :: mouse click [%ret ~] :: return == :: +$ blit :: client output $% [%bel ~] :: make a noise [%clr ~] :: clear the screen - [%hop p=$@(@ud [r=@ud c=@ud])] :: set cursor col/pos + [%hop p=$@(@ud [x=@ud y=@ud])] :: set cursor col/pos [%klr p=stub] :: put styled [%mor p=(list blit)] :: multiple blits [%nel ~] :: newline @@ -1100,7 +1100,6 @@ $% belt :: client input [%cru p=@tas q=(list tank)] :: echo error [%hey ~] :: refresh - ::TODO inconsistent with %hit and %hop [%rez p=@ud q=@ud] :: resize, cols, rows [%yow p=gill:gall] :: connect to app == :: diff --git a/pkg/base-dev/lib/dill.hoon b/pkg/base-dev/lib/dill.hoon index d3592c07d..41608b263 100644 --- a/pkg/base-dev/lib/dill.hoon +++ b/pkg/base-dev/lib/dill.hoon @@ -13,7 +13,7 @@ %bel b+& %clr b+& %hop ?@ p.blit (numb p.blit) - (pairs 'r'^(numb r.p.blit) 'c'^(numb c.p.blit) ~) + (pairs 'x'^(numb x.p.blit) 'y'^(numb y.p.blit) ~) %put a+(turn p.blit |=(c=@c s+(tuft c))) %nel b+& %url s+p.blit @@ -74,7 +74,7 @@ :~ aro+(su (perk %d %l %r %u ~)) bac+ul del+ul - hit+(ot 'r'^ni 'c'^ni ~) + hit+(ot 'x'^ni 'y'^ni ~) ret+ul == :: diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx index 067fd0cf9..67b8f03c6 100644 --- a/pkg/interface/webterm/Buffer.tsx +++ b/pkg/interface/webterm/Buffer.tsx @@ -90,7 +90,7 @@ const readInput = (term: Terminal, e: string): Belt[] => { if (1 === m) { const c = e.charCodeAt(2) - 32; const r = e.charCodeAt(3) - 32; - belts.push({ hit: { r: term.rows - r, c: c - 1 } }); + belts.push({ hit: { y: term.rows - r, x: c - 1 } }); } e = e.slice(3); break; diff --git a/pkg/interface/webterm/lib/blit.ts b/pkg/interface/webterm/lib/blit.ts index 5285675f1..cd25de168 100644 --- a/pkg/interface/webterm/lib/blit.ts +++ b/pkg/interface/webterm/lib/blit.ts @@ -21,7 +21,7 @@ export const showBlit = (term: Terminal, blit: Blit) => { if (typeof blit.hop === 'number') { out += csi('H', term.rows, blit.hop + 1); } else { - out += csi('H', term.rows - blit.hop.r, blit.hop.c + 1); + out += csi('H', term.rows - blit.hop.y, blit.hop.x + 1); } out += csi('s'); // save cursor position } else if ('put' in blit) { diff --git a/pkg/npm/api/term/types.ts b/pkg/npm/api/term/types.ts index 362973f31..2f352a728 100644 --- a/pkg/npm/api/term/types.ts +++ b/pkg/npm/api/term/types.ts @@ -25,7 +25,7 @@ export type Stub = { export type Blit = | { bel: null } // make a noise | { clr: null } // clear the screen - | { hop: number | { r: number, c: number } } // set cursor col/pos + | { hop: number | { x: number, y: number } } // set cursor col/pos | { klr: Stub[] } // put styled | { mor: Blit[] } // multiple blits | { nel: null } // newline @@ -43,7 +43,7 @@ export type Bolt = | { aro: 'd' | 'l' | 'r' | 'u' } | { bac: null } | { del: null } - | { hit: { r: number, c: number } } + | { hit: { x: number, y: number } } | { ret: null } export type Belt = diff --git a/pkg/urbit/vere/io/term.c b/pkg/urbit/vere/io/term.c index ba5775cbd..387e939ea 100644 --- a/pkg/urbit/vere/io/term.c +++ b/pkg/urbit/vere/io/term.c @@ -405,7 +405,7 @@ _term_it_show_blank(u3_utty* uty_u) * it is clipped to stay within the window. */ static void -_term_it_move_cursor(u3_utty* uty_u, c3_w row_w, c3_w col_w) +_term_it_move_cursor(u3_utty* uty_u, c3_w col_w, c3_w row_w) { c3_l row_l = uty_u->tat_u.siz.row_l; c3_l col_l = uty_u->tat_u.siz.col_l; @@ -698,7 +698,9 @@ _term_io_suck_char(u3_utty* uty_u, c3_y cay_y) c3_y row_y = cay_y - 32; // only acknowledge button 1 presses within our window if ( 1 != tat_u->esc.ton_y && row_y <= tat_u->siz.row_l ) { - _term_io_belt(uty_u, u3nt(c3__hit, tat_u->siz.row_l - row_y, tat_u->esc.col_y - 1)); + _term_io_belt(uty_u, u3nt(c3__hit, + tat_u->esc.col_y - 1, + tat_u->siz.row_l - row_y)); } tat_u->esc.mou = c3n; tat_u->esc.ton_y = tat_u->esc.col_y = 0; @@ -1334,7 +1336,7 @@ _term_ef_blit(u3_utty* uty_u, case c3__hop: { u3_noun pos = u3t(blt); if ( c3y == u3r_ud(pos) ) { - _term_it_move_cursor(uty_u, 0, pos); + _term_it_move_cursor(uty_u, pos, 0); } else { _term_it_move_cursor(uty_u, u3h(pos), u3t(pos)); From 890e5f1e9b2b1a1128dd81c5492fd3b73315badc Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 25 Mar 2022 14:41:53 +0100 Subject: [PATCH 049/715] webterm: do not warn on session creation cancel --- pkg/interface/webterm/lib/useAddSession.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/interface/webterm/lib/useAddSession.ts b/pkg/interface/webterm/lib/useAddSession.ts index b740ebcc4..25a5fc0c2 100644 --- a/pkg/interface/webterm/lib/useAddSession.ts +++ b/pkg/interface/webterm/lib/useAddSession.ts @@ -17,8 +17,7 @@ export const useAddSession = () => { const userInput = prompt('Please enter an alpha-numeric session name.'); // user canceled or did not enter a value - if (!userInput) { - alert('A valid name is required to create a new session'); + if (null === userInput) { return; } From 8da6c20f700772af7c65825d1a1cf9f5b3179407 Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 25 Mar 2022 15:08:50 +0100 Subject: [PATCH 050/715] herm: stop sending %hail on-connect Client will probably want to send a %blew first anyway. By not doing any screen refreshed in herm, we avoid doing unnecessary redraws on-connect. --- pkg/arvo/app/herm.hoon | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/pkg/arvo/app/herm.hoon b/pkg/arvo/app/herm.hoon index 0d7f45a65..aefe6c8df 100644 --- a/pkg/arvo/app/herm.hoon +++ b/pkg/arvo/app/herm.hoon @@ -44,17 +44,12 @@ ~| path ?> ?=([%session @ %view ~] path) =* ses i.t.path - :~ :: subscribe to the requested session - :: - ::NOTE multiple views do not result in multiple subscriptions - :: because they go over the same wire/duct - :: - (pass-session ses %view ~) - :: tell session to refresh, so new client knows what's on screen - ::TODO should client be responsible for this? - :: - (pass-session ses %hail ~) - == + :: subscribe to the requested session + :: + ::NOTE multiple views do not result in multiple subscriptions + :: because they go over the same wire/duct + :: + [(pass-session ses %view ~)]~ :: ++ on-arvo |= [=wire =sign-arvo] From 60ed368bc4752b7244eb7d8bf6074f5b26699fa9 Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 25 Mar 2022 15:38:56 +0100 Subject: [PATCH 051/715] webterm: fix bell icon in tabs Presumably due to how js non-objects work in closures, the selected prop we were reading out whenever a blit came in was stale. Also, it was possible that a bell was hiding inside a %mor blit, so we add a small helper for checking properly. --- pkg/interface/webterm/Buffer.tsx | 5 +++-- pkg/interface/webterm/lib/blit.ts | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx index 67b8f03c6..8d5ae2ce7 100644 --- a/pkg/interface/webterm/Buffer.tsx +++ b/pkg/interface/webterm/Buffer.tsx @@ -12,7 +12,7 @@ import useTermState from './state'; import React from 'react'; import { Box, Col } from '@tlon/indigo-react'; import { makeTheme } from './lib/theme'; -import { showBlit, csi } from './lib/blit'; +import { showBlit, csi, hasBell } from './lib/blit'; import { DEFAULT_SESSION } from './constants'; import { retry } from './lib/retry'; @@ -180,7 +180,8 @@ export default function Buffer({ name, selected, dark }: BufferProps) { app: 'herm', path: '/session/' + name + '/view', event: (e) => { showBlit(ses.term, e); - if (e.bel && !selected) { + //NOTE getting selected from state because selected prop is stale + if (hasBell(e) && (useTermState.getState().selected !== name)) { useTermState.getState().set((state) => { state.sessions[name].hasBell = true; }); diff --git a/pkg/interface/webterm/lib/blit.ts b/pkg/interface/webterm/lib/blit.ts index cd25de168..e98f8fe75 100644 --- a/pkg/interface/webterm/lib/blit.ts +++ b/pkg/interface/webterm/lib/blit.ts @@ -73,3 +73,13 @@ export const showSlog = (term: Terminal, slog: string) => { + csi('r') + csi('u')); }; + +export const hasBell = (blit: Blit) => { + if ('bel' in blit) { + return true; + } else if ('mor' in blit) { + return blit.mor.some(hasBell); + } else { + return false; + } +} From af7d38124be14d6f66f3486ea9a70b9853ef3cc6 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Wed, 30 Mar 2022 14:51:40 -0400 Subject: [PATCH 052/715] doccords: finding and print doccords library initial commit for library for finding and printing doccords. has some basic functionality for looking through a type and finding the docs within it and printing them, but is mostly unfinished --- pkg/arvo/lib/dprint.hoon | 204 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 pkg/arvo/lib/dprint.hoon diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon new file mode 100644 index 000000000..6695cad0d --- /dev/null +++ b/pkg/arvo/lib/dprint.hoon @@ -0,0 +1,204 @@ +:: A library for printing doccords +=> + |% + :> an overview of all named things in the type. + :> + :> each element in the overview list is either a documentation for a sublist + :> or an association betwen a term and documentation for it + +$ overview (list overview-item) + :: + :> an element of an overview + +$ overview-item + $% [%header doc=what children=overview] + [%item name=tape doc=what] + == + :: + :> the part of a type being inspected + +$ item + $% + :: overview of a type + :: + [%view items=overview] + :: inspecting a full core + $: %core + name=tape + docs=what + sut=type + con=coil + children=(unit item) + == + :: inspecting a single arm on a core + $: %arm + name=tape + docs=what + gen=hoon + sut=type + == + :: inspecting a face and what's behind it + $: %face + name=tape + docs=what + children=(unit item) + == + :: inspecting a single chapter on a core + $: %chapter + name=tape + docs=what + sut=type + con=coil + chapter-id=@ + == + == + :: + -- +|% +:: arms for finding docs in types +::+| %searching +:> returns the item to print while searching through topic +:> +:> this gate is called recursively to find the path (topic) in the type +:> (sut). once it finds the correct part of the type, it switches to +:> +build-inspectable-recursively to describe that part of the type +++ find-item-in-type + |= [topics=(list term) sut=type] + ^- (unit item) + ?~ topics + ~ ::(build-inspectable-recursively sut) + ?- sut + [%atom *] ~ + :: + [%cell *] + =+ lhs=$(sut p.sut) + ?~ lhs + $(sut q.sut) + lhs + :: + [%core *] + :: cores don't have any doc structure inside of them. i probably need to + :: check that they're wrapped with a %hint type. so this just looks for + :: docs on the arms + =+ arm=(find-arm-in-coil i.topics q.sut) + ?~ arm + :: the current topic is not an arm in the core + $(sut p.sut) + :: check to see if the arm is wrapped with a note + =+ wat=(unwrap-note u.arm) + `[%arm (trip i.topics) wat u.arm p.sut] + :: TODO: check for chapter docs + :: + [%face *] + ?. ?=(term p.sut) + :: TODO: handle tune case + ~ + ?. =(i.topics p.sut) + :: this face has a name, but not the one we're looking for + ~ + :: faces need to be checked to see if they're wrapped + ~ + :: + [%fork *] + =/ types=(list type) ~(tap in p.sut) + |- + ?~ types + ~ + =+ res=^$(sut i.types) + ?~ res + $(types t.types) + res + :: + [%hint *] + :: this is probably where most of the action should take place. it should + :: grab the docs from the hint and then look inside of the type to see where + :: it ought to go + ~ + :: + [%hold *] $(sut (~(play ut p.sut) q.sut)) + :: + %noun ~ + %void ~ + == +:: +:> checks if a hoon is wrapped with a help note, and returns it if so +++ unwrap-note + |= gen=hoon + ^- what + ?: ?=([%note *] gen) + ?: ?=([%help *] p.gen) + `crib.p.p.gen + ~ + ~ +:: +:> if arm-name is an arm in con, return its hoon and potentially the note wrapping it (?) +++ find-arm-in-coil + |= [arm-name=term con=coil] + ^- (unit hoon) + :: + =/ tomes=(list [p=term q=tome]) ~(tap by q.r.con) + |- + ?~ tomes + ~ + =+ item=(~(get by q.q.i.tomes) arm-name) + ?~ item + $(tomes t.tomes) +:: ?: =([%note *] u.item) :: the arm is wrapped with a %note +:: [~ p.u.item u.item] :: maybe i should check for the note later + `u.item +:: +:> gets the documentation inside of a type +++ docs-from-type + |= sut=type + ^- what + ?+ sut ~ + [%core *] ~ :: should this get the chapter docs? + [%hint *] ?>(?=(%help -.q.p.sut) `crib.p.q.p.sut) + [%hold *] $(sut (~(play ut p.sut) q.sut)) + == +:> grabs the docs for an arm. +++ select-arm-docs + |= [arm-doc=what fot=foot sut=type] + ^- [what what what] + =+ foot-type=(~(play ut sut) p.fot) + =/ raw-doc=what (docs-from-type foot-type) + :: if the arm builds a core, get the docs for the default arm + :: in that core + =/ core-doc=what + ?. ?=([%core *] foot-type) + ~ + (docs-from-type (~(play ut foot-type) [%limb %$])) + :: i think at least one of these will always be empty + :+ arm-doc raw-doc core-doc +:: +:: :> # +:: :> # %printing +:: :> # +:: :> functions which display output of various types +:: +| %printing +:: +:> renders a list of sections as tang +:> +:> prints the longform documentation +++ print-sections + |= sections=(list sect) + ^- tang + =| out=tang + |- + ?~ sections out + =. out + ;: weld + out + `tang`[%leaf ""]~ + (print-section i.sections) + == + $(sections t.sections) +:: +:> renders a sect as a tang +++ print-section + |= section=sect + ^- tang + %+ turn section + |= =pica + ^- tank + ?: p.pica + [%leaf (trip q.pica)] + [%leaf " {(trip q.pica)}"] +-- From 91aeb0fdbff20ab209284238de7478919209f895 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Wed, 30 Mar 2022 15:36:30 -0400 Subject: [PATCH 053/715] doccords: more printing tools --- pkg/arvo/lib/dprint.hoon | 110 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 3 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index 6695cad0d..1cc1710e5 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -46,7 +46,7 @@ docs=what sut=type con=coil - chapter-id=@ + chapter-id=term == == :: @@ -155,9 +155,9 @@ == :> grabs the docs for an arm. ++ select-arm-docs - |= [arm-doc=what fot=foot sut=type] + |= [arm-doc=what gen=hoon sut=type] ^- [what what what] - =+ foot-type=(~(play ut sut) p.fot) + =+ foot-type=(~(play ut sut) gen) =/ raw-doc=what (docs-from-type foot-type) :: if the arm builds a core, get the docs for the default arm :: in that core @@ -168,11 +168,115 @@ :: i think at least one of these will always be empty :+ arm-doc raw-doc core-doc :: +:> returns an overview of the arms in a specific chapter +++ arms-in-chapter + |= [sut=type con=coil chapter-id=term] + ^- overview + =/ chapter-tome (~(got by q.r.con) chapter-id) + (sort-overview (arms-as-overview q.chapter-tome sut)) +:: +:> sort items in an overview in alphabetical order +++ sort-overview + |= ovr=overview + ^- overview + %+ sort ovr + |= [lhs=overview-item rhs=overview-item] + (aor (get-overview-name lhs) (get-overview-name rhs)) +:: +:> returns the name of an overview +++ get-overview-name + |= ovr=overview-item + ?- ovr + [%header *] "" + [%item *] name.ovr + == +:: +:> translate a tome into an overview +++ arms-as-overview + |= [a=(map term hoon) sut=type] + ^- overview + *overview +:: :: :> # :: :> # %printing :: :> # :: :> functions which display output of various types :: +| %printing +:> prints a doccords item +++ print-item + |= =item + ^- tang + ?- item + [%view *] (print-overview items.item) + [%core *] (print-core +.item) + [%arm *] (print-arm +.item) + [%chapter *] (print-chapter +.item) + [%face *] (print-face +.item) + == +:: +:> renders documentation for a full core +++ print-core + |= [name=tape docs=what sut=type con=coil uit=(unit item)] + ^- tang + *tang +:: +++ print-chapter + |= [name=tape doc=what sut=type con=coil chapter-id=term] + ^- tang + ;: weld + (print-header name doc) + :: + ?~ doc + ~ + (print-sections q.u.doc) + :: + =+ arms=(arms-in-chapter sut con chapter-id) + ?~ arms + ~ + (print-overview [%header `['arms:' ~] arms]~) + == +:: +:> renders documentation for a single arm in a core +++ print-arm + |= [name=tape docs=what gen=hoon sut=type] + ^- tang + =+ [main-doc raw-doc product-doc]=(select-arm-docs docs gen sut) + %+ weld + (print-header name main-doc) + ?~ product-doc + ~ + %+ weld + `tang`[[%leaf ""] [%leaf "product:"] ~] + (print-header "" product-doc) +:: +++ print-face + |= [name=tape doc=what children=(unit item)] + ^- tang + %+ weld + (print-header name doc) + ?~ children + ~ + (print-item u.children) +:: +++ print-header + |= [name=tape doc=what] + ^- tang + ?~ name + ?~ doc + [%leaf "(undocumented)"]~ + %+ weld + `tang`[%leaf "{(trip p.u.doc)}"]~ + (print-sections q.u.doc) + ?~ doc + [%leaf name]~ + %+ weld + `tang`[%leaf "{name}: {(trip p.u.doc)}"]~ + (print-sections q.u.doc) +:: +++ print-overview + |= ovr=overview + ^- tang + *tang :: :> renders a list of sections as tang :> From 1af2e8fdae68ce39703fb9bcb76421d8c9508ba3 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Thu, 31 Mar 2022 14:39:09 -0400 Subject: [PATCH 054/715] doccords: dprint library unwrapping hints doesn't totally work yet --- pkg/arvo/lib/dprint.hoon | 244 ++++++++++++++++++++++++++++++++++----- 1 file changed, 215 insertions(+), 29 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index 1cc1710e5..ee0d9fce5 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -1,4 +1,5 @@ :: A library for printing doccords +=/ debug & => |% :> an overview of all named things in the type. @@ -58,13 +59,17 @@ :> :> this gate is called recursively to find the path (topic) in the type :> (sut). once it finds the correct part of the type, it switches to -:> +build-inspectable-recursively to describe that part of the type +:> +signify to describe that part of the type ++ find-item-in-type - |= [topics=(list term) sut=type] + :: TODO make this work with a list of topics + |= [topic=term sut=type] ^- (unit item) - ?~ topics - ~ ::(build-inspectable-recursively sut) + :: ?~ topics + :: :: we have no more search paths TODO: return the rest as an overview + :: (signify sut) ?- sut + %noun ~ + %void ~ [%atom *] ~ :: [%cell *] @@ -77,20 +82,21 @@ :: cores don't have any doc structure inside of them. i probably need to :: check that they're wrapped with a %hint type. so this just looks for :: docs on the arms - =+ arm=(find-arm-in-coil i.topics q.sut) + =+ arm=(find-arm-in-coil topic q.sut) ?~ arm :: the current topic is not an arm in the core $(sut p.sut) :: check to see if the arm is wrapped with a note =+ wat=(unwrap-note u.arm) - `[%arm (trip i.topics) wat u.arm p.sut] + `[%arm (trip topic) wat u.arm p.sut] + :: `[%arm (trip topic) wat u.arm q.q.sut] :: what's the difference if i use the type in the coil? :: TODO: check for chapter docs :: [%face *] ?. ?=(term p.sut) :: TODO: handle tune case ~ - ?. =(i.topics p.sut) + ?. =(topic p.sut) :: this face has a name, but not the one we're looking for ~ :: faces need to be checked to see if they're wrapped @@ -107,18 +113,88 @@ res :: [%hint *] - :: this is probably where most of the action should take place. it should - :: grab the docs from the hint and then look inside of the type to see where - :: it ought to go - ~ + :: If we found a help hint, it is wrapping a type for which we might want to + :: produce an item, so we should peek inside of it to see what type it is + :: and grab the docs from +signify + :: + :: check to see if type inside the hint is a match + :: TODO: should i be trying to match both types in the hint? + :: TODO: actually hints can be nested, if e.g. an arm has a product with a hint, whose + :: product also has a hint. so this won't actually work for nested hints as written + ?: (shallow-match topic q.sut) + =/ wat=what (unwrap-hint sut) + =/ itm=(unit item) (signify q.sut) + ?~ itm + ~ + `(emblazen u.itm wat) +:: (emblazen (need (signify q.sut)) (unwrap-hint sut)) + $(sut q.sut) :: [%hold *] $(sut (~(play ut p.sut) q.sut)) :: - %noun ~ - %void ~ == :: -:> checks if a hoon is wrapped with a help note, and returns it if so +:> non-recursive check to see if type matches search +:> +:> this is for applying help hints to types when searching for a match. hints +:> are only for the type theyre immediately wrapping, not something nested +:> deeper, so we dont always want to recurse +++ shallow-match + |= [topic=term sut=type] + ^- ? + ?+ sut %.n + [%atom *] %.n :: should we allow doccords on individual atoms? i think they should be for faces + [%core *] !=(~ (find ~[topic] (sloe sut))) + [%face *] ?. ?=(term p.sut) + %.n :: TODO: handle tune case + =(topic p.sut) + == +:: +:> changes a type into a item +:> +:> this does not actually assign the docs, since they usually come from a hint +:> wrapping the type. +++ signify + |= sut=type + ^- (unit item) + ?- sut + :: + [%atom *] ~ + :: + [%cell *] + %+ join-items + $(sut p.sut) + $(sut q.sut) + :: + [%core *] + =/ name ~ :: should check if core is built with an arm and use that name? + =* compiled-against $(sut p.sut) + `[%core (trip name) *what p.sut q.sut compiled-against] + :: + [%face *] + ?. ?=(term p.sut) + :: TODO: handle tune case + ~ + =* compiled-against $(sut q.sut) + `[%face (trip p.sut) *what compiled-against] + :: + [%fork *] + =* types ~(tap in p.sut) + =* items (turn types signify) + (roll items join-items) + :: + [%hint *] + =* rest-type $(sut q.sut) + :: check to see if it is a help hint + ?> ?=(%help -.q.p.sut) + `[%view [%header `crib.p.q.p.sut (item-as-overview rest-type)]~] + :: + [%hold *] $(sut (~(play ut p.sut) q.sut)) + %noun ~ + %void ~ + == + +:> checks if a hoon is wrapped with a help note, and returns it if so ++ unwrap-note |= gen=hoon ^- what @@ -128,11 +204,41 @@ ~ ~ :: +:> checks if a hint type is a help hint and returns the docs if so +++ unwrap-hint + |= sut=type + ^- what + :: should I care what the type in the (pair type note) is? + ?. ?=([%hint *] sut) + ~? > debug %not-hint-type + ~ + ?>(?=(%help -.q.p.sut) `crib.p.q.p.sut) +:: +:> inserts docs into an item +:> +:> most docs are going to be found in hint types wrapping another type. when +:> we come across a hint, we grab the docs from the hint and then build the +:> item for the type it wrapped. since building an item is handled separately, +:> this item will initially have no docs in it, so we add it in after with this +:> +:> the exceptions to this are %chapter and %view items. chapters have an axis +:> for docs in their $tome structure, and %views are summaries of several types +++ emblazen + |= [=item =what] + ~? >> debug %emblazen + ^+ item + ?+ item item :: no-op on %chapter and %view + ?([%core *] [%arm *] [%face *]) ?~ docs.item + item(docs what) + ~? > debug %docs-in-item + item(docs what) + == +:: :> if arm-name is an arm in con, return its hoon and potentially the note wrapping it (?) ++ find-arm-in-coil |= [arm-name=term con=coil] + ~? >> debug %find-arm-in-coil ^- (unit hoon) - :: =/ tomes=(list [p=term q=tome]) ~(tap by q.r.con) |- ?~ tomes @@ -140,34 +246,73 @@ =+ item=(~(get by q.q.i.tomes) arm-name) ?~ item $(tomes t.tomes) -:: ?: =([%note *] u.item) :: the arm is wrapped with a %note -:: [~ p.u.item u.item] :: maybe i should check for the note later `u.item :: :> gets the documentation inside of a type ++ docs-from-type + :: TODO: the following comment doesn't appear because of some issue with product + :: docs, unless i erase the arm-doc + :> testing |= sut=type ^- what ?+ sut ~ - [%core *] ~ :: should this get the chapter docs? - [%hint *] ?>(?=(%help -.q.p.sut) `crib.p.q.p.sut) + [%core *] ~? >> debug %docs-from-type-core ~ :: should this get the chapter docs? + [%hint *] ~? >> debug %docs-from-type-hint ?>(?=(%help -.q.p.sut) `crib.p.q.p.sut) [%hold *] $(sut (~(play ut p.sut) q.sut)) == +:: :> grabs the docs for an arm. +:> +:> there are three possible places with relevant docs for an arm: +:> docs for the arm itself, docs for the product of the arm, and +:> if the arm builds a core, docs for the default arm of that core. +:> arm-doc: docs wrapping the arm - this should have already been found +:> raw-doc: docs for the product of the arm +:> core-doc: docs for the default arm of the core produced by the arm ++ select-arm-docs |= [arm-doc=what gen=hoon sut=type] + ~? >> debug %select-arm-docs ^- [what what what] - =+ foot-type=(~(play ut sut) gen) - =/ raw-doc=what (docs-from-type foot-type) + =+ hoon-type=(~(play ut sut) gen) + ~? >>> debug hoon-type + =/ raw-doc=what (docs-from-type hoon-type) + ~? > debug raw-doc :: if the arm builds a core, get the docs for the default arm :: in that core =/ core-doc=what - ?. ?=([%core *] foot-type) + ?. ?=([%core *] hoon-type) + ~? > debug %no-core-product ~ - (docs-from-type (~(play ut foot-type) [%limb %$])) - :: i think at least one of these will always be empty + (docs-from-type (~(play ut hoon-type) [%limb %$])) + :: i think arm-doc and raw-doc might always be the same + ~? > debug :+ arm-doc raw-doc core-doc :+ arm-doc raw-doc core-doc :: +:> returns an overview for a cores arms and chapters +:> +:> returns an overview for arms which are part of unnamed chapters, and +:> an overview of the named chapters +++ arm-and-chapter-overviews + |= [sut=type con=coil core-name=tape] + ^- [overview overview] + =| arm-docs=overview + =| chapter-docs=overview + =/ tomes ~(tap by q.r.con) + |- + ?~ tomes + [(sort-overview arm-docs) (sort-overview chapter-docs)] + =* current i.tomes ::[term tome] + ?~ p.current + :: chapter has no name. add documentation for its arms to arm-docs + =. arm-docs (weld arm-docs (arms-as-overview q.q.current sut)) + $(tomes t.tomes) + :: chapter has a name. add to list of chapters + =. chapter-docs + %+ weld chapter-docs + ^- overview + [%item :(weld (trip -.current) ":" core-name) p.q.current]~ + $(tomes t.tomes) +:: :> returns an overview of the arms in a specific chapter ++ arms-in-chapter |= [sut=type con=coil chapter-id=term] @@ -180,8 +325,8 @@ |= ovr=overview ^- overview %+ sort ovr - |= [lhs=overview-item rhs=overview-item] - (aor (get-overview-name lhs) (get-overview-name rhs)) + |= [lhs=overview-item rhs=overview-item] + (aor (get-overview-name lhs) (get-overview-name rhs)) :: :> returns the name of an overview ++ get-overview-name @@ -193,10 +338,49 @@ :: :> translate a tome into an overview ++ arms-as-overview + :: currently this doesn't do anything until i implement arm-doc |= [a=(map term hoon) sut=type] ^- overview - *overview + %+ turn ~(tap by a) + |= ar=(pair term hoon) + =/ doc (select-arm-docs *what q.ar sut) :: *what should be from the hint wrapper + [%item (weld "++" (trip p.ar)) -.doc] :: +:> changes an item into an overview +++ item-as-overview + |= uit=(unit item) + ^- overview + ?~ uit ~ + =+ itm=(need uit) + ?- itm + :: + [%view *] items.itm + :: + [%core *] + ?~ name.itm + (item-as-overview children.itm) + :- [%item name.itm docs.itm] + (item-as-overview children.itm) + :: + [%arm *] + [%item name.itm docs.itm]~ + :: + [%chapter *] + [%item name.itm docs.itm]~ + :: + [%face *] + ?~ name.itm + ~ + [%item name.itm docs.itm]~ + == +:: +:> combines two (unit items) together +++ join-items + |= [lhs=(unit item) rhs=(unit item)] + ^- (unit item) + ?~ lhs rhs + ?~ rhs lhs + `[%view (weld (item-as-overview lhs) (item-as-overview rhs))] :: :> # :: :> # %printing :: :> # @@ -240,15 +424,17 @@ ++ print-arm |= [name=tape docs=what gen=hoon sut=type] ^- tang + ~? >> debug %print-arm =+ [main-doc raw-doc product-doc]=(select-arm-docs docs gen sut) %+ weld (print-header name main-doc) - ?~ product-doc - ~ + :: ?~ product-doc + :: ~ %+ weld `tang`[[%leaf ""] [%leaf "product:"] ~] (print-header "" product-doc) :: +:> renders documentation for a face ++ print-face |= [name=tape doc=what children=(unit item)] ^- tang From 752182f0bf76e438e05f2d814e47ea9791e3bdce Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Thu, 31 Mar 2022 17:33:59 -0400 Subject: [PATCH 055/715] doccords: dprint fix default core arm printing if the product had its own docs, it wouldn't also get the docs for a the default arm produced by the core. this fixes that. also misc style fixes --- pkg/arvo/lib/dprint.hoon | 103 ++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 39 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index ee0d9fce5..12c30c4b7 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -81,12 +81,19 @@ [%core *] :: cores don't have any doc structure inside of them. i probably need to :: check that they're wrapped with a %hint type. so this just looks for - :: docs on the arms + :: docs on the arms. + :: + :: cores also can't have names right now. %brcn and %brpt have a slot in + :: their AST for the name, but it doesn't end up in the their type. so + :: if i want core names right now, i'd have to look inside their AST, and + :: only |% and |@ cores would have names, which is silly. =+ arm=(find-arm-in-coil topic q.sut) ?~ arm :: the current topic is not an arm in the core $(sut p.sut) :: check to see if the arm is wrapped with a note + :: TODO: this is taking docs from the AST rather than the type. is that + :: the right thing to do here? =+ wat=(unwrap-note u.arm) `[%arm (trip topic) wat u.arm p.sut] :: `[%arm (trip topic) wat u.arm q.q.sut] :: what's the difference if i use the type in the coil? @@ -126,8 +133,8 @@ =/ itm=(unit item) (signify q.sut) ?~ itm ~ - `(emblazen u.itm wat) -:: (emblazen (need (signify q.sut)) (unwrap-hint sut)) + `(emblazon u.itm wat) +:: (emblazon (need (signify q.sut)) (unwrap-hint sut)) $(sut q.sut) :: [%hold *] $(sut (~(play ut p.sut) q.sut)) @@ -157,10 +164,10 @@ ++ signify |= sut=type ^- (unit item) - ?- sut + ?- sut :: [%atom *] ~ - :: + :: [%cell *] %+ join-items $(sut p.sut) @@ -171,27 +178,26 @@ =* compiled-against $(sut p.sut) `[%core (trip name) *what p.sut q.sut compiled-against] :: - [%face *] + [%face *] ?. ?=(term p.sut) - :: TODO: handle tune case - ~ + ~ :: TODO: handle tune case =* compiled-against $(sut q.sut) `[%face (trip p.sut) *what compiled-against] :: - [%fork *] - =* types ~(tap in p.sut) - =* items (turn types signify) - (roll items join-items) - :: - [%hint *] - =* rest-type $(sut q.sut) - :: check to see if it is a help hint - ?> ?=(%help -.q.p.sut) - `[%view [%header `crib.p.q.p.sut (item-as-overview rest-type)]~] - :: - [%hold *] $(sut (~(play ut p.sut) q.sut)) - %noun ~ - %void ~ + [%fork *] + =* types ~(tap in p.sut) + =* items (turn types signify) + (roll items join-items) + :: + [%hint *] + =* rest-type $(sut q.sut) + :: check to see if it is a help hint + ?> ?=(%help -.q.p.sut) + `[%view [%header `crib.p.q.p.sut (item-as-overview rest-type)]~] + :: + [%hold *] $(sut (~(play ut p.sut) q.sut)) + %noun ~ + %void ~ == :> checks if a hoon is wrapped with a help note, and returns it if so @@ -223,9 +229,9 @@ :> :> the exceptions to this are %chapter and %view items. chapters have an axis :> for docs in their $tome structure, and %views are summaries of several types -++ emblazen +++ emblazon |= [=item =what] - ~? >> debug %emblazen + ~? >> debug %emblazon ^+ item ?+ item item :: no-op on %chapter and %view ?([%core *] [%arm *] [%face *]) ?~ docs.item @@ -234,7 +240,7 @@ item(docs what) == :: -:> if arm-name is an arm in con, return its hoon and potentially the note wrapping it (?) +:> looks for an arm in a coil and returns its hoon ++ find-arm-in-coil |= [arm-name=term con=coil] ~? >> debug %find-arm-in-coil @@ -243,10 +249,10 @@ |- ?~ tomes ~ - =+ item=(~(get by q.q.i.tomes) arm-name) - ?~ item + =+ gen=(~(get by q.q.i.tomes) arm-name) + ?~ gen $(tomes t.tomes) - `u.item + `u.gen :: :> gets the documentation inside of a type ++ docs-from-type @@ -258,7 +264,7 @@ ?+ sut ~ [%core *] ~? >> debug %docs-from-type-core ~ :: should this get the chapter docs? [%hint *] ~? >> debug %docs-from-type-hint ?>(?=(%help -.q.p.sut) `crib.p.q.p.sut) - [%hold *] $(sut (~(play ut p.sut) q.sut)) + [%hold *] ~? >> debug %docs-from-type-hold $(sut (~(play ut p.sut) q.sut)) == :: :> grabs the docs for an arm. @@ -266,8 +272,9 @@ :> there are three possible places with relevant docs for an arm: :> docs for the arm itself, docs for the product of the arm, and :> if the arm builds a core, docs for the default arm of that core. +:> :> arm-doc: docs wrapping the arm - this should have already been found -:> raw-doc: docs for the product of the arm +:> product-doc: docs for the product of the arm :> core-doc: docs for the default arm of the core produced by the arm ++ select-arm-docs |= [arm-doc=what gen=hoon sut=type] @@ -275,18 +282,36 @@ ^- [what what what] =+ hoon-type=(~(play ut sut) gen) ~? >>> debug hoon-type - =/ raw-doc=what (docs-from-type hoon-type) - ~? > debug raw-doc + =/ product-doc=what (docs-from-type hoon-type) + ~? > debug product-doc :: if the arm builds a core, get the docs for the default arm :: in that core + :: + :: this is broken if it also has an arm-doc. if i have an arm-doc, i + :: need to strip off the first hint and then check if i have a core, i think =/ core-doc=what - ?. ?=([%core *] hoon-type) - ~? > debug %no-core-product - ~ - (docs-from-type (~(play ut hoon-type) [%limb %$])) - :: i think arm-doc and raw-doc might always be the same - ~? > debug :+ arm-doc raw-doc core-doc - :+ arm-doc raw-doc core-doc + :: if product-doc is empty, just go right on and check if its a core + ?~ product-doc + ?. ?=([%core *] hoon-type) + ~? > debug %no-core-product + ~ + (docs-from-type (~(play ut hoon-type) [%limb %$])) + :: if there is a product doc, then step through the hint and check for a core + ?: ?=([%hint *] hoon-type) + ~? > debug %step-through-hint + =+ inner-type=(~(play ut q.hoon-type) gen) + :: using mule since it crashes if there's not a core + =/ res (mule |.((~(play ut inner-type) [%limb %$]))) + ?- -.res + %| ~ + %& (docs-from-type p.res) + == + ~ + :: i think arm-doc and product-doc might always be the same + :: upon further reflection, i think this is a limitation of the wrapping + :: approach + ~? > debug :* %arm-doc arm-doc %product-doc product-doc %core-doc core-doc == + :+ arm-doc product-doc core-doc :: :> returns an overview for a cores arms and chapters :> From d9e44e9e761f3b41152c7e6a85b70a9b69801ebe Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Thu, 31 Mar 2022 17:35:50 -0400 Subject: [PATCH 056/715] doccords: dprint print core routine --- pkg/arvo/lib/dprint.hoon | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index 12c30c4b7..68dabe63c 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -427,7 +427,24 @@ ++ print-core |= [name=tape docs=what sut=type con=coil uit=(unit item)] ^- tang - *tang + =+ [arms chapters]=(arm-and-chapter-overviews sut con name) + ;: weld + :: cores don't have names + (print-header *tape *what) + :: + ?~ arms + ~ + (print-overview [%header `['arms:' ~] arms]~) + :: + ?~ chapters + ~ + (print-overview [%header `['chapters:' ~] chapters]~) + :: + =+ compiled=(item-as-overview uit) + ?~ compiled + ~ + (print-overview [%header `['compiled against: ' ~] compiled]~) + == :: ++ print-chapter |= [name=tape doc=what sut=type con=coil chapter-id=term] From f9dfb590d6c8b30dc15777ad8ddc0e5fe4c57aa2 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Thu, 31 Mar 2022 17:41:48 -0400 Subject: [PATCH 057/715] hoon: turn on hints for %noun types --- pkg/arvo/sys/hoon.hoon | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index 42d15e896..04607d81b 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -7199,7 +7199,6 @@ |= [p=(pair type note) q=type] ^- type ?: =(%void q) %void - ?: =(%noun q) %noun [%hint p q] :: ++ face :: make %face type From a15711c74d95d3eb3294df9cee080e48ddb39288 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Thu, 31 Mar 2022 17:59:45 -0400 Subject: [PATCH 058/715] doccords: dprint fix crash on non-help %hint --- pkg/arvo/lib/dprint.hoon | 45 ++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index 68dabe63c..b2b0272f0 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -255,16 +255,22 @@ `u.gen :: :> gets the documentation inside of a type -++ docs-from-type - :: TODO: the following comment doesn't appear because of some issue with product - :: docs, unless i erase the arm-doc +++ what-from-type :> testing |= sut=type ^- what - ?+ sut ~ - [%core *] ~? >> debug %docs-from-type-core ~ :: should this get the chapter docs? - [%hint *] ~? >> debug %docs-from-type-hint ?>(?=(%help -.q.p.sut) `crib.p.q.p.sut) - [%hold *] ~? >> debug %docs-from-type-hold $(sut (~(play ut p.sut) q.sut)) + ?+ sut + ~ + :: + [%core *] + ~? >> debug %what-from-type-core ~ :: should this get the chapter docs? + :: + [%hold *] + ~? >> debug %what-from-type-hold $(sut (~(play ut p.sut) q.sut)) + :: + [%hint *] + ~? >> debug :- %what-from-type-hint -.q.p.sut + ?: ?=(%help -.q.p.sut) `crib.p.q.p.sut ~ == :: :> grabs the docs for an arm. @@ -282,7 +288,7 @@ ^- [what what what] =+ hoon-type=(~(play ut sut) gen) ~? >>> debug hoon-type - =/ product-doc=what (docs-from-type hoon-type) + =/ product-doc=what (what-from-type hoon-type) ~? > debug product-doc :: if the arm builds a core, get the docs for the default arm :: in that core @@ -295,7 +301,7 @@ ?. ?=([%core *] hoon-type) ~? > debug %no-core-product ~ - (docs-from-type (~(play ut hoon-type) [%limb %$])) + (what-from-type (~(play ut hoon-type) [%limb %$])) :: if there is a product doc, then step through the hint and check for a core ?: ?=([%hint *] hoon-type) ~? > debug %step-through-hint @@ -304,13 +310,16 @@ =/ res (mule |.((~(play ut inner-type) [%limb %$]))) ?- -.res %| ~ - %& (docs-from-type p.res) + %& (what-from-type p.res) == ~ :: i think arm-doc and product-doc might always be the same :: upon further reflection, i think this is a limitation of the wrapping :: approach - ~? > debug :* %arm-doc arm-doc %product-doc product-doc %core-doc core-doc == + ~? > debug :* %arm-doc arm-doc + %product-doc product-doc + %core-doc core-doc + == :+ arm-doc product-doc core-doc :: :> returns an overview for a cores arms and chapters @@ -467,14 +476,14 @@ |= [name=tape docs=what gen=hoon sut=type] ^- tang ~? >> debug %print-arm - =+ [main-doc raw-doc product-doc]=(select-arm-docs docs gen sut) - %+ weld + =+ [main-doc product-doc core-doc]=(select-arm-docs docs gen sut) + ;: weld (print-header name main-doc) - :: ?~ product-doc - :: ~ - %+ weld - `tang`[[%leaf ""] [%leaf "product:"] ~] - (print-header "" product-doc) + `tang`[[%leaf ""] [%leaf "product:"] ~] + (print-header "" product-doc) + `tang`[[%leaf ""] [%leaf "default arm in core:"] ~] + (print-header "" core-doc) + == :: :> renders documentation for a face ++ print-face From edfcceb1d950a65409c48e7a3e29cbdfed4cb7f4 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Thu, 31 Mar 2022 18:45:28 -0400 Subject: [PATCH 059/715] doccords: dprint print overview also adds another mule to a play:ut call to avoid another crash that i'm not sure yet why it is happening --- pkg/arvo/lib/dprint.hoon | 61 ++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index b2b0272f0..243e06953 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -287,7 +287,7 @@ ~? >> debug %select-arm-docs ^- [what what what] =+ hoon-type=(~(play ut sut) gen) - ~? >>> debug hoon-type + ::~? >>> debug hoon-type =/ product-doc=what (what-from-type hoon-type) ~? > debug product-doc :: if the arm builds a core, get the docs for the default arm @@ -305,20 +305,28 @@ :: if there is a product doc, then step through the hint and check for a core ?: ?=([%hint *] hoon-type) ~? > debug %step-through-hint - =+ inner-type=(~(play ut q.hoon-type) gen) - :: using mule since it crashes if there's not a core - =/ res (mule |.((~(play ut inner-type) [%limb %$]))) - ?- -.res - %| ~ - %& (what-from-type p.res) + ::=+ inner-type=(~(play ut q.hoon-type) gen) + ::=/ res (mule |.((~(play ut inner-type) [%limb %$]))) + :: pretty sure having to use mule twice here means im doing something wrong + =/ h-res (mule |.((~(play ut q.hoon-type) gen))) + ?- -.h-res + %| + ~ + :: + %& + =/ in-res (mule |.((~(play ut p.h-res) [%limb %$]))) + ?- -.in-res + %| ~ + %& (what-from-type p.in-res) + == == ~ :: i think arm-doc and product-doc might always be the same :: upon further reflection, i think this is a limitation of the wrapping :: approach - ~? > debug :* %arm-doc arm-doc + ~? > debug :* %arm-doc arm-doc %product-doc product-doc - %core-doc core-doc + %core-doc core-doc == :+ arm-doc product-doc core-doc :: @@ -495,6 +503,7 @@ ~ (print-item u.children) :: +:> prints name and docs only ++ print-header |= [name=tape doc=what] ^- tang @@ -511,9 +520,39 @@ (print-sections q.u.doc) :: ++ print-overview - |= ovr=overview + |= =overview ^- tang - *tang + =| out=tang + |- + ?~ overview out + =/ oitem i.overview + ?- oitem + [%header *] + %= $ + overview t.overview + out ;: weld + out + ?~ doc.oitem ~ + `tang`[[%leaf ""] [%leaf "{(trip p.u.doc.oitem)}"] ~] + ?~ doc.oitem ~ + (print-sections q.u.doc.oitem) + ^$(overview children.oitem) + == + == + :: + [%item *] + %= $ + overview t.overview + out ;: weld + out + `tang`[[%leaf ""] [%leaf name.oitem] ~] + ?~ doc.oitem ~ + `tang`[[%leaf ""] [%leaf "{(trip p.u.doc.oitem)}"] ~] + ?~ doc.oitem ~ + (print-sections q.u.doc.oitem) + == + == + == :: :> renders a list of sections as tang :> From 531fd61ace550154ff8dfb1e2d8f1ebc96477a4f Mon Sep 17 00:00:00 2001 From: tomholford Date: Fri, 1 Apr 2022 06:59:39 -0700 Subject: [PATCH 060/715] ux: add info modal Add a new tab to the top bar that shows an alert with a brief usage guide. --- pkg/interface/webterm/App.tsx | 6 ++++- pkg/interface/webterm/InfoButton.tsx | 19 ++++++++++++++++ pkg/interface/webterm/Tabs.tsx | 8 ++++++- pkg/interface/webterm/index.html | 34 +++++++++++++++++++++++++++- 4 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 pkg/interface/webterm/InfoButton.tsx diff --git a/pkg/interface/webterm/App.tsx b/pkg/interface/webterm/App.tsx index 9ce3b0c00..c8dee297c 100644 --- a/pkg/interface/webterm/App.tsx +++ b/pkg/interface/webterm/App.tsx @@ -19,6 +19,7 @@ import { Tabs } from './Tabs'; import Buffer from './Buffer'; import { DEFAULT_SESSION } from './constants'; import { showSlog } from './lib/blit'; +import { InfoButton } from './InfoButton'; export default function TermApp() { const { names, selected } = useTermState(); @@ -78,7 +79,10 @@ export default function TermApp() { return ( <> - +
+ + +
{names.map((name) => { return ; diff --git a/pkg/interface/webterm/InfoButton.tsx b/pkg/interface/webterm/InfoButton.tsx new file mode 100644 index 000000000..4ec3a3347 --- /dev/null +++ b/pkg/interface/webterm/InfoButton.tsx @@ -0,0 +1,19 @@ +import React, { useCallback } from 'react'; +import { Icon } from '@tlon/indigo-react'; + +export const InfoButton = () => { + const onInfoClick = useCallback(() => { + alert('To select text in the terminal, hold down the alt key.'); + }, []); + + return ( + <> + + + ); +}; diff --git a/pkg/interface/webterm/Tabs.tsx b/pkg/interface/webterm/Tabs.tsx index 09751537a..3b0cd0a0f 100644 --- a/pkg/interface/webterm/Tabs.tsx +++ b/pkg/interface/webterm/Tabs.tsx @@ -2,6 +2,7 @@ import React from 'react'; import useTermState from './state'; import { Tab } from './Tab'; import { useAddSession } from './lib/useAddSession'; +import { Icon } from '@tlon/indigo-react'; export const Tabs = () => { const { sessions, names } = useTermState(); @@ -14,7 +15,12 @@ export const Tabs = () => { ); })} - +
); }; diff --git a/pkg/interface/webterm/index.html b/pkg/interface/webterm/index.html index e2f4a18c2..1ab870732 100644 --- a/pkg/interface/webterm/index.html +++ b/pkg/interface/webterm/index.html @@ -32,7 +32,19 @@ height: calc(100% - 40px); } + div.header { + display: grid; + grid-template-areas: "tabs info"; + grid-template-columns: auto min-content; + grid-template-rows: auto; + } + + div.info { + grid-area: info; + } + div.tabs { + grid-area: tabs; height: 40px; display: flex; flex-flow: row nowrap; @@ -71,6 +83,15 @@ padding: 5px; } + button.info-btn { + border: none; + border-bottom: solid black 1px; + background: transparent; + padding: 10px; + line-height: 10px; + cursor: pointer; + } + @media (prefers-color-scheme: dark) { div.tabs { background-color: rgb(26, 26, 26); @@ -78,14 +99,25 @@ border-bottom-color: rgba(255, 255, 255, 0.9); } - div.tab, button.tab { + div.tab { background-color: rgb(26, 26, 26); color: rgba(255, 255, 255, 0.9); border-color: rgba(255, 255, 255, 0.9); } + button.tab { + background-color: rgb(42, 42, 42); + color: rgba(255, 255, 255, 0.9); + border-color: rgba(255, 255, 255, 0.9); + } + div.tabs > div.selected { border-bottom: black solid 1px; + } + + button.info-btn { + border-bottom: solid rgba(255, 255, 255, 0.9) 1px; + background: rgb(26, 26, 26); } } From c5b07f520379614e183285cd437763bf4146ab2a Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 1 Apr 2022 22:15:34 +0200 Subject: [PATCH 061/715] term: batch simple input events into a single %txt By accumulating %txt events until we reach a more complex event or reach the end of the input buffer, we can significantly reduce the "overhead" of pasting text into the terminal. Instead of an event for each character, we now inject up to a buffer's worth of characters (currently, 123 bytes) at a time. This makes pasting process much faster. Incidentally, the behavior for pasting text with syntax errors into the dojo may be a little bit surprising: after every buffer boundary, the dojo will complain about the syntax error, moving the cursor to its location, and causing the remainder of the text to be inserted in that position. This may result in garbled-looking input in some cases. This ux problem should be resolved on dojo's end, perhaps by highlighting syntax errors with color, instead of the cursor. Alleviates most of the need for #5687. --- pkg/urbit/include/vere/vere.h | 9 ++++--- pkg/urbit/vere/io/term.c | 47 +++++++++++++++++++++++++---------- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/pkg/urbit/include/vere/vere.h b/pkg/urbit/include/vere/vere.h index 023635f35..3d7c0b030 100644 --- a/pkg/urbit/include/vere/vere.h +++ b/pkg/urbit/include/vere/vere.h @@ -158,10 +158,11 @@ c3_y col_y; // column coordinate } esc; - struct { - c3_y syb_y[5]; // utf8 code buffer - c3_w len_w; // present length - c3_w wid_w; // total width + struct { // input buffering + c3_y syb_y[5]; // utf8 code buffer + c3_w len_w; // present length + c3_w wid_w; // total width + u3_noun imp; // %txt input buffer } fut; struct { diff --git a/pkg/urbit/vere/io/term.c b/pkg/urbit/vere/io/term.c index 387e939ea..f4039bf8b 100644 --- a/pkg/urbit/vere/io/term.c +++ b/pkg/urbit/vere/io/term.c @@ -147,6 +147,7 @@ u3_term_log_init(void) uty_u->tat_u.fut.len_w = 0; uty_u->tat_u.fut.wid_w = 0; + uty_u->tat_u.fut.imp = u3_nul; } // default size @@ -636,9 +637,28 @@ _term_io_belt(u3_utty* uty_u, u3_noun blb) } } -/* _term_io_suck_char(): process a single character. +/* _term_io_spit(): input the buffer (if any), then input the belt (if any) */ static void +_term_io_spit(u3_utty* uty_u, u3_noun bet) { + u3_utat* tat_u = &uty_u->tat_u; + if (u3_nul != tat_u->fut.imp) { + _term_io_belt(uty_u, u3nc(c3__txt, u3kb_flop(tat_u->fut.imp))); + tat_u->fut.imp = u3_nul; + } + if (u3_none != bet) { + _term_io_belt(uty_u, bet); + } +} + +/* _term_io_suck_char(): process a single character. + * + * Note that this accumulates simple inputs in a buffer, and is not + * guaranteed to flush it fully. After a call (or sequence of calls) + * to this function, please call _term_io_spit(uty_u, u3_none) to + * flush any remainder. + */ +static void _term_io_suck_char(u3_utty* uty_u, c3_y cay_y) { u3_utat* tat_u = &uty_u->tat_u; @@ -652,10 +672,10 @@ _term_io_suck_char(u3_utty* uty_u, c3_y cay_y) _term_it_dump_buf(uty_u, &uty_u->ufo_u.bel_u); break; } - case 'A': _term_io_belt(uty_u, u3nc(c3__aro, 'u')); break; - case 'B': _term_io_belt(uty_u, u3nc(c3__aro, 'd')); break; - case 'C': _term_io_belt(uty_u, u3nc(c3__aro, 'r')); break; - case 'D': _term_io_belt(uty_u, u3nc(c3__aro, 'l')); break; + case 'A': _term_io_spit(uty_u, u3nc(c3__aro, 'u')); break; + case 'B': _term_io_spit(uty_u, u3nc(c3__aro, 'd')); break; + case 'C': _term_io_spit(uty_u, u3nc(c3__aro, 'r')); break; + case 'D': _term_io_spit(uty_u, u3nc(c3__aro, 'l')); break; // case 'M': tat_u->esc.mou = c3y; break; } @@ -667,13 +687,13 @@ _term_io_suck_char(u3_utty* uty_u, c3_y cay_y) // XX for backwards compatibility, check kelvin version // and fallback to [%met @c] // - _term_io_belt(uty_u, u3nt(c3__mod, c3__met, cay_y)); + _term_io_spit(uty_u, u3nt(c3__mod, c3__met, cay_y)); } else if ( 8 == cay_y || 127 == cay_y ) { tat_u->esc.ape = c3n; // XX backwards compatibility [%met @c] // - _term_io_belt(uty_u, u3nq(c3__mod, c3__met, c3__bac, u3_nul)); + _term_io_spit(uty_u, u3nq(c3__mod, c3__met, c3__bac, u3_nul)); } else if ( ('[' == cay_y) || ('O' == cay_y) ) { tat_u->esc.bra = c3y; @@ -698,7 +718,7 @@ _term_io_suck_char(u3_utty* uty_u, c3_y cay_y) c3_y row_y = cay_y - 32; // only acknowledge button 1 presses within our window if ( 1 != tat_u->esc.ton_y && row_y <= tat_u->siz.row_l ) { - _term_io_belt(uty_u, u3nt(c3__hit, + _term_io_spit(uty_u, u3nt(c3__hit, tat_u->esc.col_y - 1, tat_u->siz.row_l - row_y)); } @@ -720,28 +740,28 @@ _term_io_suck_char(u3_utty* uty_u, c3_y cay_y) wug = u3do("taft", huv); tat_u->fut.len_w = tat_u->fut.wid_w = 0; - _term_io_belt(uty_u, u3nt(c3__txt, wug, u3_nul)); + tat_u->fut.imp = u3nc(wug, tat_u->fut.imp); } } // individual characters // else { if ( (cay_y >= 32) && (cay_y < 127) ) { // visual ascii - _term_io_belt(uty_u, u3nt(c3__txt, cay_y, u3_nul)); + tat_u->fut.imp = u3nc(cay_y, tat_u->fut.imp); } else if ( 0 == cay_y ) { // null _term_it_dump_buf(uty_u, &uty_u->ufo_u.bel_u); } else if ( 8 == cay_y || 127 == cay_y ) { // backspace & delete - _term_io_belt(uty_u, u3nc(c3__bac, u3_nul)); + _term_io_spit(uty_u, u3nc(c3__bac, u3_nul)); } else if ( 10 == cay_y || 13 == cay_y ) { // newline & carriage return - _term_io_belt(uty_u, u3nc(c3__ret, u3_nul)); + _term_io_spit(uty_u, u3nc(c3__ret, u3_nul)); } else if ( cay_y <= 26 ) { // XX backwards compatibility [%ctl @c] // - _term_io_belt(uty_u, u3nt(c3__mod, c3__ctl, ('a' + (cay_y - 1)))); + _term_io_spit(uty_u, u3nt(c3__mod, c3__ctl, ('a' + (cay_y - 1)))); } else if ( 27 == cay_y ) { tat_u->esc.ape = c3y; @@ -799,6 +819,7 @@ _term_suck(u3_utty* uty_u, const c3_y* buf, ssize_t siz_i) for ( i=0; i < siz_i; i++ ) { _term_io_suck_char(uty_u, buf[i]); } + _term_io_spit(uty_u, u3_none); } } } From 064b15e5a01e3f466f33bd8bc87a00a9d838834c Mon Sep 17 00:00:00 2001 From: fang Date: Sun, 3 Apr 2022 21:38:09 +0200 Subject: [PATCH 062/715] term: move coordinate origin to top left Having the origin at the top left instead of the bottom left is more conventional and ergonomic. The only thing this complicates is prompt-specific logic, where we care about the coordinates of the bottom-most line on the screen. For that reason, the bulk of the changes here are in vere, where we treat the bottom-most line specially, drawing the spinner onto it. Webterm is likewise updated to account for the new coordinate system. Drum now opts to accept clicks anywhere on the screen, and does its best to move the cursor as close to the clicked location as possible (within the confines of the prompt). --- pkg/arvo/lib/hood/drum.hoon | 3 +-- pkg/interface/webterm/Buffer.tsx | 2 +- pkg/interface/webterm/lib/blit.ts | 2 +- pkg/urbit/vere/io/term.c | 29 ++++++++++++++--------------- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/pkg/arvo/lib/hood/drum.hoon b/pkg/arvo/lib/hood/drum.hoon index 39ceb90db..1914b69fa 100644 --- a/pkg/arvo/lib/hood/drum.hoon +++ b/pkg/arvo/lib/hood/drum.hoon @@ -687,10 +687,9 @@ ++ ta-hit :: hear click |= [x=@ud y=@ud] ^+ +> - ?. =(0 y) +> =/ pol=@ud (lent-char:klr (make:klr cad.pom)) - ?: (lth x pol) +>.$ + =? x (lth x pol) pol +>.$(pos.inp (min (sub x pol) (lent buf.say.inp))) :: ++ ta-erl :: hear local error diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx index 8d5ae2ce7..da4a8e8a6 100644 --- a/pkg/interface/webterm/Buffer.tsx +++ b/pkg/interface/webterm/Buffer.tsx @@ -90,7 +90,7 @@ const readInput = (term: Terminal, e: string): Belt[] => { if (1 === m) { const c = e.charCodeAt(2) - 32; const r = e.charCodeAt(3) - 32; - belts.push({ hit: { y: term.rows - r, x: c - 1 } }); + belts.push({ hit: { y: r - 1, x: c - 1 } }); } e = e.slice(3); break; diff --git a/pkg/interface/webterm/lib/blit.ts b/pkg/interface/webterm/lib/blit.ts index e98f8fe75..a34e75900 100644 --- a/pkg/interface/webterm/lib/blit.ts +++ b/pkg/interface/webterm/lib/blit.ts @@ -21,7 +21,7 @@ export const showBlit = (term: Terminal, blit: Blit) => { if (typeof blit.hop === 'number') { out += csi('H', term.rows, blit.hop + 1); } else { - out += csi('H', term.rows - blit.hop.y, blit.hop.x + 1); + out += csi('H', blit.hop.y + 1, blit.hop.x + 1); } out += csi('s'); // save cursor position } else if ('put' in blit) { diff --git a/pkg/urbit/vere/io/term.c b/pkg/urbit/vere/io/term.c index f4039bf8b..a653a6bcb 100644 --- a/pkg/urbit/vere/io/term.c +++ b/pkg/urbit/vere/io/term.c @@ -385,7 +385,7 @@ _term_it_clear_line(u3_utty* uty_u) // if we're clearing the bottom line, clear our mirror of it too // - if ( 0 == uty_u->tat_u.mir.rus_w ) { + if ( uty_u->tat_u.siz.row_l - 1 == uty_u->tat_u.mir.rus_w ) { _term_it_free_line(uty_u); } } @@ -401,7 +401,7 @@ _term_it_show_blank(u3_utty* uty_u) /* _term_it_move_cursor(): move cursor to row & column * - * row 0 is at the bottom, col 0 is to the left. + * row 0 is at the top, col 0 is to the left. * if the given position exceeds the known window size, * it is clipped to stay within the window. */ @@ -413,7 +413,7 @@ _term_it_move_cursor(u3_utty* uty_u, c3_w col_w, c3_w row_w) if ( row_w >= row_l ) { row_w = row_l - 1; } if ( col_w >= col_l ) { col_w = col_l - 1; } - _term_it_send_csi(uty_u, 'H', 2, row_l - row_w, col_w + 1); + _term_it_send_csi(uty_u, 'H', 2, row_w + 1, col_w + 1); _term_it_dump_buf(uty_u, &uty_u->ufo_u.suc_u); uty_u->tat_u.mir.rus_w = row_w; @@ -473,7 +473,7 @@ _term_it_restore_line(u3_utty* uty_u) { u3_utat* tat_u = &uty_u->tat_u; - _term_it_send_csi(uty_u, 'H', 2, tat_u->siz.row_l, 0); + _term_it_send_csi(uty_u, 'H', 2, tat_u->siz.row_l, 1); _term_it_dump_buf(uty_u, &uty_u->ufo_u.cel_u); _term_it_send_stub(uty_u, u3k(tat_u->mir.lin)); //NOTE send_stub restores cursor position @@ -490,7 +490,8 @@ _term_it_save_stub(u3_utty* uty_u, u3_noun tub) // keep track of changes to bottom-most line, to aid spinner drawing logic. // -t mode doesn't need this logic, because it doesn't render the spinner. // - if ( (0 == tat_u->mir.rus_w) && (c3n == u3_Host.ops_u.tem)) { + if ( ( tat_u->siz.row_l - 1 == tat_u->mir.rus_w ) && + ( c3n == u3_Host.ops_u.tem ) ) { lin = u3dq("wail:klr:format", lin, tat_u->mir.cus_w, u3k(tub), ' '); lin = u3do("pact:klr:format", lin); } @@ -513,8 +514,8 @@ _term_it_show_nel(u3_utty* uty_u) } uty_u->tat_u.mir.cus_w = 0; - if ( uty_u->tat_u.mir.rus_w > 0 ) { - uty_u->tat_u.mir.rus_w--; + if ( uty_u->tat_u.mir.rus_w < uty_u->tat_u.siz.row_l - 1 ) { + uty_u->tat_u.mir.rus_w++; } else { // newline at bottom of screen, so bottom line is now empty @@ -716,11 +717,9 @@ _term_io_suck_char(u3_utty* uty_u, c3_y cay_y) } else { c3_y row_y = cay_y - 32; - // only acknowledge button 1 presses within our window + // only acknowledge button 1 presses within our known window if ( 1 != tat_u->esc.ton_y && row_y <= tat_u->siz.row_l ) { - _term_io_spit(uty_u, u3nt(c3__hit, - tat_u->esc.col_y - 1, - tat_u->siz.row_l - row_y)); + _term_io_spit(uty_u, u3nt(c3__hit, tat_u->esc.col_y - 1, row_y - 1)); } tat_u->esc.mou = c3n; tat_u->esc.ton_y = tat_u->esc.col_y = 0; @@ -907,8 +906,8 @@ _term_spin_step(u3_utty* uty_u) // if we know where the bottom line is, and the cursor is not on it, // move it to the bottom left // - if ( tat_u->siz.row_l && tat_u->mir.rus_w > 0 ) { - _term_it_send_csi(uty_u, 'H', 2, tat_u->siz.row_l, 0); + if ( tat_u->siz.row_l && tat_u->mir.rus_w < tat_u->siz.row_l - 1 ) { + _term_it_send_csi(uty_u, 'H', 2, tat_u->siz.row_l, 1); } c3_w i_w; @@ -1357,7 +1356,7 @@ _term_ef_blit(u3_utty* uty_u, case c3__hop: { u3_noun pos = u3t(blt); if ( c3y == u3r_ud(pos) ) { - _term_it_move_cursor(uty_u, pos, 0); + _term_it_move_cursor(uty_u, pos, uty_u->tat_u.siz.row_l - 1); } else { _term_it_move_cursor(uty_u, u3h(pos), u3t(pos)); @@ -1369,7 +1368,7 @@ _term_ef_blit(u3_utty* uty_u, } break; case c3__lin: { //TMP backwards compatibility - _term_it_move_cursor(uty_u, 0, 0); + _term_it_move_cursor(uty_u, 0, uty_u->tat_u.siz.row_l - 1); _term_it_clear_line(uty_u); } // case c3__put: { From d3f9d7621799a57844469d097dfed2941bd0bd62 Mon Sep 17 00:00:00 2001 From: fang Date: Sun, 3 Apr 2022 21:44:05 +0200 Subject: [PATCH 063/715] term: move cursor to end before exit When urbit exits, the host shell it was running in takes over, often re-prints its own prompt. Here, we move the cursor to the bottom of the screen right before exiting, so that any subsequent output doesn't destroy whatever we had on-screen when we closed. --- pkg/urbit/vere/io/term.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/urbit/vere/io/term.c b/pkg/urbit/vere/io/term.c index a653a6bcb..7b3f7720e 100644 --- a/pkg/urbit/vere/io/term.c +++ b/pkg/urbit/vere/io/term.c @@ -1762,6 +1762,10 @@ _term_io_exit(u3_auto* car_u) // _term_it_dump_buf(uty_u, &uty_u->ufo_u.mof_u); + // move cursor to the end + // + _term_it_move_cursor(uty_u, 0, uty_u->tat_u.siz.row_l - 1); + // NB, closed in u3_term_log_exit() // uv_read_stop((uv_stream_t*)&(uty_u->pin_u)); From 0c255c1294b924c871179be553a24c3de2cd0604 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Fri, 25 Mar 2022 10:27:32 -0400 Subject: [PATCH 064/715] hoon: plug type leak in vase literals by properly burping %hint --- pkg/arvo/sys/hoon.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index 04607d81b..216642b53 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -9121,7 +9121,7 @@ == [%face *] [%face p.sut burp(sut q.sut)] [%fork *] [%fork (~(run in p.sut) |=(type burp(sut +<)))] - [%hint *] (hint p.sut burp(sut q.sut)) + [%hint *] (hint [burp(sut p.p.sut) q.p.sut] burp(sut q.sut)) [%hold *] [%hold burp(sut p.sut) q.sut] == :: From f7f4b3e7487364c7cff00d56cba5b18098fa2844 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Fri, 25 Mar 2022 10:28:05 -0400 Subject: [PATCH 065/715] hoon: preserve structural sharing by testing subject/product equality in +burp --- pkg/arvo/sys/hoon.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index 216642b53..59a4b2d4d 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -9107,7 +9107,7 @@ :: ^- type ~+ - ~= sut + =- ?.(=(sut -) - sut) ?+ sut sut [%cell *] [%cell burp(sut p.sut) burp(sut q.sut)] [%core *] :+ %core From 6a6078b5548d01fe3245a3756e69ce4bb59221db Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Mon, 4 Apr 2022 16:23:27 -0400 Subject: [PATCH 066/715] doccords: dprint core and chapter items adds the ability to find cores and chapters and produce an item from them --- pkg/arvo/lib/dprint.hoon | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index 243e06953..4b83d8d4a 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -52,9 +52,9 @@ == :: -- +:> # %dprint |% -:: arms for finding docs in types -::+| %searching ++| %searching :> returns the item to print while searching through topic :> :> this gate is called recursively to find the path (topic) in the type @@ -83,21 +83,22 @@ :: check that they're wrapped with a %hint type. so this just looks for :: docs on the arms. :: - :: cores also can't have names right now. %brcn and %brpt have a slot in - :: their AST for the name, but it doesn't end up in the their type. so - :: if i want core names right now, i'd have to look inside their AST, and - :: only |% and |@ cores would have names, which is silly. + =+ core-name=p.p.q.sut + ?: =(`topic core-name) + :: if core-name matches topic, return the core as a (unit item) + (signify sut) + =+ chapters=~(key by q.r.q.sut) + ?: (~(has in chapters) topic) + :: if there is a chapter with a name matching the topic, return chapter + :: as a (unit item) + =/ docs=what p:(~(got by q.r.q.sut) topic) + `[%chapter (trip topic) docs sut q.sut topic] =+ arm=(find-arm-in-coil topic q.sut) ?~ arm - :: the current topic is not an arm in the core + :: the current topic is not an arm in the core, recurse into type $(sut p.sut) - :: check to see if the arm is wrapped with a note - :: TODO: this is taking docs from the AST rather than the type. is that - :: the right thing to do here? =+ wat=(unwrap-note u.arm) `[%arm (trip topic) wat u.arm p.sut] - :: `[%arm (trip topic) wat u.arm q.q.sut] :: what's the difference if i use the type in the coil? - :: TODO: check for chapter docs :: [%face *] ?. ?=(term p.sut) @@ -174,9 +175,11 @@ $(sut q.sut) :: [%core *] - =/ name ~ :: should check if core is built with an arm and use that name? + =/ name=(unit term) p.p.q.sut :: should check if core is built with an arm and use that name? =* compiled-against $(sut p.sut) - `[%core (trip name) *what p.sut q.sut compiled-against] + ?~ name + `[%core ~ *what p.sut q.sut compiled-against] + `[%core (trip u.name) *what p.sut q.sut compiled-against] :: [%face *] ?. ?=(term p.sut) @@ -427,7 +430,7 @@ :: :> # %printing :: :> # :: :> functions which display output of various types -:: +| %printing ++| %printing :> prints a doccords item ++ print-item |= =item From 063e3ed716b1bae15a408461e16f5668e8c47dc6 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Tue, 5 Apr 2022 12:35:53 -0400 Subject: [PATCH 067/715] hoon: doccords dist. between arm-doc and prod-doc docs written above an arm are now distinguishable in the AST from docs written above the product of the arm, by tagging docs written above the arm with a %funk link --- pkg/arvo/sys/hoon.hoon | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index 59a4b2d4d..b114ceeb8 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -13288,10 +13288,15 @@ %+ knee [p=*term q=*hoon] |. ~+ %+ cook |= [a=whit b=term c=whit d=hoon] - =+ e=(glom a c) - ?~ boy.e - [b d] - [b [%note help+`[u.boy.e] d]] + ?~ boy.a :: no arm docs + ?~ boy.c :: no product docs + [b d] + :: product docs, no arm docs + [b [%note help+`[u.boy.c] d]] + ?~ boy.c :: arm docs, no product docs + [b [%note help+[[%funk b]~ u.boy.a] d]] + :: arm docs and product docs + [b [%note help+[[%funk b]~ u.boy.a] [%note help+`[u.boy.c] d]]] ;~ pose ;~ plug apex:docs From eb4b996420896815070c80df70ec99b207e6f063 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Tue, 5 Apr 2022 12:38:02 -0400 Subject: [PATCH 068/715] doccords: dprint can dist. arm-doc and prod-doc rewrites select-arm-docs so that it checks for nested hint types and sees if the outermost help hint has a %funk link with the name of the arm in order to tell that its an arm-doc --- pkg/arvo/lib/dprint.hoon | 115 ++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 50 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index 4b83d8d4a..ca3c87e82 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -95,7 +95,7 @@ `[%chapter (trip topic) docs sut q.sut topic] =+ arm=(find-arm-in-coil topic q.sut) ?~ arm - :: the current topic is not an arm in the core, recurse into type + :: the current topic is not an arm in the core, recurse into sut $(sut p.sut) =+ wat=(unwrap-note u.arm) `[%arm (trip topic) wat u.arm p.sut] @@ -135,7 +135,6 @@ ?~ itm ~ `(emblazon u.itm wat) -:: (emblazon (need (signify q.sut)) (unwrap-hint sut)) $(sut q.sut) :: [%hold *] $(sut (~(play ut p.sut) q.sut)) @@ -276,62 +275,79 @@ ?: ?=(%help -.q.p.sut) `crib.p.q.p.sut ~ == :: +:> returns 0, 1, or 2 whats for an arm +++ arm-product-docs + |= [sut=type name=tape] + ^- (unit [what what]) + =/ doc-one=(unit help) + ?: ?=([%hint [* [%help ^]] *] sut) + `p.q.p.sut + ~ + ?~ doc-one + :: no need to look for a second doc if there is no first one + ~ + =/ doc-two=(unit help) + ?> ?=([%hint *] sut) + ?: ?=([%hint [* [%help ^]] *] q.sut) + `p.q.p.q.sut + ~ + ?~ doc-two + ?~ links.u.doc-one + :: if links are empty, doc-one is a product-doc + [~ [~ `crib.u.doc-one]] + ?: =([%funk `@tas`(crip name)] i.links.u.doc-one) + :: if links are non-empty, check that the link is for the arm + [~ [`crib.u.doc-one ~]] + ~? > debug %link-doesnt-match-arm + :: this shouldn't happen at this point in time + [~ [`crib.u.doc-one ~]] + :: doc-two is non-empty. make sure that doc-one is an arm-doc + ?~ links.u.doc-one + ~? > debug %doc-one-empty-link + [~ [`crib.u.doc-one `crib.u.doc-two]] + [~ [`crib.u.doc-one `crib.u.doc-two]] +:: :> grabs the docs for an arm. :> :> there are three possible places with relevant docs for an arm: :> docs for the arm itself, docs for the product of the arm, and :> if the arm builds a core, docs for the default arm of that core. :> -:> arm-doc: docs wrapping the arm - this should have already been found +:> arm-doc: docs wrapping the arm :> product-doc: docs for the product of the arm :> core-doc: docs for the default arm of the core produced by the arm ++ select-arm-docs - |= [arm-doc=what gen=hoon sut=type] - ~? >> debug %select-arm-docs + |= [gen=hoon sut=type name=tape] + ~? > debug %select-arm-docs ^- [what what what] =+ hoon-type=(~(play ut sut) gen) - ::~? >>> debug hoon-type - =/ product-doc=what (what-from-type hoon-type) - ~? > debug product-doc - :: if the arm builds a core, get the docs for the default arm - :: in that core - :: - :: this is broken if it also has an arm-doc. if i have an arm-doc, i - :: need to strip off the first hint and then check if i have a core, i think - =/ core-doc=what - :: if product-doc is empty, just go right on and check if its a core - ?~ product-doc - ?. ?=([%core *] hoon-type) - ~? > debug %no-core-product - ~ - (what-from-type (~(play ut hoon-type) [%limb %$])) - :: if there is a product doc, then step through the hint and check for a core - ?: ?=([%hint *] hoon-type) - ~? > debug %step-through-hint - ::=+ inner-type=(~(play ut q.hoon-type) gen) - ::=/ res (mule |.((~(play ut inner-type) [%limb %$]))) - :: pretty sure having to use mule twice here means im doing something wrong - =/ h-res (mule |.((~(play ut q.hoon-type) gen))) - ?- -.h-res - %| - ~ - :: - %& - =/ in-res (mule |.((~(play ut p.h-res) [%limb %$]))) - ?- -.in-res - %| ~ - %& (what-from-type p.in-res) - == - == + =+ arm-prod=(arm-product-docs hoon-type name) + ~? >> debug arm-prod + ^- [what what what] + |^ + :: use arm-prod to determine how many layers to look into the type + :: for core docs + =/ depth=@ (add !=(~ +<.arm-prod) !=(~ +>.arm-prod)) + ^- [what what what] + ?+ depth [~ ~ ~] + %0 [~ ~ (check-core hoon-type)] + %1 :+ +<.arm-prod + +>.arm-prod + ?> ?=([%hint *] hoon-type) + (check-core q.hoon-type) + %2 :+ +<.arm-prod + +>.arm-prod + ?> ?=([%hint *] hoon-type) + ?> ?=([%hint *] q.hoon-type) + (check-core q.q.hoon-type) + == + ++ check-core + |= sut=type + ^- what + ?: ?=([%core *] sut) + (what-from-type (~(play ut sut) [%limb %$])) ~ - :: i think arm-doc and product-doc might always be the same - :: upon further reflection, i think this is a limitation of the wrapping - :: approach - ~? > debug :* %arm-doc arm-doc - %product-doc product-doc - %core-doc core-doc - == - :+ arm-doc product-doc core-doc + -- :: :> returns an overview for a cores arms and chapters :> @@ -383,13 +399,12 @@ :: :> translate a tome into an overview ++ arms-as-overview - :: currently this doesn't do anything until i implement arm-doc |= [a=(map term hoon) sut=type] ^- overview %+ turn ~(tap by a) |= ar=(pair term hoon) - =/ doc (select-arm-docs *what q.ar sut) :: *what should be from the hint wrapper - [%item (weld "++" (trip p.ar)) -.doc] + =+ [adoc pdoc cdoc]=(select-arm-docs q.ar sut (trip p.ar)) + [%item (weld "++" (trip p.ar)) adoc] :: :> changes an item into an overview ++ item-as-overview @@ -487,7 +502,7 @@ |= [name=tape docs=what gen=hoon sut=type] ^- tang ~? >> debug %print-arm - =+ [main-doc product-doc core-doc]=(select-arm-docs docs gen sut) + =+ [main-doc product-doc core-doc]=(select-arm-docs gen sut name) ;: weld (print-header name main-doc) `tang`[[%leaf ""] [%leaf "product:"] ~] From 151608d583ffb41df5ae5e50c7fca2240276899d Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Tue, 5 Apr 2022 14:44:47 -0400 Subject: [PATCH 069/715] doccords: dprint fix depth calculation stupid loobeans tripping me up --- pkg/arvo/lib/dprint.hoon | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index ca3c87e82..64cccc183 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -323,12 +323,11 @@ =+ hoon-type=(~(play ut sut) gen) =+ arm-prod=(arm-product-docs hoon-type name) ~? >> debug arm-prod - ^- [what what what] |^ - :: use arm-prod to determine how many layers to look into the type + :: check arm-prod to determine how many layers to look into the type :: for core docs - =/ depth=@ (add !=(~ +<.arm-prod) !=(~ +>.arm-prod)) - ^- [what what what] + =/ depth=@ ?~ arm-prod 0 + (add =(~ +<.arm-prod) =(~ +>.arm-prod)) ?+ depth [~ ~ ~] %0 [~ ~ (check-core hoon-type)] %1 :+ +<.arm-prod From 6f32d107fc737bf1f39e7e5605aa4d8dec71633b Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Tue, 5 Apr 2022 14:45:51 -0400 Subject: [PATCH 070/715] hoon: doccords wrap tisfas fix I didn't know what I was doing before, I think this is the right way to wrap tisfas with a %note hoon. --- pkg/arvo/sys/hoon.hoon | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index b114ceeb8..b1698487a 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -8242,10 +8242,7 @@ :: :: tis runes [%tsfs *] - ?~ boy.wit - gen - [%tsfs [%help `u.boy.wit p.gen] q.gen r.gen] -:: [%tsfs help+`u.boy.wit p.gen q.gen r.gen] + wrap-boy == :: ++ wrap-boy From 37a787970ca5876fa27f54b926fa0683d5382fde Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Tue, 5 Apr 2022 15:17:57 -0400 Subject: [PATCH 071/715] doccords: dprint refactoring and renaming --- pkg/arvo/lib/dprint.hoon | 105 +++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 42 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index 64cccc183..5b854fbb6 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -256,56 +256,76 @@ $(tomes t.tomes) `u.gen :: -:> gets the documentation inside of a type -++ what-from-type - :> testing +:> gets the documentation inside of a hint, or a hold that plays to a hint +++ what-from-hint |= sut=type ^- what ?+ sut ~ - :: - [%core *] - ~? >> debug %what-from-type-core ~ :: should this get the chapter docs? :: [%hold *] - ~? >> debug %what-from-type-hold $(sut (~(play ut p.sut) q.sut)) + ~? >> debug %what-from-hint-hold $(sut (~(play ut p.sut) q.sut)) :: [%hint *] - ~? >> debug :- %what-from-type-hint -.q.p.sut + ~? >> debug :- %what-from-hint-hint -.q.p.sut ?: ?=(%help -.q.p.sut) `crib.p.q.p.sut ~ == +:> gets the $help from a %help %hint type and returns it as a unit +++ help-from-hint + |= sut=type + ^- (unit help) + ?+ sut ~ + [%hold *] + ~? >> debug %help-from-hold $(sut (~(play ut p.sut) q.sut)) + :: + [%hint *] + ~? >> debug %help-from-hint + ?. ?=(%help -.q.p.sut) + ~ + (some p.q.p.sut) + == :: :> returns 0, 1, or 2 whats for an arm +:> +:> this arm should be handed the compiled type of the hoon of an arm, as well +:> as the name of that arm. it checks for up to 2 nested hints on the outermost +:> layer of the type. if you have 2, it is presumed to be arm-doc followed by +:> product-doc. if you only have one, we check links in the $help of the hint +:> to determine whether it is an arm doc or product doc. +:> +:> this returns ~ if there are no docs. if there are docs, the first one is the +:> arm-doc, and the second one is the product-doc. ++ arm-product-docs - |= [sut=type name=tape] + |= [sut=type name=term] ^- (unit [what what]) =/ doc-one=(unit help) - ?: ?=([%hint [* [%help ^]] *] sut) - `p.q.p.sut - ~ + (help-from-hint sut) ?~ doc-one - :: no need to look for a second doc if there is no first one - ~ + ~? > debug %doc-one-empty + ~ :: no need to look for a second doc if there is no first one + :: technically doc-two doesn't need to be a help, i could just grab the what + :: directly since we aren't testing it to see if its an arm-doc, but it makes + :: the code more confusing to use a different structure. =/ doc-two=(unit help) ?> ?=([%hint *] sut) - ?: ?=([%hint [* [%help ^]] *] q.sut) - `p.q.p.q.sut - ~ + (help-from-hint q.sut) ?~ doc-two + ~? > debug %doc-two-empty ?~ links.u.doc-one :: if links are empty, doc-one is a product-doc - [~ [~ `crib.u.doc-one]] - ?: =([%funk `@tas`(crip name)] i.links.u.doc-one) + [~ [~ (some crib.u.doc-one)]] + ?: =([%funk name] i.links.u.doc-one) :: if links are non-empty, check that the link is for the arm - [~ [`crib.u.doc-one ~]] + ~? > debug %link-match + [~ [(some crib.u.doc-one) ~]] ~? > debug %link-doesnt-match-arm :: this shouldn't happen at this point in time - [~ [`crib.u.doc-one ~]] + [~ [(some crib.u.doc-one) ~]] :: doc-two is non-empty. make sure that doc-one is an arm-doc ?~ links.u.doc-one ~? > debug %doc-one-empty-link - [~ [`crib.u.doc-one `crib.u.doc-two]] - [~ [`crib.u.doc-one `crib.u.doc-two]] + [~ [(some crib.u.doc-one) (some crib.u.doc-two)]] + [~ [(some crib.u.doc-one) (some crib.u.doc-two)]] :: :> grabs the docs for an arm. :> @@ -313,38 +333,42 @@ :> docs for the arm itself, docs for the product of the arm, and :> if the arm builds a core, docs for the default arm of that core. :> -:> arm-doc: docs wrapping the arm +:> arm-doc: docs written above the the arm :> product-doc: docs for the product of the arm :> core-doc: docs for the default arm of the core produced by the arm -++ select-arm-docs +++ all-arm-docs |= [gen=hoon sut=type name=tape] - ~? > debug %select-arm-docs + ~? > debug %all-arm-docs ^- [what what what] =+ hoon-type=(~(play ut sut) gen) - =+ arm-prod=(arm-product-docs hoon-type name) + =+ arm-prod=(arm-product-docs hoon-type `@tas`(crip name)) ~? >> debug arm-prod |^ :: check arm-prod to determine how many layers to look into the type :: for core docs =/ depth=@ ?~ arm-prod 0 (add =(~ +<.arm-prod) =(~ +>.arm-prod)) - ?+ depth [~ ~ ~] - %0 [~ ~ (check-core hoon-type)] + ?+ depth ``~ + %0 ``(extract hoon-type) %1 :+ +<.arm-prod +>.arm-prod ?> ?=([%hint *] hoon-type) - (check-core q.hoon-type) + (extract q.hoon-type) %2 :+ +<.arm-prod +>.arm-prod ?> ?=([%hint *] hoon-type) ?> ?=([%hint *] q.hoon-type) - (check-core q.q.hoon-type) + (extract q.q.hoon-type) == - ++ check-core + :> grabs the first doc for the default arm of a core + :> + :> this could end up being an arm doc or a product doc. or it might even + :> produce another core with docs in that. should I care? + ++ extract |= sut=type ^- what ?: ?=([%core *] sut) - (what-from-type (~(play ut sut) [%limb %$])) + (what-from-hint (~(play ut sut) [%limb %$])) ~ -- :: @@ -402,7 +426,7 @@ ^- overview %+ turn ~(tap by a) |= ar=(pair term hoon) - =+ [adoc pdoc cdoc]=(select-arm-docs q.ar sut (trip p.ar)) + =+ [adoc pdoc cdoc]=(all-arm-docs q.ar sut (trip p.ar)) [%item (weld "++" (trip p.ar)) adoc] :: :> changes an item into an overview @@ -440,10 +464,7 @@ ?~ lhs rhs ?~ rhs lhs `[%view (weld (item-as-overview lhs) (item-as-overview rhs))] -:: :> # -:: :> # %printing -:: :> # -:: :> functions which display output of various types +:: +| %printing :> prints a doccords item ++ print-item @@ -501,13 +522,13 @@ |= [name=tape docs=what gen=hoon sut=type] ^- tang ~? >> debug %print-arm - =+ [main-doc product-doc core-doc]=(select-arm-docs gen sut name) + =+ [adoc pdoc cdoc]=(all-arm-docs gen sut name) ;: weld - (print-header name main-doc) + (print-header name adoc) `tang`[[%leaf ""] [%leaf "product:"] ~] - (print-header "" product-doc) + (print-header "" pdoc) `tang`[[%leaf ""] [%leaf "default arm in core:"] ~] - (print-header "" core-doc) + (print-header "" cdoc) == :: :> renders documentation for a face From 3afc9b6899ae32ff0aa3f130f60140147c850fd7 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Tue, 5 Apr 2022 15:52:35 -0400 Subject: [PATCH 072/715] doccords: dprint all docs in %arm items from type before this, it was grabbing the initial arm-doc from the AST rather than the type. now %arm items have all 3 types of docs available. the interface has been degraded somewhat though, as %arm items no longer have a single docs field. more refactoring will be needed to figure out the best way to do this. --- pkg/arvo/lib/dprint.hoon | 54 +++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index 5b854fbb6..bf95e6012 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -31,7 +31,9 @@ :: inspecting a single arm on a core $: %arm name=tape - docs=what + adoc=what + pdoc=what + cdoc=what gen=hoon sut=type == @@ -97,8 +99,8 @@ ?~ arm :: the current topic is not an arm in the core, recurse into sut $(sut p.sut) - =+ wat=(unwrap-note u.arm) - `[%arm (trip topic) wat u.arm p.sut] + =+ [adoc pdoc cdoc]=(all-arm-docs u.arm p.sut (trip topic)) + `[%arm (trip topic) adoc pdoc cdoc u.arm p.sut] :: [%face *] ?. ?=(term p.sut) @@ -129,12 +131,15 @@ :: TODO: should i be trying to match both types in the hint? :: TODO: actually hints can be nested, if e.g. an arm has a product with a hint, whose :: product also has a hint. so this won't actually work for nested hints as written + :: + :: this should only be doing something for cores right now. you run into an + :: arm's name before you run into its docs ?: (shallow-match topic q.sut) =/ wat=what (unwrap-hint sut) - =/ itm=(unit item) (signify q.sut) - ?~ itm + =/ uitm=(unit item) (signify q.sut) + ?~ uitm ~ - `(emblazon u.itm wat) + `(emblazon u.uitm wat) $(sut q.sut) :: [%hold *] $(sut (~(play ut p.sut) q.sut)) @@ -224,22 +229,15 @@ :: :> inserts docs into an item :> -:> most docs are going to be found in hint types wrapping another type. when -:> we come across a hint, we grab the docs from the hint and then build the -:> item for the type it wrapped. since building an item is handled separately, -:> this item will initially have no docs in it, so we add it in after with this -:> -:> the exceptions to this are %chapter and %view items. chapters have an axis -:> for docs in their $tome structure, and %views are summaries of several types +:> when matching for a core or a face type, the docs for that type will be in +:> a hint that wraps it. thus we end up producing an item for that type, then +:> need to add the docs to it. ++ emblazon |= [=item =what] ~? >> debug %emblazon ^+ item - ?+ item item :: no-op on %chapter and %view - ?([%core *] [%arm *] [%face *]) ?~ docs.item - item(docs what) - ~? > debug %docs-in-item - item(docs what) + ?+ item item :: no-op on %chapter, %arm, $view + ?([%core *] [%face *]) item(docs what) == :: :> looks for an arm in a coil and returns its hoon @@ -282,7 +280,7 @@ ~? >> debug %help-from-hint ?. ?=(%help -.q.p.sut) ~ - (some p.q.p.sut) + `p.q.p.sut == :: :> returns 0, 1, or 2 whats for an arm @@ -313,19 +311,19 @@ ~? > debug %doc-two-empty ?~ links.u.doc-one :: if links are empty, doc-one is a product-doc - [~ [~ (some crib.u.doc-one)]] + [~ [~ `crib.u.doc-one]] ?: =([%funk name] i.links.u.doc-one) :: if links are non-empty, check that the link is for the arm ~? > debug %link-match - [~ [(some crib.u.doc-one) ~]] + [~ [`crib.u.doc-one ~]] ~? > debug %link-doesnt-match-arm :: this shouldn't happen at this point in time - [~ [(some crib.u.doc-one) ~]] + [~ [`crib.u.doc-one ~]] :: doc-two is non-empty. make sure that doc-one is an arm-doc ?~ links.u.doc-one ~? > debug %doc-one-empty-link - [~ [(some crib.u.doc-one) (some crib.u.doc-two)]] - [~ [(some crib.u.doc-one) (some crib.u.doc-two)]] + [~ [`crib.u.doc-one `crib.u.doc-two]] + [~ [`crib.u.doc-one `crib.u.doc-two]] :: :> grabs the docs for an arm. :> @@ -446,7 +444,7 @@ (item-as-overview children.itm) :: [%arm *] - [%item name.itm docs.itm]~ + [%item name.itm adoc.itm]~ :: [%chapter *] [%item name.itm docs.itm]~ @@ -484,8 +482,7 @@ ^- tang =+ [arms chapters]=(arm-and-chapter-overviews sut con name) ;: weld - :: cores don't have names - (print-header *tape *what) + (print-header name docs) :: ?~ arms ~ @@ -519,10 +516,9 @@ :: :> renders documentation for a single arm in a core ++ print-arm - |= [name=tape docs=what gen=hoon sut=type] + |= [name=tape adoc=what pdoc=what cdoc=what gen=hoon sut=type] ^- tang ~? >> debug %print-arm - =+ [adoc pdoc cdoc]=(all-arm-docs gen sut name) ;: weld (print-header name adoc) `tang`[[%leaf ""] [%leaf "product:"] ~] From 69399c4153075317a9121ac4941486cecbff4e63 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Tue, 5 Apr 2022 15:55:42 -0400 Subject: [PATCH 073/715] doccords: remove unwrap-note from dprint we shouldn't be getting docs from the AST, so this should never be needed --- pkg/arvo/lib/dprint.hoon | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index bf95e6012..34bacf745 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -206,16 +206,6 @@ %noun ~ %void ~ == - -:> checks if a hoon is wrapped with a help note, and returns it if so -++ unwrap-note - |= gen=hoon - ^- what - ?: ?=([%note *] gen) - ?: ?=([%help *] p.gen) - `crib.p.p.gen - ~ - ~ :: :> checks if a hint type is a help hint and returns the docs if so ++ unwrap-hint From 877fe0059e7aec696510f0b85434d907b03a25f8 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Wed, 6 Apr 2022 14:02:25 -0400 Subject: [PATCH 074/715] dojo: add command to lookup doccords syntax: `# foo` to look up foo. this is not the final form - it does not support `# foo:bar` yet. the dprint library needs some changes first. --- pkg/arvo/app/dojo.hoon | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/pkg/arvo/app/dojo.hoon b/pkg/arvo/app/dojo.hoon index b127a3ce0..8b6674f60 100644 --- a/pkg/arvo/app/dojo.hoon +++ b/pkg/arvo/app/dojo.hoon @@ -3,7 +3,7 @@ :: :: :: /? 309 :: arvo kelvin /- *sole, lens :: console structures -/+ sole, pprint, :: +/+ sole, pprint, dprint, :: auto=language-server-complete, :: easy-print=language-server-easy-print :: :: :: :: @@ -54,6 +54,7 @@ r=@t == [%poke p=goal] :: poke app + [%help p=term] :: doccords [%show p=?(%0 %1 %2 %3 %4 %5)] :: val/type/hoon/xray [%verb p=term] :: store variable == :: @@ -178,6 +179,18 @@ (parse-variable (cold %lib lus) ;~(pfix gap parse-cables)) == == + :: + ;~ pfix hax + ;~ pose + ;~ pfix ace + %+ cook + |= a=term + [[%help a] 0 %ex [%cnts p=~[[%.y p=1]] q=~]] + sym :: should be (most col sym) once i switch to (list term) + == + (easy [[%help %$] 0 %ex [%cnts p=~[[%.y p=1]] q=~]]) + == + == :: ;~((glue ace) parse-sink parse-source) (stag [%show %0] parse-source) @@ -624,6 +637,9 @@ ++ maar ?: =(%noun p.cay) ~ [[%rose [~ " " ~] >p.cay< ~] ~] -- + :: + %help + (dy-inspect p.p.mad p.q.cay) == :: ++ dy-show |=(cay=cage (dy-print cay ~)) @@ -663,6 +679,15 @@ :- i="" t=(turn `wain`?~(r.hit ~ (to-wain:format q.u.r.hit)) trip) == + :: + ++ dy-inspect + |= [topic=term sut=type] + %+ dy-rash %tan + =+ to-display=(find-item-in-type:dprint topic sut) + ?~ to-display + [%leaf "Could not find help"]~ + (print-item:dprint u.to-display) + :: ++ dy-show-type-noun |= a=type ^- tank =- >[-]< From 912a5023bbecc4ce41ae6eafcc2e96b8d8b0c66a Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Wed, 6 Apr 2022 14:58:28 -0400 Subject: [PATCH 075/715] doccords: flop order of +print-arm results --- pkg/arvo/lib/dprint.hoon | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index 34bacf745..eac96902a 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -509,6 +509,7 @@ |= [name=tape adoc=what pdoc=what cdoc=what gen=hoon sut=type] ^- tang ~? >> debug %print-arm + %- flop ;: weld (print-header name adoc) `tang`[[%leaf ""] [%leaf "product:"] ~] From 33b2761b39ce94962129ffc771ea4e4e470cc97b Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Wed, 6 Apr 2022 15:50:23 -0400 Subject: [PATCH 076/715] doccords, dojo: move flop print-arm -> dy-inspect this looks more sensible --- pkg/arvo/app/dojo.hoon | 2 +- pkg/arvo/lib/dprint.hoon | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/arvo/app/dojo.hoon b/pkg/arvo/app/dojo.hoon index 8b6674f60..c5a00ba46 100644 --- a/pkg/arvo/app/dojo.hoon +++ b/pkg/arvo/app/dojo.hoon @@ -686,7 +686,7 @@ =+ to-display=(find-item-in-type:dprint topic sut) ?~ to-display [%leaf "Could not find help"]~ - (print-item:dprint u.to-display) + (flop (print-item:dprint u.to-display)) :: ++ dy-show-type-noun |= a=type ^- tank diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index eac96902a..34bacf745 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -509,7 +509,6 @@ |= [name=tape adoc=what pdoc=what cdoc=what gen=hoon sut=type] ^- tang ~? >> debug %print-arm - %- flop ;: weld (print-header name adoc) `tang`[[%leaf ""] [%leaf "product:"] ~] From 2a57e85a091d0406a1bd17ad942ea62134d4f9a9 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Wed, 6 Apr 2022 16:27:07 -0400 Subject: [PATCH 077/715] hoon: comment out %note entry in +open this was wiping out some comments buried that weren't written at the top of an arm. not sure if this is used in another fashion that will create issues, so I just commented it out to help remember that it used to be there in case it needs further changes, like if I should actually skip %know and %made notes but not %help notes --- pkg/arvo/sys/hoon.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/sys/hoon.hoon b/pkg/arvo/sys/hoon.hoon index b1698487a..ad1d68ff6 100644 --- a/pkg/arvo/sys/hoon.hoon +++ b/pkg/arvo/sys/hoon.hoon @@ -8450,7 +8450,7 @@ [%tell *] [%cncl [%limb %noah] [%zpgr [%cltr p.gen]] ~] [%wing *] [%cnts p.gen ~] [%yell *] [%cncl [%limb %cain] [%zpgr [%cltr p.gen]] ~] - [%note *] q.gen + ::[%note *] q.gen :: [%brbc *] =- ?~ - !! [%brtr [%bccl -] [%ktcl body.gen]] From 0e8cf3bbfa5d300cff3ae9b03bbd6e7ab8d5e220 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Wed, 6 Apr 2022 16:34:02 -0400 Subject: [PATCH 078/715] doccords: dprint improve default arm core docs the logic for getting the docs on the default arm of a core is now more similar to how other arm docs are gotten, rather than having its own system. there is still more room for improvement --- pkg/arvo/lib/dprint.hoon | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index 34bacf745..f465ac2a9 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -324,13 +324,16 @@ :> arm-doc: docs written above the the arm :> product-doc: docs for the product of the arm :> core-doc: docs for the default arm of the core produced by the arm +:> this will be the first of the arm-doc or product-doc on the default +:> arm. maybe this should be recursive and/or give both but its a decision +:> ill leave for later ++ all-arm-docs |= [gen=hoon sut=type name=tape] ~? > debug %all-arm-docs ^- [what what what] =+ hoon-type=(~(play ut sut) gen) =+ arm-prod=(arm-product-docs hoon-type `@tas`(crip name)) - ~? >> debug arm-prod + ~? >> debug :- %arm-prod arm-prod |^ :: check arm-prod to determine how many layers to look into the type :: for core docs @@ -350,14 +353,18 @@ == :> grabs the first doc for the default arm of a core :> - :> this could end up being an arm doc or a product doc. or it might even - :> produce another core with docs in that. should I care? + :> this could end up being an arm doc or a product doc. ++ extract |= sut=type ^- what - ?: ?=([%core *] sut) - (what-from-hint (~(play ut sut) [%limb %$])) - ~ + ?. ?=([%core *] sut) + ~? > debug %no-nested-core ~ + ~? > debug %found-nested-core + =+ carm=(find-arm-in-coil %$ q.sut) + ?~ carm ~? > debug %empty-carm ~ + ~? > debug %found-default-arm + =+ carm-type=(~(play ut p.sut) u.carm) + (what-from-hint carm-type) -- :: :> returns an overview for a cores arms and chapters From 7a94319af3933c025974e6e73bbb268d590344e3 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Wed, 6 Apr 2022 17:37:55 -0400 Subject: [PATCH 079/715] dojo, doccords: dprint library can take list term this allows you to search for foo:bar instead of just foo --- pkg/arvo/app/dojo.hoon | 12 +++--- pkg/arvo/lib/dprint.hoon | 85 +++++++++++++++++++++++++--------------- 2 files changed, 60 insertions(+), 37 deletions(-) diff --git a/pkg/arvo/app/dojo.hoon b/pkg/arvo/app/dojo.hoon index c5a00ba46..9363ab4b7 100644 --- a/pkg/arvo/app/dojo.hoon +++ b/pkg/arvo/app/dojo.hoon @@ -54,7 +54,7 @@ r=@t == [%poke p=goal] :: poke app - [%help p=term] :: doccords + [%help p=(list term)] :: doccords [%show p=?(%0 %1 %2 %3 %4 %5)] :: val/type/hoon/xray [%verb p=term] :: store variable == :: @@ -184,11 +184,11 @@ ;~ pose ;~ pfix ace %+ cook - |= a=term + |= a=(list term) [[%help a] 0 %ex [%cnts p=~[[%.y p=1]] q=~]] - sym :: should be (most col sym) once i switch to (list term) + (most col sym) == - (easy [[%help %$] 0 %ex [%cnts p=~[[%.y p=1]] q=~]]) + (easy [[%help ~[%$]] 0 %ex [%cnts p=~[[%.y p=1]] q=~]]) == == :: @@ -681,9 +681,9 @@ == :: ++ dy-inspect - |= [topic=term sut=type] + |= [topics=(list term) sut=type] %+ dy-rash %tan - =+ to-display=(find-item-in-type:dprint topic sut) + =+ to-display=(find-item-in-type:dprint topics sut %.y) ?~ to-display [%leaf "Could not find help"]~ (flop (print-item:dprint u.to-display)) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index f465ac2a9..b409978fc 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -59,16 +59,17 @@ +| %searching :> returns the item to print while searching through topic :> -:> this gate is called recursively to find the path (topic) in the type -:> (sut). once it finds the correct part of the type, it switches to -:> +signify to describe that part of the type +:> this gate is optionally called recursively to find the path (topic) in the +:> type (sut). once it finds the correct part of the type, it switches to +:> +signify to describe that part of the type. recursion is turned off (for some +:> cases) when a hint type is found, in case it is wrapping a match. ++ find-item-in-type :: TODO make this work with a list of topics - |= [topic=term sut=type] + |= [topics=(list term) sut=type rec=?] ^- (unit item) - :: ?~ topics - :: :: we have no more search paths TODO: return the rest as an overview - :: (signify sut) + ?~ topics + :: we have no more search paths, return an overview of what remains + (signify sut) ?- sut %noun ~ %void ~ @@ -77,6 +78,7 @@ [%cell *] =+ lhs=$(sut p.sut) ?~ lhs + :: not sure if this should recurse when rec=%.n $(sut q.sut) lhs :: @@ -86,31 +88,47 @@ :: docs on the arms. :: =+ core-name=p.p.q.sut - ?: =(`topic core-name) - :: if core-name matches topic, return the core as a (unit item) - (signify sut) + ?: !=(`i.topics core-name) + :: the current topic isn't the top level core name + :: else, look for an arm matching the name + =+ arm=(find-arm-in-coil i.topics q.sut) + ?~ arm + :: the current topic is not an arm in the core, recurse into sut + ?:(rec $(sut p.sut) ~) + ::$(sut p.sut) + :: else, return the arm as docs + =+ [adoc pdoc cdoc]=(all-arm-docs u.arm p.sut (trip i.topics)) + `[%arm (trip i.topics) adoc pdoc cdoc u.arm p.sut] + :: the core name matches. check to see if there are any topics left + ?~ t.topics + :: we matched the core name and have no further topics. return the core + =* compiled-against (signify p.sut) + `[%core (trip i.topics) *what p.sut q.sut compiled-against] + :: we matched the core name, but there are still topics left + :: check to see if one the chapters matches the next topic =+ chapters=~(key by q.r.q.sut) - ?: (~(has in chapters) topic) - :: if there is a chapter with a name matching the topic, return chapter - :: as a (unit item) - =/ docs=what p:(~(got by q.r.q.sut) topic) - `[%chapter (trip topic) docs sut q.sut topic] - =+ arm=(find-arm-in-coil topic q.sut) - ?~ arm - :: the current topic is not an arm in the core, recurse into sut - $(sut p.sut) - =+ [adoc pdoc cdoc]=(all-arm-docs u.arm p.sut (trip topic)) - `[%arm (trip topic) adoc pdoc cdoc u.arm p.sut] + ?. (~(has in chapters) i.t.topics) + :: the core name matched, but nothing inside of it did. return null + ~ + :: if there is a chapter with a name matching the topic, return chapter + :: as a (unit item) + =/ docs=what p:(~(got by q.r.q.sut) i.topics) + `[%chapter (trip i.topics) docs sut q.sut i.topics] :: [%face *] ?. ?=(term p.sut) :: TODO: handle tune case ~ - ?. =(topic p.sut) + ?. =(i.topics p.sut) :: this face has a name, but not the one we're looking for ~ - :: faces need to be checked to see if they're wrapped - ~ + ?~ t.topics + :: we found a match, and there are no further topics + :: this might have been wrapped with a hint type, that case will handle + :: docs for this face + `[%face (trip p.sut) *what (signify q.sut)] + :: the first topic matched the face, but there are more left. + ?:(rec $(topics t.topics, sut q.sut) ~) :: [%fork *] =/ types=(list type) ~(tap in p.sut) @@ -134,13 +152,18 @@ :: :: this should only be doing something for cores right now. you run into an :: arm's name before you run into its docs - ?: (shallow-match topic q.sut) - =/ wat=what (unwrap-hint sut) - =/ uitm=(unit item) (signify q.sut) - ?~ uitm - ~ - `(emblazon u.uitm wat) - $(sut q.sut) + :: + ::?: (shallow-match i.topics q.sut) + =/ shallow-match=(unit item) $(sut q.sut, rec %.n) + ?~ shallow-match + :: hint isn't wrapping a match, so step through it + $(sut q.sut, rec %.y) + :: hint was wrapping a match, so signify the type and emblazon it + :: =/ wat=what (unwrap-hint sut) + `(emblazon u.shallow-match (unwrap-hint sut)) + ::=/ uitm=(unit item) (signify q.sut) + ::?~ uitm + :: ~ :: [%hold *] $(sut (~(play ut p.sut) q.sut)) :: From 7d8fabe6cff150a05081c15e55c2b40de086334e Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Thu, 7 Apr 2022 11:54:33 -0400 Subject: [PATCH 080/715] doccords: dprint remove +shallow-match it was factored into +find-item-in-type --- pkg/arvo/lib/dprint.hoon | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index b409978fc..5ae38811c 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -169,22 +169,6 @@ :: == :: -:> non-recursive check to see if type matches search -:> -:> this is for applying help hints to types when searching for a match. hints -:> are only for the type theyre immediately wrapping, not something nested -:> deeper, so we dont always want to recurse -++ shallow-match - |= [topic=term sut=type] - ^- ? - ?+ sut %.n - [%atom *] %.n :: should we allow doccords on individual atoms? i think they should be for faces - [%core *] !=(~ (find ~[topic] (sloe sut))) - [%face *] ?. ?=(term p.sut) - %.n :: TODO: handle tune case - =(topic p.sut) - == -:: :> changes a type into a item :> :> this does not actually assign the docs, since they usually come from a hint From b41b22ab70941eb5fdcf040df20b189740df30e8 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Thu, 7 Apr 2022 12:42:55 -0400 Subject: [PATCH 081/715] doccords: dprint fix chapter printing --- pkg/arvo/lib/dprint.hoon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index 5ae38811c..377d74903 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -112,8 +112,8 @@ ~ :: if there is a chapter with a name matching the topic, return chapter :: as a (unit item) - =/ docs=what p:(~(got by q.r.q.sut) i.topics) - `[%chapter (trip i.topics) docs sut q.sut i.topics] + =/ docs=what p:(~(got by q.r.q.sut) i.t.topics) + `[%chapter (trip i.t.topics) docs sut q.sut i.t.topics] :: [%face *] ?. ?=(term p.sut) From b0230086ce4db18c209ae4e7e98b67c5a88ca22c Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Thu, 7 Apr 2022 12:55:30 -0400 Subject: [PATCH 082/715] doccords: dprint chapter and overview print tweak printing an overview only gives the summary now, not the details. also fixed chapter printing so that it doesn't print the details twice --- pkg/arvo/lib/dprint.hoon | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index 377d74903..f4bd522c7 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -56,6 +56,9 @@ -- :> # %dprint |% +:> contains arms used for looking for docs inside of a type +:> +:> the entrypoint for finding docs within a type is +find-item-in-type. +| %searching :> returns the item to print while searching through topic :> @@ -505,12 +508,13 @@ ++ print-chapter |= [name=tape doc=what sut=type con=coil chapter-id=term] ^- tang + ~? > debug %print-chapter ;: weld (print-header name doc) :: - ?~ doc - ~ - (print-sections q.u.doc) + ::?~ doc + :: ~ + ::(print-sections q.u.doc) :: =+ arms=(arms-in-chapter sut con chapter-id) ?~ arms @@ -572,8 +576,8 @@ out ?~ doc.oitem ~ `tang`[[%leaf ""] [%leaf "{(trip p.u.doc.oitem)}"] ~] - ?~ doc.oitem ~ - (print-sections q.u.doc.oitem) + ::?~ doc.oitem ~ + ::(print-sections q.u.doc.oitem) ^$(overview children.oitem) == == @@ -586,8 +590,8 @@ `tang`[[%leaf ""] [%leaf name.oitem] ~] ?~ doc.oitem ~ `tang`[[%leaf ""] [%leaf "{(trip p.u.doc.oitem)}"] ~] - ?~ doc.oitem ~ - (print-sections q.u.doc.oitem) + ::?~ doc.oitem ~ + ::(print-sections q.u.doc.oitem) == == == From 24a175a803d8dea51bd29f0bf5d347ffa877aa71 Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Thu, 7 Apr 2022 13:05:15 -0400 Subject: [PATCH 083/715] dojo: flop order of topics for dy-inspect you had to search for core:arm instead of arm:core before --- pkg/arvo/app/dojo.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/app/dojo.hoon b/pkg/arvo/app/dojo.hoon index 9363ab4b7..7fc5ed3b3 100644 --- a/pkg/arvo/app/dojo.hoon +++ b/pkg/arvo/app/dojo.hoon @@ -683,7 +683,7 @@ ++ dy-inspect |= [topics=(list term) sut=type] %+ dy-rash %tan - =+ to-display=(find-item-in-type:dprint topics sut %.y) + =+ to-display=(find-item-in-type:dprint (flop topics) sut %.y) ?~ to-display [%leaf "Could not find help"]~ (flop (print-item:dprint u.to-display)) From dd71b7c788730f49e29d3b75f7185676616de4fe Mon Sep 17 00:00:00 2001 From: drbeefsupreme Date: Thu, 7 Apr 2022 13:05:58 -0400 Subject: [PATCH 084/715] doccords: dprint debug printfs --- pkg/arvo/lib/dprint.hoon | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/pkg/arvo/lib/dprint.hoon b/pkg/arvo/lib/dprint.hoon index f4bd522c7..6b9664565 100644 --- a/pkg/arvo/lib/dprint.hoon +++ b/pkg/arvo/lib/dprint.hoon @@ -70,6 +70,7 @@ :: TODO make this work with a list of topics |= [topics=(list term) sut=type rec=?] ^- (unit item) + ~? > debug topics ?~ topics :: we have no more search paths, return an overview of what remains (signify sut) @@ -258,8 +259,25 @@ ++ what-from-hint |= sut=type ^- what - ?+ sut - ~ + ?- sut + :: ~? > debug %what-from-hint-miss ~ + %noun ~? >> debug %what-from-hint-noun-miss ~ + %void ~? >> debug %what-from-hint-void-miss ~ + :: + [%core *] + ~? >> debug %what-from-hint-core-miss ~ + :: + [%cell *] + ~? >> debug %what-from-hint-cell-miss ~ + :: + [%face *] + ~? >> debug %what-from-hint-face-miss ~ + :: + [%fork *] + ~? >> debug %what-from-hint-fork-miss ~ + :: + [%atom *] + ~? >> debug %what-from-hint-atom-miss ~ :: [%hold *] ~? >> debug %what-from-hint-hold $(sut (~(play ut p.sut) q.sut)) @@ -311,6 +329,7 @@ ~? > debug %doc-two-empty ?~ links.u.doc-one :: if links are empty, doc-one is a product-doc + ~? > debug %link-empty [~ [~ `crib.u.doc-one]] ?: =([%funk name] i.links.u.doc-one) :: if links are non-empty, check that the link is for the arm @@ -343,7 +362,7 @@ ^- [what what what] =+ hoon-type=(~(play ut sut) gen) =+ arm-prod=(arm-product-docs hoon-type `@tas`(crip name)) - ~? >> debug :- %arm-prod arm-prod + ::~? >> debug :- %arm-prod arm-prod |^ :: check arm-prod to determine how many layers to look into the type :: for core docs @@ -373,6 +392,7 @@ =+ carm=(find-arm-in-coil %$ q.sut) ?~ carm ~? > debug %empty-carm ~ ~? > debug %found-default-arm + ::~? >>> debug u.carm =+ carm-type=(~(play ut p.sut) u.carm) (what-from-hint carm-type) -- @@ -474,6 +494,7 @@ :> prints a doccords item ++ print-item |= =item + ~? >> debug %print-item ^- tang ?- item [%view *] (print-overview items.item) @@ -539,6 +560,7 @@ ++ print-face |= [name=tape doc=what children=(unit item)] ^- tang + ~? >> debug %print-face %+ weld (print-header name doc) ?~ children @@ -549,6 +571,7 @@ ++ print-header |= [name=tape doc=what] ^- tang + ~? >> debug %print-header ?~ name ?~ doc [%leaf "(undocumented)"]~ @@ -564,6 +587,7 @@ ++ print-overview |= =overview ^- tang + ~? >> debug %print-overview =| out=tang |- ?~ overview out From 50d120e3c166410f9d1646b17a537b8e93653f18 Mon Sep 17 00:00:00 2001 From: tomholford Date: Mon, 11 Apr 2022 12:05:25 -0700 Subject: [PATCH 085/715] devex: address PR feedback - move App#initSessions definition outside function component closure - enhance useAddSessions performance --- pkg/interface/webterm/App.tsx | 16 ++++++++-------- pkg/interface/webterm/Tabs.tsx | 2 +- pkg/interface/webterm/lib/useAddSession.ts | 4 +--- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/pkg/interface/webterm/App.tsx b/pkg/interface/webterm/App.tsx index c8dee297c..211066b74 100644 --- a/pkg/interface/webterm/App.tsx +++ b/pkg/interface/webterm/App.tsx @@ -21,18 +21,18 @@ import { DEFAULT_SESSION } from './constants'; import { showSlog } from './lib/blit'; import { InfoButton } from './InfoButton'; +const initSessions = async () => { + const response = await api.scry(scrySessions()); + + useTermState.getState().set((state) => { + state.names = response.sort(); + }); +}; + export default function TermApp() { const { names, selected } = useTermState(); const dark = useDark(); - const initSessions = useCallback(async () => { - const response = await api.scry(scrySessions()); - - useTermState.getState().set((state) => { - state.names = response.sort(); - }); - }, []); - const setupSlog = useCallback(() => { console.log('slog: setting up...'); let available = false; diff --git a/pkg/interface/webterm/Tabs.tsx b/pkg/interface/webterm/Tabs.tsx index 3b0cd0a0f..ed583635a 100644 --- a/pkg/interface/webterm/Tabs.tsx +++ b/pkg/interface/webterm/Tabs.tsx @@ -6,7 +6,7 @@ import { Icon } from '@tlon/indigo-react'; export const Tabs = () => { const { sessions, names } = useTermState(); - const { addSession } = useAddSession(); + const addSession = useAddSession(); return (
diff --git a/pkg/interface/webterm/lib/useAddSession.ts b/pkg/interface/webterm/lib/useAddSession.ts index 25a5fc0c2..c5556c14b 100644 --- a/pkg/interface/webterm/lib/useAddSession.ts +++ b/pkg/interface/webterm/lib/useAddSession.ts @@ -62,7 +62,5 @@ export const useAddSession = () => { } }, [names]); - return { - addSession - }; + return addSession; }; From 349033fb121aa39b77e8846b974f3a64115f6192 Mon Sep 17 00:00:00 2001 From: tomholford Date: Wed, 13 Apr 2022 08:47:30 -0700 Subject: [PATCH 086/715] ux: detect OS for hotkey instructions Also, ensure changes from this PR are included in the session branch: https://github.com/urbit/urbit/pull/5529 --- pkg/interface/webterm/Buffer.tsx | 4 ++- pkg/interface/webterm/InfoButton.tsx | 9 +++-- pkg/interface/webterm/lib/theme.ts | 3 +- pkg/interface/webterm/lib/useDetectOS.ts | 44 ++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 pkg/interface/webterm/lib/useDetectOS.ts diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx index da4a8e8a6..e0ce5e143 100644 --- a/pkg/interface/webterm/Buffer.tsx +++ b/pkg/interface/webterm/Buffer.tsx @@ -33,7 +33,9 @@ const termConfig: ITerminalOptions = { bellSound: bel, // // allows text selection by holding modifier (option, or shift) - macOptionClickForcesSelection: true + macOptionClickForcesSelection: true, + // prevent insertion of simulated arrow keys on-altclick + altClickMovesCursor: false }; const readInput = (term: Terminal, e: string): Belt[] => { diff --git a/pkg/interface/webterm/InfoButton.tsx b/pkg/interface/webterm/InfoButton.tsx index 4ec3a3347..b0ba22953 100644 --- a/pkg/interface/webterm/InfoButton.tsx +++ b/pkg/interface/webterm/InfoButton.tsx @@ -1,10 +1,15 @@ import React, { useCallback } from 'react'; import { Icon } from '@tlon/indigo-react'; +import { useDetectOS } from './lib/useDetectOS'; export const InfoButton = () => { + const { isMacOS } = useDetectOS(); + const onInfoClick = useCallback(() => { - alert('To select text in the terminal, hold down the alt key.'); - }, []); + const key = isMacOS ? 'alt' : 'shift'; + + alert(`To select text in the terminal, hold down the ${key} key.`); + }, [isMacOS]); return ( <> diff --git a/pkg/interface/webterm/lib/theme.ts b/pkg/interface/webterm/lib/theme.ts index 6044f1c30..9b97806d4 100644 --- a/pkg/interface/webterm/lib/theme.ts +++ b/pkg/interface/webterm/lib/theme.ts @@ -16,6 +16,7 @@ export const makeTheme = (dark: boolean): ITheme => { foreground: fg, background: bg, brightBlack: '#7f7f7f', // NOTE slogs - cursor: fg + cursor: fg, + selection: fg }; }; diff --git a/pkg/interface/webterm/lib/useDetectOS.ts b/pkg/interface/webterm/lib/useDetectOS.ts new file mode 100644 index 000000000..7b8f915f9 --- /dev/null +++ b/pkg/interface/webterm/lib/useDetectOS.ts @@ -0,0 +1,44 @@ +/* eslint-disable no-useless-escape */ +// Regex patterns inspired by: +// https://github.com/faisalman/ua-parser-js/blob/master/src/ua-parser.js +const LINUX = [ + /\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i, + /(mint)[\/\(\) ]?(\w*)/i, + /(mageia|vectorlinux)[; ]/i, + /([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\/ ]?(?!chrom|package)([-\w\.]*)/i, + /(hurd|linux) ?([\w\.]*)/i, + /(gnu) ?([\w\.]*)/i, + /\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, + /(haiku) (\w+)/i, + /(sunos) ?([\w\.\d]*)/i, + /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, + /(aix) ((\d)(?=\.|\)| )[\w\.])*/i, + /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux)/i, + /(unix) ?([\w\.]*)/i +]; + +const MAC_OS = [ + /(mac os x) ?([\w\. ]*)/i, + /(macintosh|mac_powerpc\b)(?!.+haiku)/i +]; + +const WINDOWS = [ + /microsoft (windows) (vista|xp)/i, + /(windows) nt 6\.2; (arm)/i, + /(windows (?:phone(?: os)?|mobile))[\/ ]?([\d\.\w ]*)/i, + /(windows)[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i +]; + +export const useDetectOS = () => { + const userAgent = navigator.userAgent; + + const isLinux = LINUX.some(regex => regex.test(userAgent)); + const isMacOS = MAC_OS.some(regex => regex.test(userAgent)); + const isWindows = WINDOWS.some(regex => regex.test(userAgent)); + + return { + isLinux, + isMacOS, + isWindows + }; +}; From 37ce741a77898d0bdd99fff497699e622bea6146 Mon Sep 17 00:00:00 2001 From: tomholford Date: Thu, 14 Apr 2022 04:52:43 -0700 Subject: [PATCH 087/715] deps: replace deprecated xterm#setOption See: https://github.com/xtermjs/xterm.js/blob/4.15.0/typings/xterm.d.ts#L1053 --- pkg/interface/webterm/Buffer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx index e0ce5e143..f18f0ab6e 100644 --- a/pkg/interface/webterm/Buffer.tsx +++ b/pkg/interface/webterm/Buffer.tsx @@ -155,7 +155,7 @@ export default function Buffer({ name, selected, dark }: BufferProps) { // set up xterm terminal // const term = new Terminal(termConfig); - term.setOption('theme', makeTheme(dark)); + term.options.theme = makeTheme(dark); const fit = new FitAddon(); term.loadAddon(fit); fit.fit(); @@ -252,7 +252,7 @@ export default function Buffer({ name, selected, dark }: BufferProps) { useEffect(() => { const theme = makeTheme(dark); if (session) { - session.term.setOption('theme', theme); + session.term.options.theme = theme; } if (container.current) { container.current.style.backgroundColor = theme.background || ''; From dfded5e592a7e4f27272733c455896f4709fecba Mon Sep 17 00:00:00 2001 From: tomholford Date: Thu, 14 Apr 2022 07:13:09 -0700 Subject: [PATCH 088/715] ux: refactor resize behavior - debounced resize event listener - new Buffer#onSelect: resize, focus, and pokes `herm` with updated rows / cols - simplify container ref implementation (no need for a callback ref), remove isOpen hack - add lodash for debounce - Tab#onClick no longer handles focus (it's now handled by Buffer#onSelect) --- pkg/interface/webterm/Buffer.tsx | 87 +++++++++++++----------- pkg/interface/webterm/Tab.tsx | 1 - pkg/interface/webterm/constants.ts | 1 + pkg/interface/webterm/package-lock.json | Bin 1283742 -> 1283772 bytes pkg/interface/webterm/package.json | 1 + 5 files changed, 49 insertions(+), 41 deletions(-) diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx index f18f0ab6e..4fb21b775 100644 --- a/pkg/interface/webterm/Buffer.tsx +++ b/pkg/interface/webterm/Buffer.tsx @@ -1,5 +1,6 @@ import { Terminal, ITerminalOptions } from 'xterm'; import { FitAddon } from 'xterm-addon-fit'; +import { debounce } from 'lodash'; import bel from './lib/bel'; import api from './api'; @@ -13,7 +14,7 @@ import React from 'react'; import { Box, Col } from '@tlon/indigo-react'; import { makeTheme } from './lib/theme'; import { showBlit, csi, hasBell } from './lib/blit'; -import { DEFAULT_SESSION } from './constants'; +import { DEFAULT_SESSION, RESIZE_DEBOUNCE_MS } from './constants'; import { retry } from './lib/retry'; const termConfig: ITerminalOptions = { @@ -120,11 +121,10 @@ const readInput = (term: Terminal, e: string): Belt[] => { return belts; }; -const onResize = (session: Session) => () => { - //TODO debounce, if it ever becomes a problem - //TODO test that we only send this to the selected session, - // and that we *do* send it on-selected-change if necessary. - session?.fit.fit(); +const onResize = async (name: string, session: Session) => { + if (session) { + session.fit.fit(); + } }; const onInput = (name: string, session: Session, e: string) => { @@ -145,7 +145,7 @@ interface BufferProps { } export default function Buffer({ name, selected, dark }: BufferProps) { - const container = useRef(null); + const containerRef = useRef(null); const session: Session = useTermState(s => s.sessions[name]); @@ -165,7 +165,7 @@ export default function Buffer({ name, selected, dark }: BufferProps) { // term.write(csi('?9h')); - const ses: Session = { term, fit, hasBell: false, subscriptionId: null }; + const ses: Session = { term, fit, hasBell: false, subscriptionId: null }; // set up event handlers // @@ -218,6 +218,15 @@ export default function Buffer({ name, selected, dark }: BufferProps) { }); }, []); + const onSelect = useCallback(async () => { + if (session && selected) { + session.fit.fit(); + session.term.focus(); + await api.poke(pokeTask(name, { blew: { w: session.term.cols, h: session.term.rows } })); + } + }, [session, selected]); + + // Effects // init session useEffect(() => { if(session) { @@ -227,25 +236,27 @@ export default function Buffer({ name, selected, dark }: BufferProps) { initSession(name, dark); }, [name]); - // on selected change, maybe setup the term, or put it into the container - // - const setContainer = useCallback((containerRef: HTMLDivElement | null) => { - const newContainer = containerRef || container.current; - if(session && newContainer) { - container.current = newContainer; + // attach to DOM when ref is available + useEffect(() => { + if(session && containerRef.current && !session.term.element) { + session.term.open(containerRef.current); } - }, [session]); + }, [session, containerRef]); - // on-init, open slogstream and fetch existing sessions + // on-init, open slogstream and fetch existing sessions // useEffect(() => { - window.addEventListener('resize', onResize(session)); + if(!session) { + return; + } + + const debouncedResize = debounce(() => onResize(name, session), RESIZE_DEBOUNCE_MS); + window.addEventListener('resize', debouncedResize); return () => { - // TODO clean up subs? - window.removeEventListener('resize', onResize(session)); + window.removeEventListener('resize', debouncedResize); }; - }, []); + }, [session]); // on dark mode change, change terminals' theme // @@ -254,24 +265,20 @@ export default function Buffer({ name, selected, dark }: BufferProps) { if (session) { session.term.options.theme = theme; } - if (container.current) { - container.current.style.backgroundColor = theme.background || ''; + if (containerRef.current) { + containerRef.current.style.backgroundColor = theme.background || ''; } }, [session, dark]); + // On select, resize, focus, and poke herm with updated cols and rows useEffect(() => { - if (session && selected && !session.term.isOpen) { - session.term.open(container.current); - session.fit.fit(); - session.term.focus(); - session.term.isOpen = true; - } - }, [selected, session]); + onSelect(); + }, [onSelect]); return ( !session && !selected ?

Loading...

- : + : - - - + + + ); } diff --git a/pkg/interface/webterm/Tab.tsx b/pkg/interface/webterm/Tab.tsx index 209d408e5..6f15e9f59 100644 --- a/pkg/interface/webterm/Tab.tsx +++ b/pkg/interface/webterm/Tab.tsx @@ -17,7 +17,6 @@ export const Tab = ( { session, name }: TabProps ) => { state.selected = name; state.sessions[name].hasBell = false; }); - useTermState.getState().sessions[name]?.term?.focus(); }; const onDelete = useCallback(async (e) => { diff --git a/pkg/interface/webterm/constants.ts b/pkg/interface/webterm/constants.ts index 66d4b0ecc..549f4bd94 100644 --- a/pkg/interface/webterm/constants.ts +++ b/pkg/interface/webterm/constants.ts @@ -1,5 +1,6 @@ export const DEFAULT_SESSION = ''; export const DEFAULT_HANDLER = 'hood'; +export const RESIZE_DEBOUNCE_MS = 100; /** * Session ID validity: diff --git a/pkg/interface/webterm/package-lock.json b/pkg/interface/webterm/package-lock.json index 902930d988df8539a038394474507620face3d54..4e617d5f3024df6fc15133e3af632b343071f301 100644 GIT binary patch delta 109 zcmWl|OA0_x7=Y1!@AorPOJY$57C_yZY~YrO6gG5~J@}kDi|%gSZI>v$maTeE$)-md j)hmeyBcqYOMVk&?dh{7EWW<;WQ)bLruw-=@srUHz delta 104 zcmWl~y9t0W06;+!KZ!=;57){}f`tPpq!8R7kVY(YGAp0OaZhkZaPby?dW~JR9DUq{ gnU!3W6!=e&B0~-ZjRGYMD%7xO(4s?sDLI_m2aMVl`Tzg` diff --git a/pkg/interface/webterm/package.json b/pkg/interface/webterm/package.json index 856b29eed..0e58cc608 100644 --- a/pkg/interface/webterm/package.json +++ b/pkg/interface/webterm/package.json @@ -11,6 +11,7 @@ "@urbit/api": "^1.1.1", "@urbit/http-api": "^1.2.1", "file-saver": "^2.0.5", + "lodash": "^4.17.21", "react": "^16.14.0", "react-dom": "^16.14.0", "react-router-dom": "^5.2.0", From 65f9f904c73becdc0e7c656b8a5c217f0a6a5c6c Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 15 Apr 2022 18:02:42 +0200 Subject: [PATCH 089/715] zuse: rewrite klr:format's +scag and +slag The previous implementation was counting the full length of the stub unnecessarily. Doing a single "dumb" traversal is ~40% faster. --- pkg/arvo/sys/zuse.hoon | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/pkg/arvo/sys/zuse.hoon b/pkg/arvo/sys/zuse.hoon index 1d465267e..a1895c0ee 100644 --- a/pkg/arvo/sys/zuse.hoon +++ b/pkg/arvo/sys/zuse.hoon @@ -3788,29 +3788,24 @@ ++ slag :: slag stub |= [a=@ b=stub] ^- stub - =+ c=(lnts-char b) - =+ i=(brek a c) - ?~ i ~ - =+ r=(^slag +(p.u.i) b) - ?: =(a q.u.i) - r - =+ n=(snag p.u.i b) - :_ r :- p.n - (^slag (sub (snag p.u.i c) (sub q.u.i a)) q.n) + ?: =(0 a) b + ?~ b ~ + =+ c=(lent q.i.b) + ?: =(c a) t.b + ?: (gth c a) + [[p.i.b (^slag a q.i.b)] t.b] + $(a (sub a c), b t.b) :: ++ scag :: scag stub |= [a=@ b=stub] ^- stub - =+ c=(lnts-char b) - =+ i=(brek a c) - ?~ i b - ?: =(a q.u.i) - (^scag +(p.u.i) b) - %+ welp - (^scag p.u.i b) - =+ n=(snag p.u.i b) - :_ ~ :- p.n - (^scag (sub (snag p.u.i c) (sub q.u.i a)) q.n) + ?: =(0 a) ~ + ?~ b ~ + =+ c=(lent q.i.b) + ?: (gth c a) + [p.i.b (^scag a q.i.b)]~ + :- i.b + $(a (sub a c), b t.b) :: ++ swag :: swag stub |= [[a=@ b=@] c=stub] From 2d3e803704af38e761f014ff612d8097494ee2f8 Mon Sep 17 00:00:00 2001 From: tomholford Date: Tue, 19 Apr 2022 03:41:40 -0700 Subject: [PATCH 090/715] devex: improved resize behavior - only resize when necessary (check the container's height) - refactor CSS: use position relative / absolute to stack Buffers instead of display:none; this affects the calcuations used by fit() - fix dark mode styles, tweak viewport height (100vh --> 99vh) to prevent overflow scroller --- pkg/interface/webterm/Buffer.tsx | 27 +++++++++++++++++++-------- pkg/interface/webterm/constants.ts | 1 + pkg/interface/webterm/index.html | 14 ++++++++++++-- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx index 4fb21b775..3e1be2bb3 100644 --- a/pkg/interface/webterm/Buffer.tsx +++ b/pkg/interface/webterm/Buffer.tsx @@ -14,7 +14,7 @@ import React from 'react'; import { Box, Col } from '@tlon/indigo-react'; import { makeTheme } from './lib/theme'; import { showBlit, csi, hasBell } from './lib/blit'; -import { DEFAULT_SESSION, RESIZE_DEBOUNCE_MS } from './constants'; +import { DEFAULT_SESSION, RESIZE_DEBOUNCE_MS, RESIZE_THRESHOLD_PX } from './constants'; import { retry } from './lib/retry'; const termConfig: ITerminalOptions = { @@ -124,6 +124,7 @@ const readInput = (term: Terminal, e: string): Belt[] => { const onResize = async (name: string, session: Session) => { if (session) { session.fit.fit(); + api.poke(pokeTask(name, { blew: { w: session.term.cols, h: session.term.rows } })); } }; @@ -171,9 +172,6 @@ export default function Buffer({ name, selected, dark }: BufferProps) { // term.onData(e => onInput(name, ses, e)); term.onBinary(e => onInput(name, ses, e)); - term.onResize((e) => { - api.poke(pokeTask(name, { blew: { w: e.cols, h: e.rows } })); - }); // open subscription // @@ -218,11 +216,22 @@ export default function Buffer({ name, selected, dark }: BufferProps) { }); }, []); + const shouldResize = useCallback(() => { + if(!session) { + return false; + } + + const containerHeight = document.querySelector('.buffer-container')?.clientHeight || Infinity; + const terminalHeight = session.term.element?.clientHeight || 0; + + return (containerHeight - terminalHeight) >= RESIZE_THRESHOLD_PX; + }, [session]); + const onSelect = useCallback(async () => { - if (session && selected) { + if (session && selected && shouldResize()) { session.fit.fit(); - session.term.focus(); await api.poke(pokeTask(name, { blew: { w: session.term.cols, h: session.term.rows } })); + session.term.focus(); } }, [session, selected]); @@ -243,13 +252,14 @@ export default function Buffer({ name, selected, dark }: BufferProps) { } }, [session, containerRef]); - // on-init, open slogstream and fetch existing sessions + // initialize resize listeners // useEffect(() => { if(!session) { return; } + // TODO: use ResizeObserver for improved performance? const debouncedResize = debounce(() => onResize(name, session), RESIZE_DEBOUNCE_MS); window.addEventListener('resize', debouncedResize); @@ -285,7 +295,8 @@ export default function Buffer({ name, selected, dark }: BufferProps) { bg='white' fontFamily='mono' overflow='hidden' - style={selected ? {} : { display: 'none' }} + className="terminal-container" + style={selected ? { zIndex: 999 } : {}} > - - - - - diff --git a/pkg/grid/src/assets/go.png b/pkg/grid/src/assets/go.png deleted file mode 100644 index 77bd1f958c26ef177af06914ad8eb167946e5a51..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4737 zcmZ8l2QVD$({~Au!|DA_v}i}P5JYsjJLU9{kRZAU4$(_EM-rSCHG=3Z`g?ezmph#x zN(jyoq&cFK`21(S`DVWV% z<3j3bTLuGuzD<6%L|`RomPN~Px<8E00mWK6lwJ|$w5eQO1tF|`H$i&V&kbpcU{rR1 zZIBobfW>4cwI#|mlVRz6d67H5C6q_nwVo=_wTppA-VXep@3YDD#UoTw+qDOp%`5Tv zg1@#*!fWJN-7wAO>UVA1<;3lIuZfErH*N$@5}AI6Hj>+9jx62~2W*6XB))lfhcQWg zk;?=pObaATD(i*`YO4KWhN|#9I8H{!%U2|E_Mp1CGlg?2bQy7xP!=BIl>u#B0qZTX zC6x+D;(&ir{e5yNUR!v&CKUvnQ<_>3jxbWQNs-P4ZKDL)M0I-52yC!uOka#MNu^)& zUdOByb?>;*9>r*lWt^7fTKa?>7m;fZC$}Om%Sx5B1LkX{>jOwR^}dg8;DPKzq8H)8 z3My#he=R9)3?1^MqxM4n_}xHvHJwQjn(Z+G#g_as6|HARG2RfuqVVpgZJSCMW3#K@oTiEd|I(6q+P|hcRb8~e3t(G)2{;X62y=vAUfnG&K_Yq(^Ls0O#4#L4 zE@WQGMvd3B)l;dWYPkox!uBP%OFs!QUuX&0JmNNb!Wo9z|jX9s|ZY z0Q~a8*57e|6Nyg#eG#pG{!-`iH5iD%eb{(ZVIq~x&CMN_9I5IJ3FC;R85}tWKMW04 zSz2vXjX4-^S^=M)$HmlBh2%g3POca3)J+b|NvfJ2O}a2U$y2Io37+UlLy4qM80a>I z-qG%V^CAHWFh_Y(E2!)N)5Mj({NcJxBbXpuX*T%K&-ZJb^U3qz2ZKrUE3udL>E$i+ z;e#l~Xs6{WjU@I13~1+?XO zdIm4;4n|?ocU2F!1^~?iD&F^$g5y*;d`TYXqCXU9`X%RSfqim}|4)MXZ?MGmrRSO_ zhi??FXghILz4_}Cg+_lQKg}lgk&vGxt$zj%sc@{paw$V-@W%#Da-ZcZzF`KP{gR5A z&NPEv4|k>g%D6yG)->#^6&bX7^$g?&^p6;N(%JiWz5a?aT{SlN`E#vN|FZ7ZcXDc_ zT4*|x-(MXn>%DDUq?*0sd<4M^{X#NHZJ5cI)2*^k;k%T?H9_4(b_kwn7C6BtGZpS) zR{0C85FP7QVMk>*v&% zDM)H~z0c`AFd-`AY?5tTU&ED@Qvn_F$M`}7HN=+sUzIP@2^en6Z=3q^g)>3ntFwa7 zds16U;8-~|Ef=HAnv#;XYUHS~Gy`-W^?8xkJ@3v<57Gp1D+x(SDi#c8R3etP^22Gq zuz$T5Hs1r-OWh9vYHDZ)8HHQDHR#n|vF78T-l@rMJV=n;xpVf1IwIWiEzeIh>9z~j z#VoDPIr{24e9MCV$gpQK9JcQ0vG`@(cNv7;#;ms@epv$drU%mtIV$DFh-1jKwAU?- z-GH?3B`a@_?_@#o#dp=gA;$o0iht0Ng{MI#;0Xs1h)7mf7yEldKiQ9x>HvEw5VB=T z2N67)B*G=i;Q4~PsjQ14%&LS(X%IHAA6NB}^&2YN7a@l*{k3YiDx25!RPyQZsev+N zpF2v5`F8V7IWVb6Y9(vmb_<8}&3^!(%zJE=Qp-whmSLCagDA0twF=;r6GIfFP+4q1 zEe6O0qGT+&ixtwm_epv5FA`3ACiI{Q5x-HSnlK~5gX+oDAld3^$-{R{L4 zkKFCE*7=8RB^J7lQaR;)v#t;0@9$GAT!%Ih)Z7Jci9xvnrsswJ#M+A1+N9f&EHME( zG>>NmAc{=m(kiZe{RO@=PM_r6^N`+>;K+rnnkD}i7uh{1Q^&V6FS!g(rh(cb< zj+#+zRZ&u#jC>b&+jq6|B|iMO2iJE{;8 zw!WFYa>!DJtC91TIDY^FT;K;nhLSh|cZQ~(iBI`FFwZP2mT%jSLvgn^RD1+(nLF+y zuXR0p(JgdCeuw>Dk*2j8CjE~Q=~LF*fI`zey=AWij5HV>$l%lx~x*j!n;gej?PUMILFT?Mdz{X>y~Q zxC?evao$@@>ec=_+l`0`$Y@amN!;K+oh^YU$l(XqTi&ikXVws{sY|LC2ZJ@2Q*hni zgfhw{!J!&wpL{~Tf8_hOz*V-Pa}4BH{Ksn2aN&vHBjCgEiGN~l*jI_DYAx#)K&Cva zo&5}c^0o?h5os@Nph16`~u6-z24w?J{nPv83%(#Fx1SYTL7uMluX zdpBQT*kwxp;3Kykl2*0(c#2ZIIPKx|N+i)Yhn>27ObVy(`+N9!q*6wW_Hw9|jRbQ9 z7qsJOdH>*b?2_m%_!sN7dHFETaCCjiTbp6J0botDo`8kOvJXtpG)#bES3-CdLkNmC z$sZq#CKXaAH4V9$*z!%K4?1}spU8A!&?%kn2|MGjtbtEaYU@i?0_1XKTgfQhEe~sb z?;UVtuFH1g&sv1Z2PuKmVQX83o!Vffg*8gYN-js3n2- zw6t|9zTV$J92WUJuu*tu%M@WxO{NbV1vb@y1`0o3=0#b+K2HfJzAus)%MwYc{re@+ zimz;!J`_h;XN(LO##>VQBo}wBV&2DS9Nu6{#zelo_{Xgabb6L|^10}an0?7rRV}~4 z;*NOM5zhU~jM4nP?&mc~3QL4UzA<)`BI-YawGn<52t-82YIJ%!s}eSdc6`{ZLjkrV zU4a|eQ^YFj{1?AoWosVDLaYZL?ng7|vbOVh^uvd0e>6H(H+;YbSRUR87ZC8LL1YTr zN$yH6IPMEX7&Kn?!$BKISP(Zyd9A0x#EYd1aICZyjKGBvnc# zL>m-|^0xo#*_L>hTub4qKlg#viI}zbTN@sZrzX&n#)tltD*8bQ3lcLzwu74hwf;|+ zvwbM!Hr?xZc11$wj|j4iFD0Gd2^ehUX*8Jmh2B;`%vNg4+!(K(SHHm}?zNlYaJI*m zjAj7?PnH9%q-ldDT|?LJyN8dP+2{NidTNN>X^NT-w7U8KvD+n-vjHqKV6SVLnESSC zvdi8bOVGSSz+S6Wa6+n7M{D}KFS%9`(Do$dGlS$(U8gH9hLNL{vS7l3w$nmfUEO3+ z1eTyv%m1oaWJF2>#ukoUa6qQyxehg=mgwRL{2qqeUJcZUN0Y=D=Yf<0wkFvP;E=<* zcp6a(Vog_i=bp@jH3AMxC1nMTh0=*A-t0_yBJ^DzCTVE+l2Nq_!-+HkGmthi&;=89kqD&CMb2 zipM8rzcW#$$D8{OVlWNv3Z3wOrvw@p`{HZZyhkM>fwHYvW8i)GD%W|d{@zBOqP*?V-1Fn?ezmWc z^An5>PnCuy^%U4nTB6h*yflK73Sw_xLiPu-q}M-IXS;(rfgL@}eza58a-ORuOcgjo znkf9MKuV%((;#eS@)@=FBkt#fiKg6Guar4Jl~W`38fpRTt)F3#g+JK3q%(KUJPgBk zb6-t}TsuNf4jkFRwu)u?xcgNN>fc&s^Fdm4@+&*pzNLc-s!i&@`Ysn~oa7hxzMh~N zEOQXOWTxf>Z1OG`>x%>UNnX1DM`bk&S;oz@h;r?!M5=8wu!g5~8)3t&BAFTrdUrFa z7s6e5wB?_yehevx3xp>Matzvsr;;othnUXkV_Ko3=}xqJ@>x;N_4(z{0Tp-^k||0<$H%Bu z^|;BRxfoNLn^&UEi|f{&N&`cCvk#7M5}Xs{Ap72rnHXh7LFhDK!T!`2SgZwL&1p)= z`>C$e-R};;WWg}vk`P;3)Ql&K$<_PiH7paTNgVi|9A_fNDCI{AUD5+~Hbo>RfUhK( zUQ_rJ!cE-45XgXYhfEpV9xyMLG+s-LFuaZ9~(bsS>;2b%5ZCjbBd diff --git a/pkg/grid/src/assets/help-and-support.svg b/pkg/grid/src/assets/help-and-support.svg deleted file mode 100644 index 020dbfeba..000000000 --- a/pkg/grid/src/assets/help-and-support.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pkg/grid/src/assets/manifest.json b/pkg/grid/src/assets/manifest.json deleted file mode 100644 index 5c5876c10..000000000 --- a/pkg/grid/src/assets/manifest.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "urbit", - "short_name": "urbit", - "icons": [ - { - "src": "/apps/grid/android-chrome-512x512.png", - "sizes": "512x512", - "type": "image/png" - } - ], - "theme_color": "#ffffff", - "background_color": "#ffffff", - "display": "standalone" -} diff --git a/pkg/grid/src/assets/safari-pinned-tab.svg b/pkg/grid/src/assets/safari-pinned-tab.svg deleted file mode 100644 index c3de016ef..000000000 --- a/pkg/grid/src/assets/safari-pinned-tab.svg +++ /dev/null @@ -1,54 +0,0 @@ - - - - -Created by potrace 1.14, written by Peter Selinger 2001-2017 - - - - - - - - diff --git a/pkg/grid/src/assets/system.png b/pkg/grid/src/assets/system.png deleted file mode 100644 index 09f6a4e6050d64a45c656bebd2a50a2f3c450f03..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12724 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 diff --git a/pkg/grid/src/components/AppInfo.tsx b/pkg/grid/src/components/AppInfo.tsx deleted file mode 100644 index a6ad97fba..000000000 --- a/pkg/grid/src/components/AppInfo.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import { chadIsRunning, Pike, Treaty } from '@urbit/api'; -import clipboardCopy from 'clipboard-copy'; -import React, { FC, useCallback, useState } from 'react'; -import cn from 'classnames'; -import { Button, PillButton } from './Button'; -import { Dialog, DialogClose, DialogContent, DialogTrigger } from './Dialog'; -import { DocketHeader } from './DocketHeader'; -import { Spinner } from './Spinner'; -import { PikeMeta } from './PikeMeta'; -import useDocketState, { ChargeWithDesk, useTreaty } from '../state/docket'; -import { getAppHref, getAppName } from '../state/util'; -import { addRecentApp } from '../nav/search/Home'; -import { TreatyMeta } from './TreatyMeta'; - -type InstallStatus = 'uninstalled' | 'installing' | 'installed'; - -type App = ChargeWithDesk | Treaty; -interface AppInfoProps { - docket: App; - pike?: Pike; - className?: string; -} - -function getInstallStatus(docket: App): InstallStatus { - if (!('chad' in docket)) { - return 'uninstalled'; - } - if (chadIsRunning(docket.chad)) { - return 'installed'; - } - if ('install' in docket.chad) { - return 'installing'; - } - return 'uninstalled'; -} - -function getRemoteDesk(docket: App, pike?: Pike) { - if (pike && pike.sync) { - return [pike.sync.ship, pike.sync.desk]; - } - if ('chad' in docket) { - return ['', docket.desk]; - } - const { ship, desk } = docket; - return [ship, desk]; -} - -export const AppInfo: FC = ({ docket, pike, className }) => { - const installStatus = getInstallStatus(docket); - const [ship, desk] = getRemoteDesk(docket, pike); - const publisher = pike?.sync?.ship ?? ship; - const [copied, setCopied] = useState(false); - const treaty = useTreaty(ship, desk); - - const installApp = async () => { - if (installStatus === 'installed') { - return; - } - await useDocketState.getState().installDocket(ship, desk); - }; - - const copyApp = useCallback(() => { - setCopied(true); - clipboardCopy(`web+urbitgraph://${publisher}/${desk}`); - - setTimeout(() => { - setCopied(false); - }, 1250); - }, [publisher, desk]); - - const installing = installStatus === 'installing'; - - if (!docket) { - // TODO: maybe replace spinner with skeletons - return ( -
- -
- ); - } - - return ( -
- -
- {installStatus === 'installed' && ( - addRecentApp(docket.desk)} - > - Open App - - )} - {installStatus !== 'installed' && ( - - - {installing ? ( - <> - - Installing... - - ) : ( - 'Get App' - )} - - -

Install “{getAppName(docket)}”

-

- This application will be able to view and interact with the contents of your - Urbit. Only install if you trust the developer. -

-
- - Cancel - - - Get “{getAppName(docket)}” - -
-
-
- )} - - {!copied && 'Copy App Link'} - {copied && 'copied!'} - -
-
-
- {pike ? ( - <> -
- - - ) : null} - {!treaty ? null : ( - <> -
- - - )} -
-
- ); -}; diff --git a/pkg/grid/src/components/AppLink.tsx b/pkg/grid/src/components/AppLink.tsx deleted file mode 100644 index 7ff8547ec..000000000 --- a/pkg/grid/src/components/AppLink.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import classNames from 'classnames'; -import React, { HTMLProps, ReactNode } from 'react'; -import { Link, LinkProps } from 'react-router-dom'; -import { DocketWithDesk } from '../state/docket'; -import { getAppHref, getAppName } from '../state/util'; -import { DocketImage } from './DocketImage'; - -type Sizes = 'xs' | 'small' | 'default'; -type LinkOrAnchorProps = { - [P in keyof LinkProps & - keyof HTMLProps]?: LinkProps[P] extends HTMLProps[P] - ? LinkProps[P] - : never; -}; - -export type AppLinkProps = Omit & { - app: T; - size?: Sizes; - selected?: boolean; - to?: (app: T) => LinkProps['to'] | undefined; -}; - -export const AppLink = ({ - app, - to, - size = 'default', - selected = false, - className, - ...props -}: AppLinkProps) => { - const linkTo = to?.(app); - const linkClassnames = classNames( - 'flex items-center default-ring rounded-lg', - size === 'default' && 'ring-offset-2', - size !== 'xs' && 'p-2', - size === 'xs' && 'p-1', - selected && 'bg-blue-200', - className - ); - const link = (children: ReactNode) => - linkTo ? ( - - {children} - - ) : ( -
- {children} - - ); - return link( - <> - -
-

{getAppName(app)}

- {app.info && size === 'default' &&

{app.info}

} -
- - ); -}; diff --git a/pkg/grid/src/components/AppList.tsx b/pkg/grid/src/components/AppList.tsx deleted file mode 100644 index 0764bab47..000000000 --- a/pkg/grid/src/components/AppList.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import React, { MouseEvent, useCallback } from 'react'; -import classNames from 'classnames'; -import { MatchItem } from '../nav/Nav'; -import { useRecentsStore } from '../nav/search/Home'; -import { AppLink, AppLinkProps } from './AppLink'; -import { DocketWithDesk } from '../state/docket'; -import { getAppName } from '../state/util'; - -type AppListProps = { - apps: T[]; - labelledBy: string; - matchAgainst?: MatchItem; - onClick?: (e: MouseEvent, app: T) => void; - listClass?: string; -} & Omit, 'app' | 'onClick'>; - -export function appMatches(target: DocketWithDesk, match?: MatchItem): boolean { - if (!match) { - return false; - } - - const matchValue = match.display || match.value; - return target.title === matchValue || target.desk === matchValue; -} - -export const AppList = ({ - apps, - labelledBy, - matchAgainst, - onClick, - listClass, - size = 'default', - ...props -}: AppListProps) => { - const addRecentApp = useRecentsStore((state) => state.addRecentApp); - const selected = useCallback((app: T) => appMatches(app, matchAgainst), [matchAgainst]); - - return ( -
    - {apps.map((app) => ( -
  • - { - addRecentApp(app.desk); - onClick?.(e, app); - }} - /> -
  • - ))} -
- ); -}; diff --git a/pkg/grid/src/components/Attribute.tsx b/pkg/grid/src/components/Attribute.tsx deleted file mode 100644 index 1f1309662..000000000 --- a/pkg/grid/src/components/Attribute.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import cn from 'classnames'; -import { capitalize } from 'lodash'; - -interface AttributeProps { - attr: string; - children: React.ReactNode; - title?: string; - className?: string; -} - -export const Attribute = ({ attr, children, title, className }: AttributeProps) => ( -
-

{title || capitalize(attr)}

-

{children}

-
-); diff --git a/pkg/grid/src/components/Avatar.tsx b/pkg/grid/src/components/Avatar.tsx deleted file mode 100644 index 2f3991530..000000000 --- a/pkg/grid/src/components/Avatar.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import classNames from 'classnames'; -import React, { useMemo } from 'react'; -import { sigil, reactRenderer } from '@tlon/sigil-js'; -import { deSig, Contact } from '@urbit/api'; -import { darken, lighten, parseToHsla } from 'color2k'; -import { useCurrentTheme } from '../state/local'; -import { normalizeUrbitColor } from '../state/util'; - -export type AvatarSizes = 'xs' | 'small' | 'default'; - -interface AvatarProps extends Contact { - shipName: string; - size: AvatarSizes; - className?: string; -} - -interface AvatarMeta { - classes: string; - size: number; -} - -const sizeMap: Record = { - xs: { classes: 'w-6 h-6 rounded', size: 12 }, - small: { classes: 'w-8 h-8 rounded-lg', size: 16 }, - default: { classes: 'w-12 h-12 rounded-lg', size: 24 } -}; - -const foregroundFromBackground = (background: string): 'black' | 'white' => { - const rgb = { - r: parseInt(background.slice(1, 3), 16), - g: parseInt(background.slice(3, 5), 16), - b: parseInt(background.slice(5, 7), 16) - }; - const brightness = (299 * rgb.r + 587 * rgb.g + 114 * rgb.b) / 1000; - const whiteBrightness = 255; - - return whiteBrightness - brightness < 50 ? 'black' : 'white'; -}; - -const emptyContact: Contact = { - nickname: '', - bio: '', - status: '', - color: '#000000', - avatar: null, - cover: null, - groups: [], - 'last-updated': 0 -}; - -function themeAdjustColor(color: string, theme: 'light' | 'dark'): string { - const hsla = parseToHsla(color); - const lightness = hsla[2]; - - if (lightness <= 0.1 && theme === 'dark') { - return lighten(color, 0.1 - lightness); - } - - if (lightness >= 0.9 && theme === 'light') { - return darken(color, lightness - 0.9); - } - - return color; -} - -export const Avatar = ({ size, className, ...ship }: AvatarProps) => { - const currentTheme = useCurrentTheme(); - const { shipName, color, avatar } = { ...emptyContact, ...ship }; - const { classes, size: sigilSize } = sizeMap[size]; - const adjustedColor = themeAdjustColor(normalizeUrbitColor(color), currentTheme); - const foregroundColor = foregroundFromBackground(adjustedColor); - const sigilElement = useMemo(() => { - if (shipName.match(/[_^]/) || shipName.length > 14) { - return null; - } - - return sigil({ - patp: deSig(shipName) || 'zod', - renderer: reactRenderer, - size: sigilSize, - icon: true, - colors: [adjustedColor, foregroundColor] - }); - }, [shipName, adjustedColor, foregroundColor]); - - if (avatar) { - return ; - } - - return ( -
- {sigilElement} -
- ); -}; diff --git a/pkg/grid/src/components/Button.tsx b/pkg/grid/src/components/Button.tsx deleted file mode 100644 index d38aeef3f..000000000 --- a/pkg/grid/src/components/Button.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; -import type * as Polymorphic from '@radix-ui/react-polymorphic'; -import classNames from 'classnames'; - -type ButtonVariant = - | 'primary' - | 'secondary' - | 'caution' - | 'destructive' - | 'alt-primary' - | 'alt-secondary'; - -type PolymorphicButton = Polymorphic.ForwardRefComponent< - 'button', - { - variant?: ButtonVariant; - } ->; - -const variants: Record = { - primary: 'text-white bg-black', - secondary: 'text-black bg-gray-100', - caution: 'text-white bg-orange-400', - destructive: 'text-white bg-red-500', - 'alt-primary': 'text-white bg-blue-400 ring-blue-300', - 'alt-secondary': 'text-blue-400 bg-blue-50' -}; - -export const Button = React.forwardRef( - ({ as: Comp = 'button', variant = 'primary', children, className, ...props }, ref) => { - return ( - - {children} - - ); - } -) as PolymorphicButton; - -export const PillButton = React.forwardRef(({ className, children, ...props }, ref) => ( - -)) as PolymorphicButton; diff --git a/pkg/grid/src/components/Checkbox.tsx b/pkg/grid/src/components/Checkbox.tsx deleted file mode 100644 index 5f4de6be4..000000000 --- a/pkg/grid/src/components/Checkbox.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React, { useState } from 'react'; -import classNames from 'classnames'; -import * as RadixCheckbox from '@radix-ui/react-checkbox'; -import { CheckIcon } from '@radix-ui/react-icons'; - -export const Checkbox: React.FC = ({ - defaultChecked, - checked, - onCheckedChange, - disabled, - className, - children -}) => { - const [on, setOn] = useState(defaultChecked); - const isControlled = !!onCheckedChange; - const proxyChecked = isControlled ? checked : on; - const proxyOnCheckedChange = isControlled ? onCheckedChange : setOn; - - return ( -
- - - - - - -
- ); -}; diff --git a/pkg/grid/src/components/DeskLink.tsx b/pkg/grid/src/components/DeskLink.tsx deleted file mode 100644 index 5e2ec45c1..000000000 --- a/pkg/grid/src/components/DeskLink.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import React, { ReactNode } from 'react'; -import { Link, useHistory } from 'react-router-dom'; -import { useCharge } from '../state/docket'; -import { getAppHref } from '../state/util'; - -interface DeskLinkProps extends React.AnchorHTMLAttributes { - desk: string; - to?: string; - children?: ReactNode; - className?: string; -} - -export function DeskLink({ children, className, desk, to = '', ...rest }: DeskLinkProps) { - const { push } = useHistory(); - const charge = useCharge(desk); - - if (!charge) { - return null; - } - if (desk === window.desk) { - return ( - - {children} - - ); - } - const href = `${getAppHref(charge.href)}${to}`; - return ( - push('/')} - > - {children} - - ); -} diff --git a/pkg/grid/src/components/Dialog.tsx b/pkg/grid/src/components/Dialog.tsx deleted file mode 100644 index 7876552e2..000000000 --- a/pkg/grid/src/components/Dialog.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React, { FC } from 'react'; -import * as DialogPrimitive from '@radix-ui/react-dialog'; -import type * as Polymorphic from '@radix-ui/react-polymorphic'; -import classNames from 'classnames'; - -export const Dialog: FC = ({ children, ...props }) => { - return ( - - - {children} - - ); -}; - -type DialogContentComponent = Polymorphic.ForwardRefComponent< - Polymorphic.IntrinsicElement, - Polymorphic.OwnProps & { - containerClass?: string; - showClose?: boolean; - } ->; - -export const DialogContent = React.forwardRef( - ({ showClose = true, containerClass, children, className, ...props }, forwardedRef) => ( - -
- {children} - {showClose && ( - - - - - - - )} -
-
- ) -) as DialogContentComponent; - -export const DialogTrigger = DialogPrimitive.Trigger; -export const DialogClose = DialogPrimitive.Close; diff --git a/pkg/grid/src/components/DocketHeader.tsx b/pkg/grid/src/components/DocketHeader.tsx deleted file mode 100644 index f8db3f7e6..000000000 --- a/pkg/grid/src/components/DocketHeader.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import { DocketImage } from './DocketImage'; -import { getAppName } from '../state/util'; -import { DocketWithDesk } from '../state/docket'; - -interface DocketHeaderProps { - docket: DocketWithDesk; - children?: React.ReactNode; -} - -export function DocketHeader(props: DocketHeaderProps) { - const { docket, children } = props; - const { info, image, color } = docket; - - return ( -
- -
-

{getAppName(docket)}

- {info &&

{info}

} -
- {children} -
- ); -} diff --git a/pkg/grid/src/components/DocketImage.tsx b/pkg/grid/src/components/DocketImage.tsx deleted file mode 100644 index 682123426..000000000 --- a/pkg/grid/src/components/DocketImage.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React, { useState } from 'react'; -import { Docket } from '@urbit/api'; -import cn from 'classnames'; -import { useTileColor } from '../tiles/useTileColor'; - -type DocketImageSizes = 'xs' | 'small' | 'default' | 'full'; - -interface DocketImageProps extends Pick { - className?: string; - size?: DocketImageSizes; -} - -const sizeMap: Record = { - xs: 'w-6 h-6 mr-2 rounded', - small: 'w-8 h-8 mr-3 rounded-md', - default: 'w-12 h-12 mr-3 rounded-lg', - full: 'w-20 h-20 md:w-32 md:h-32 rounded-2xl' -}; - -export function DocketImage({ color, image, className = '', size = 'full' }: DocketImageProps) { - const { tileColor } = useTileColor(color); - const [imageError, setImageError] = useState(false); - - return ( -
- {image && !imageError && ( - setImageError(true)} - /> - )} -
- ); -} diff --git a/pkg/grid/src/components/ErrorAlert.tsx b/pkg/grid/src/components/ErrorAlert.tsx deleted file mode 100644 index 93d18bc5a..000000000 --- a/pkg/grid/src/components/ErrorAlert.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import React from 'react'; -import cn from 'classnames'; -import { Dialog, DialogClose, DialogContent } from './Dialog'; -import { Button } from './Button'; - -interface ErrorAlertProps { - error: Error; - resetErrorBoundary: () => void; - className?: string; -} - -const SubmitIssue = ({ error }: { error: Error }) => { - const title = error.message; - const body = `\`\`\`%0A${error.stack?.replaceAll('\n', '%0A')}%0A\`\`\``; - - return ( - - ); -}; - -export const ErrorAlert = ({ error, resetErrorBoundary, className }: ErrorAlertProps) => { - return ( - resetErrorBoundary()}> - -

- Encountered error: - {error.message} -

- {error.stack && ( -
-
{error.stack}
-
- )} -
- - Try Again - - -
-
-
- ); -}; diff --git a/pkg/grid/src/components/PikeMeta.tsx b/pkg/grid/src/components/PikeMeta.tsx deleted file mode 100644 index 9349eeb3c..000000000 --- a/pkg/grid/src/components/PikeMeta.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import { Pike } from '@urbit/api'; - -import { Attribute } from './Attribute'; - -export function PikeMeta(props: { pike: Pike }) { - const { pike } = props; - - const pluralUpdates = pike.wefts?.length !== 1; - return ( -
- - {pike.hash} - - - %{pike.sync?.desk} - - {pike.wefts && pike.wefts.length > 0 ? ( - - {pike.wefts.length} update{pluralUpdates ? 's are' : ' is'} pending a System Update - - ) : null} -
- ); -} diff --git a/pkg/grid/src/components/ProviderLink.tsx b/pkg/grid/src/components/ProviderLink.tsx deleted file mode 100644 index 13d39fd5e..000000000 --- a/pkg/grid/src/components/ProviderLink.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import classNames from 'classnames'; -import React from 'react'; -import { Link, LinkProps } from 'react-router-dom'; -import { Contact, Provider } from '@urbit/api'; -import { ShipName } from './ShipName'; -import { Avatar, AvatarSizes } from './Avatar'; - -export type ProviderLinkProps = Omit & { - provider: { shipName: string } & Contact; - size?: AvatarSizes; - selected?: boolean; - to?: (p: Provider) => LinkProps['to']; -}; - -export const ProviderLink = ({ - provider, - to, - selected = false, - size = 'default', - className, - ...props -}: ProviderLinkProps) => { - const small = size === 'small' || size === 'xs'; - return ( - - -
-
- - {provider.nickname} -
- {provider.status && size === 'default' &&

{provider.status}

} -
- - ); -}; diff --git a/pkg/grid/src/components/ProviderList.tsx b/pkg/grid/src/components/ProviderList.tsx deleted file mode 100644 index 47d32adcf..000000000 --- a/pkg/grid/src/components/ProviderList.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import React, { MouseEvent, useCallback } from 'react'; -import { Contact, Provider } from '@urbit/api'; -import classNames from 'classnames'; -import { MatchItem } from '../nav/Nav'; -import { useRecentsStore } from '../nav/search/Home'; -import { ProviderLink, ProviderLinkProps } from './ProviderLink'; - -export type ProviderListProps = { - providers: ({ shipName: string } & Contact)[]; - labelledBy: string; - matchAgainst?: MatchItem; - onClick?: (e: MouseEvent, p: Provider) => void; - listClass?: string; -} & Omit; - -export function providerMatches(target: Provider, match?: MatchItem): boolean { - if (!match) { - return false; - } - - const matchValue = match.display || match.value; - return target.nickname === matchValue || target.shipName === matchValue; -} - -export const ProviderList = ({ - providers, - labelledBy, - matchAgainst, - onClick, - listClass, - size = 'default', - ...props -}: ProviderListProps) => { - const addRecentDev = useRecentsStore((state) => state.addRecentDev); - const selected = useCallback( - (provider: Provider) => providerMatches(provider, matchAgainst), - [matchAgainst] - ); - - return ( -
    - {providers.map((p) => ( -
  • - { - addRecentDev(p.shipName); - if (onClick) { - onClick(e, p); - } - }} - /> -
  • - ))} -
- ); -}; diff --git a/pkg/grid/src/components/Setting.tsx b/pkg/grid/src/components/Setting.tsx deleted file mode 100644 index 10fd5b716..000000000 --- a/pkg/grid/src/components/Setting.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import classNames from 'classnames'; -import React, { FC, HTMLAttributes } from 'react'; -import slugify from 'slugify'; -import { useAsyncCall } from '../logic/useAsyncCall'; -import { Spinner } from './Spinner'; -import { Toggle } from './Toggle'; - -type SettingsProps = { - name: string; - on: boolean; - disabled?: boolean; - toggle: (open: boolean) => Promise; -} & HTMLAttributes; - -export const Setting: FC = ({ - name, - on, - disabled = false, - toggle, - className, - children -}) => { - const { status, call } = useAsyncCall(toggle); - const id = slugify(name); - - return ( -
-

- {name} {status === 'loading' && } -

-
- -
{children}
-
-
- ); -}; diff --git a/pkg/grid/src/components/ShipName.tsx b/pkg/grid/src/components/ShipName.tsx deleted file mode 100644 index 4a49706b1..000000000 --- a/pkg/grid/src/components/ShipName.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { cite } from '@urbit/api'; -import React, { HTMLAttributes } from 'react'; - -type ShipNameProps = { - name: string; - truncate?: boolean; -} & HTMLAttributes; - -export const ShipName = ({ name, truncate = true, ...props }: ShipNameProps) => { - const separator = /([_^-])/; - const citedName = truncate ? cite(name) : name; - - if (!citedName) { - return null; - } - - const parts = citedName.replace('~', '').split(separator); - const first = parts.shift(); - - return ( - - ~ - {first} - {parts.length > 1 && ( - <> - {parts.map((piece, index) => ( - - {piece} - - ))} - - )} - - ); -}; diff --git a/pkg/grid/src/components/SourceSetter.tsx b/pkg/grid/src/components/SourceSetter.tsx deleted file mode 100644 index b37936f26..000000000 --- a/pkg/grid/src/components/SourceSetter.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import React, { useCallback, useState } from 'react'; -import { useAsyncCall } from '../logic/useAsyncCall'; -import { Button } from './Button'; -import { ShipName } from './ShipName'; -import { Spinner } from './Spinner'; - -interface SourceSetterProps { - appName: string; - srcDesk: string; - srcShip?: string; - title: string; - toggleSrc: (desk: string, ship: string) => Promise; -} - -export default function SourceSetter({ - appName, - srcDesk, - srcShip, - title, - toggleSrc -}: SourceSetterProps) { - const [newSyncShip, setNewSyncShip] = useState(srcShip ?? ''); - const { status: requestStatus, call: handleSubmit } = useAsyncCall(toggleSrc); - const syncDirty = newSyncShip !== srcShip; - - const onUnset = useCallback(() => { - if (!srcShip) { - return; - } - if ( - // eslint-disable-next-line no-alert, no-restricted-globals - confirm(`Are you sure you want to unsync ${appName}? You will no longer receive updates.`) - ) { - toggleSrc(srcDesk, srcShip); - } - }, [srcShip, srcDesk]); - - const handleSourceChange = useCallback((e: React.ChangeEvent) => { - const { target } = e; - const value = target.value.trim(); - setNewSyncShip(value.startsWith('~') ? value : `~${value}`); - }, []); - - const onSubmit = useCallback( - async (e: React.FormEvent) => { - e.preventDefault(); - await handleSubmit(srcDesk, newSyncShip); - }, - [srcDesk, newSyncShip] - ); - - return ( - <> -

{title}

-
- {srcShip ? ( - <> -

Automatic Updates

-

Automatically download and apply updates to keep {appName} up to date.

-
-

- OTA Source:{' '} - -

-
-
- -
- - ) : ( -
- -

Enter a valid urbit name to receive updates for {appName}.

-
- - {syncDirty && ( - - )} -
-
- )} -
- - ); -} diff --git a/pkg/grid/src/components/Spinner.tsx b/pkg/grid/src/components/Spinner.tsx deleted file mode 100644 index 5e7579a1a..000000000 --- a/pkg/grid/src/components/Spinner.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import classNames from 'classnames'; -import React from 'react'; -import { SpinnerIcon } from './icons/SpinnerIcon'; - -export const Spinner = ({ className, ...props }: React.HTMLAttributes) => ( - -); diff --git a/pkg/grid/src/components/Toggle.tsx b/pkg/grid/src/components/Toggle.tsx deleted file mode 100644 index 06cb194f5..000000000 --- a/pkg/grid/src/components/Toggle.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import classNames from 'classnames'; -import React, { useState } from 'react'; -import * as RadixToggle from '@radix-ui/react-toggle'; -import type * as Polymorphic from '@radix-ui/react-polymorphic'; - -type ToggleComponent = Polymorphic.ForwardRefComponent< - Polymorphic.IntrinsicElement, - Polymorphic.OwnProps & { - loading?: boolean; - toggleClass?: string; - knobClass?: string; - } ->; - -export const Toggle = React.forwardRef( - ( - { defaultPressed, pressed, onPressedChange, disabled, className, toggleClass, loading = false }, - ref - ) => { - const [on, setOn] = useState(defaultPressed); - const isControlled = !!onPressedChange; - const proxyPressed = isControlled ? pressed : on; - const proxyOnPressedChange = isControlled ? onPressedChange : setOn; - const knobPosition = proxyPressed ? 18 : 2; - - return ( - - - - - - - ); - } -) as ToggleComponent; diff --git a/pkg/grid/src/components/TreatyMeta.tsx b/pkg/grid/src/components/TreatyMeta.tsx deleted file mode 100644 index 00974bb70..000000000 --- a/pkg/grid/src/components/TreatyMeta.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import { daToDate, Treaty } from '@urbit/api'; - -import moment from 'moment'; -import { Attribute } from './Attribute'; - -const meta = ['license', 'website', 'version'] as const; - -export function TreatyMeta(props: { treaty: Treaty }) { - const { treaty } = props; - const { desk, ship, cass } = treaty; - return ( -
- - {ship}/{desk} - - - {moment(daToDate(cass.da)).format('YYYY.MM.DD')} - - {meta.map((d) => ( - - {treaty[d]} - - ))} -
- ); -} diff --git a/pkg/grid/src/components/icons/Adjust.tsx b/pkg/grid/src/components/icons/Adjust.tsx deleted file mode 100644 index d9aef173a..000000000 --- a/pkg/grid/src/components/icons/Adjust.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -export const Adjust = (props: React.SVGProps) => ( - - - -); diff --git a/pkg/grid/src/components/icons/Bullet.tsx b/pkg/grid/src/components/icons/Bullet.tsx deleted file mode 100644 index a5a2075d7..000000000 --- a/pkg/grid/src/components/icons/Bullet.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -export const Bullet = (props: React.SVGProps) => ( - - - -); diff --git a/pkg/grid/src/components/icons/Cross.tsx b/pkg/grid/src/components/icons/Cross.tsx deleted file mode 100644 index 70c41ddb2..000000000 --- a/pkg/grid/src/components/icons/Cross.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -export const Cross = (props: React.SVGProps) => ( - - - -); diff --git a/pkg/grid/src/components/icons/Elbow.tsx b/pkg/grid/src/components/icons/Elbow.tsx deleted file mode 100644 index 6b50598f2..000000000 --- a/pkg/grid/src/components/icons/Elbow.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React, { HTMLAttributes } from 'react'; - -type ElbowProps = HTMLAttributes; - -export const Elbow = (props: ElbowProps) => ( - - - -); diff --git a/pkg/grid/src/components/icons/Interface.tsx b/pkg/grid/src/components/icons/Interface.tsx deleted file mode 100644 index e0866da7a..000000000 --- a/pkg/grid/src/components/icons/Interface.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -export const Interface = (props: React.SVGProps) => ( - - - -); diff --git a/pkg/grid/src/components/icons/LeftArrow.tsx b/pkg/grid/src/components/icons/LeftArrow.tsx deleted file mode 100644 index b6a98f8b5..000000000 --- a/pkg/grid/src/components/icons/LeftArrow.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React, { HTMLAttributes } from 'react'; - -type LeftArrowProps = HTMLAttributes; - -export const LeftArrow = (props: LeftArrowProps) => ( - - - -); diff --git a/pkg/grid/src/components/icons/Lock.tsx b/pkg/grid/src/components/icons/Lock.tsx deleted file mode 100644 index d67eb952a..000000000 --- a/pkg/grid/src/components/icons/Lock.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; - -export const Lock = (props: React.SVGProps) => ( - - - -); diff --git a/pkg/grid/src/components/icons/Notifications.tsx b/pkg/grid/src/components/icons/Notifications.tsx deleted file mode 100644 index c4cabc2dd..000000000 --- a/pkg/grid/src/components/icons/Notifications.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -export const Notifications = (props: React.SVGProps) => ( - - - -); diff --git a/pkg/grid/src/components/icons/SpinnerIcon.tsx b/pkg/grid/src/components/icons/SpinnerIcon.tsx deleted file mode 100644 index 405b2821d..000000000 --- a/pkg/grid/src/components/icons/SpinnerIcon.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -export const SpinnerIcon = (props: React.SVGProps) => ( - - - - -); diff --git a/pkg/grid/src/components/icons/System.tsx b/pkg/grid/src/components/icons/System.tsx deleted file mode 100644 index 0a8b1a1ac..000000000 --- a/pkg/grid/src/components/icons/System.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; - -export const System = (props: React.SVGProps) => ( - - - - -); diff --git a/pkg/grid/src/env.d.ts b/pkg/grid/src/env.d.ts deleted file mode 100644 index 2fda24a0d..000000000 --- a/pkg/grid/src/env.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -interface ImportMetaEnv extends Readonly> { - readonly VITE_LAST_WIPE: string; - readonly VITE_STORAGE_VERSION: string; -} - -interface ImportMeta { - readonly env: ImportMetaEnv; -} diff --git a/pkg/grid/src/global.d.ts b/pkg/grid/src/global.d.ts deleted file mode 100644 index ce5215a80..000000000 --- a/pkg/grid/src/global.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -declare module 'urbit-ob' { - export function isValidPatp(patp: string): boolean; -} - -type Stringified = string & - { - [P in keyof T]: { '_ value': T[P] }; - }; - -interface JSON { - // stringify(value: any, replacer?: (key: string, value: any) => any, space?: string | number): string; - stringify( - value: T, - replacer?: (key: string, value: any) => any, - space?: string | number - ): string & Stringified; - // parse(text: string, reviver?: (key: any, value: any) => any): any; - parse(text: Stringified, reviver?: (key: any, value: any) => any): T; -} diff --git a/pkg/grid/src/logic/useAsyncCall.ts b/pkg/grid/src/logic/useAsyncCall.ts deleted file mode 100644 index 63ff02d7f..000000000 --- a/pkg/grid/src/logic/useAsyncCall.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { useCallback, useState } from 'react'; - -export type Status = 'initial' | 'loading' | 'success' | 'error'; - -export function useAsyncCall(cb: (...args: any[]) => Promise) { - const [status, setStatus] = useState('initial'); - const [error, setError] = useState(null); - - const call = useCallback( - (...args: any[]) => { - setStatus('loading'); - cb(...args) - .then((result) => { - setStatus('success'); - return result; - }) - .catch((err) => { - setError(err); - setStatus('error'); - }); - }, - [cb] - ); - - return { - call, - status, - error - }; -} diff --git a/pkg/grid/src/logic/useDebounce.ts b/pkg/grid/src/logic/useDebounce.ts deleted file mode 100644 index 550db124c..000000000 --- a/pkg/grid/src/logic/useDebounce.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { debounce, DebounceSettings } from 'lodash'; -import { useRef, useEffect, useCallback } from 'react'; -import { useIsMounted } from './useIsMounted'; - -export function useDebounce( - cb: (...args: any[]) => void, - delay: number, - options?: DebounceSettings -) { - const isMounted = useIsMounted(); - const inputsRef = useRef({ cb, delay }); // mutable ref like with useThrottle - - useEffect(() => { - inputsRef.current = { cb, delay }; - }); // also track cur. delay - - return useCallback( - debounce( - (...args) => { - // Debounce is an async callback. Cancel it, if in the meanwhile - // (1) component has been unmounted (see isMounted in snippet) - // (2) delay has changed - if (inputsRef.current.delay === delay && isMounted()) inputsRef.current.cb(...args); - }, - delay, - options - ), - [delay, debounce] - ); -} diff --git a/pkg/grid/src/logic/useErrorHandler.ts b/pkg/grid/src/logic/useErrorHandler.ts deleted file mode 100644 index bf5122e77..000000000 --- a/pkg/grid/src/logic/useErrorHandler.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { useErrorHandler as useBoundaryHandler } from 'react-error-boundary'; - -export function useErrorHandler() { - const handle = useBoundaryHandler(); - - function handleError(cb: (...args: any[]) => any) { - return (...args: any[]) => { - try { - cb(...args); - } catch (error) { - handle(error); - } - }; - } - - return handleError; -} diff --git a/pkg/grid/src/logic/useIsMounted.ts b/pkg/grid/src/logic/useIsMounted.ts deleted file mode 100644 index a35b8472b..000000000 --- a/pkg/grid/src/logic/useIsMounted.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useRef, useEffect } from 'react'; - -export function useIsMounted() { - const isMountedRef = useRef(true); - useEffect(() => { - return () => { - isMountedRef.current = false; - }; - }, []); - return () => isMountedRef.current; -} diff --git a/pkg/grid/src/logic/useMedia.ts b/pkg/grid/src/logic/useMedia.ts deleted file mode 100644 index 07c560ff0..000000000 --- a/pkg/grid/src/logic/useMedia.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { useCallback, useEffect, useState } from 'react'; - -export const useMedia = (mediaQuery: string) => { - const [match, setMatch] = useState(false); - - const update = useCallback((e: MediaQueryListEvent) => { - setMatch(e.matches); - }, []); - - useEffect(() => { - const query = window.matchMedia(mediaQuery); - - query.addEventListener('change', update); - update({ matches: query.matches } as MediaQueryListEvent); - return () => { - query.removeEventListener('change', update); - }; - }, [update]); - - return match; -}; diff --git a/pkg/grid/src/logic/useQuery.ts b/pkg/grid/src/logic/useQuery.ts deleted file mode 100644 index 142a15aff..000000000 --- a/pkg/grid/src/logic/useQuery.ts +++ /dev/null @@ -1,46 +0,0 @@ -import _ from 'lodash'; -import { useCallback, useMemo } from 'react'; -import { useLocation } from 'react-router-dom'; - -function mergeQuery(search: URLSearchParams, added: Record) { - _.forIn(added, (v, k) => { - if (v) { - search.append(k, v); - } else { - search.delete(k); - } - }); -} - -export function useQuery() { - const { search, pathname } = useLocation(); - - const query = useMemo(() => new URLSearchParams(search), [search]); - - const appendQuery = useCallback( - (added: Record) => { - const q = new URLSearchParams(search); - mergeQuery(q, added); - return q.toString(); - }, - [search] - ); - - const toQuery = useCallback( - (params: Record, path = pathname) => { - const q = new URLSearchParams(search); - mergeQuery(q, params); - return { - pathname: path, - search: q.toString() - }; - }, - [search, pathname] - ); - - return { - query, - appendQuery, - toQuery - }; -} diff --git a/pkg/grid/src/logic/useWaitForProps.ts b/pkg/grid/src/logic/useWaitForProps.ts deleted file mode 100644 index 278bb57b5..000000000 --- a/pkg/grid/src/logic/useWaitForProps.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { useCallback, useEffect, useState } from 'react'; - -export function useWaitForProps

(props: P, timeout = 0) { - const [mainResolve, setMainResolve] = useState<() => void>(() => () => {}); - const [ready, setReady] = useState<(p: P) => boolean | undefined>(); - - useEffect(() => { - if (typeof ready === 'function' && ready(props)) { - mainResolve(); - } - }, [props, ready, mainResolve]); - - /** - * Waits until some predicate is true - * - * @param r - Predicate to wait for - * @returns A promise that resolves when `r` returns true, or rejects if the - * waiting times out - * - */ - const waiter = useCallback( - (r: (props: P) => boolean) => { - setReady(() => r); - return new Promise((resolve, reject) => { - setMainResolve(() => resolve); - if (timeout > 0) { - setTimeout(() => { - reject(new Error('Timed out')); - }, timeout); - } - }); - }, - [setMainResolve, setReady, timeout] - ); - - return waiter; -} diff --git a/pkg/grid/src/main.tsx b/pkg/grid/src/main.tsx deleted file mode 100644 index ed91dc168..000000000 --- a/pkg/grid/src/main.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { App } from './app'; -import './styles/index.css'; - -ReactDOM.render( - - - , - document.getElementById('app') -); diff --git a/pkg/grid/src/nav/Help.tsx b/pkg/grid/src/nav/Help.tsx deleted file mode 100644 index 51db624b9..000000000 --- a/pkg/grid/src/nav/Help.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import helpAndSupport from '../assets/help-and-support.svg'; - -export const Help = () => { - return ( -

- -
-
-

For general help, ask the community

- - Join Urbit Community - -
-
-

For all other issues:

- - support@urbit.org - -
-
-
- ); -}; diff --git a/pkg/grid/src/nav/Leap.tsx b/pkg/grid/src/nav/Leap.tsx deleted file mode 100644 index fa293720c..000000000 --- a/pkg/grid/src/nav/Leap.tsx +++ /dev/null @@ -1,284 +0,0 @@ -import classNames from 'classnames'; -import React, { - ChangeEvent, - FocusEvent, - FormEvent, - KeyboardEvent, - HTMLAttributes, - useCallback, - useImperativeHandle, - useRef, - useEffect -} from 'react'; -import { Link, useHistory, useRouteMatch } from 'react-router-dom'; -import { Cross } from '../components/icons/Cross'; -import { useDebounce } from '../logic/useDebounce'; -import { useErrorHandler } from '../logic/useErrorHandler'; -import { MenuState, useLeapStore } from './Nav'; - -function normalizePathEnding(path: string) { - const end = path.length - 1; - return path[end] === '/' ? path.substring(0, end - 1) : path; -} - -export function createPreviousPath(current: string): string { - const parts = normalizePathEnding(current).split('/'); - parts.pop(); - - if (parts[parts.length - 1] === 'leap') { - parts.push('search'); - } - - return parts.join('/'); -} - -type LeapProps = { - menu: MenuState; - dropdown: string; - navOpen: boolean; - shouldDim: boolean; -} & HTMLAttributes; - -function normalizeMatchString(match: string, keepAltChars: boolean): string { - let normalizedString = match.toLocaleLowerCase().trim(); - - if (!keepAltChars) { - normalizedString = normalizedString.replace(/[^\w]/, ''); - } - - return normalizedString; -} - -export const Leap = React.forwardRef( - ({ menu, dropdown, navOpen, shouldDim, className }: LeapProps, ref) => { - const { push } = useHistory(); - const match = useRouteMatch<{ menu?: MenuState; query?: string; desk?: string }>( - `/leap/${menu}/:query?/(apps)?/:desk?` - ); - const appsMatch = useRouteMatch(`/leap/${menu}/${match?.params.query}/apps`); - const inputRef = useRef(null); - useImperativeHandle(ref, () => inputRef.current); - const { rawInput, selectedMatch, matches, selection, select } = useLeapStore(); - const handleError = useErrorHandler(); - - useEffect(() => { - const onTreaty = appsMatch && !appsMatch.isExact; - if (selection && rawInput === '' && !onTreaty) { - inputRef.current?.focus(); - } else if (selection && onTreaty) { - inputRef.current?.blur(); - } - }, [selection, rawInput, appsMatch]); - - useEffect(() => { - const newMatch = getMatch(rawInput); - if (newMatch && rawInput) { - useLeapStore.setState({ selectedMatch: newMatch }); - } - }, [rawInput, matches]); - - const toggleSearch = useCallback(() => { - if (selection || menu === 'search') { - return; - } - - push('/leap/search'); - }, [selection, menu]); - - const onFocus = useCallback( - (e: FocusEvent) => { - // refocusing tab with input focused is false trigger - const windowFocus = e.nativeEvent.currentTarget === document.body; - if (windowFocus) { - return; - } - - toggleSearch(); - }, - [toggleSearch] - ); - - const getMatch = useCallback( - (value: string) => { - const onlySymbols = !value.match(/[\w]/g); - const normValue = normalizeMatchString(value, onlySymbols); - return matches.find((m) => - normalizeMatchString(m.value, onlySymbols).startsWith(normValue) - ); - }, - [matches] - ); - - const navigateByInput = useCallback( - (input: string) => { - const normalizedValue = input - .trim() - .replace('%', '') - .replace(/(~?[\w^_-]{3,13})\//, '$1/apps/$1/'); - push(`/leap/${menu}/${normalizedValue}`); - }, - [menu] - ); - - const debouncedSearch = useDebounce( - (input: string) => { - if (!match || appsMatch) { - return; - } - - useLeapStore.setState({ searchInput: input }); - navigateByInput(input); - }, - 300, - { leading: true } - ); - - const handleSearch = useCallback(debouncedSearch, [match]); - - const onChange = useCallback( - handleError((e: ChangeEvent) => { - const input = e.target as HTMLInputElement; - const value = input.value.trim(); - const isDeletion = (e.nativeEvent as InputEvent).inputType === 'deleteContentBackward'; - const inputMatch = getMatch(value); - const matchValue = inputMatch?.value; - - if (matchValue && inputRef.current && !isDeletion) { - inputRef.current.value = matchValue; - const start = matchValue.startsWith(value) - ? value.length - : matchValue.substring(0, matchValue.indexOf(value)).length + value.length; - inputRef.current.setSelectionRange(start, matchValue.length); - useLeapStore.setState({ - rawInput: matchValue, - selectedMatch: inputMatch - }); - } else { - useLeapStore.setState({ - rawInput: value, - selectedMatch: matches[0] - }); - } - - handleSearch(value); - }), - [matches] - ); - - const onSubmit = useCallback( - handleError((e: FormEvent) => { - e.preventDefault(); - - const value = inputRef.current?.value.trim(); - const currentMatch = selectedMatch || (value && getMatch(value)); - - if (!currentMatch) { - return; - } - - if (currentMatch?.openInNewTab) { - window.open(currentMatch.url, currentMatch.value); - return; - } - - push(currentMatch.url); - useLeapStore.setState({ rawInput: '' }); - }), - [match, selectedMatch] - ); - - const onKeyDown = useCallback( - handleError((e: KeyboardEvent) => { - const deletion = e.key === 'Backspace' || e.key === 'Delete'; - const arrow = e.key === 'ArrowDown' || e.key === 'ArrowUp'; - - if (deletion && !rawInput && selection) { - e.preventDefault(); - select(null, appsMatch && !appsMatch.isExact ? undefined : match?.params.query); - const pathBack = createPreviousPath(match?.url || ''); - push(pathBack); - } - - if (arrow) { - e.preventDefault(); - if (matches.length === 0) { - return; - } - - const currentIndex = selectedMatch - ? matches.findIndex((m) => { - const matchValue = m.value; - const searchValue = selectedMatch.value; - return matchValue === searchValue; - }) - : 0; - const unsafeIndex = e.key === 'ArrowUp' ? currentIndex - 1 : currentIndex + 1; - const index = (unsafeIndex + matches.length) % matches.length; - - const newMatch = matches[index]; - useLeapStore.setState({ - rawInput: newMatch.value, - // searchInput: matchValue, - selectedMatch: newMatch - }); - } - }), - [selection, rawInput, match, matches, selectedMatch] - ); - - return ( -
-
- - {menu !== 'upgrading' ? ( - - ) : null} -
- {menu === 'search' && ( - select(null)} - > - - Close - - )} -
- ); - } -); diff --git a/pkg/grid/src/nav/Nav.tsx b/pkg/grid/src/nav/Nav.tsx deleted file mode 100644 index 89ecea223..000000000 --- a/pkg/grid/src/nav/Nav.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import { DialogContent } from '@radix-ui/react-dialog'; -import * as Portal from '@radix-ui/react-portal'; -import classNames from 'classnames'; -import React, { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react'; -import { ErrorBoundary } from 'react-error-boundary'; -import { Route, Switch, useHistory, useRouteMatch } from 'react-router-dom'; -import create from 'zustand'; -import { Dialog } from '../components/Dialog'; -import { ErrorAlert } from '../components/ErrorAlert'; -import { Help } from './Help'; -import { Leap } from './Leap'; -import { Notifications } from './Notifications'; -import { NotificationsLink } from './NotificationsLink'; -import { Search } from './Search'; -import { SystemMenu } from './SystemMenu'; -import { SystemPreferences } from './SystemPreferences'; - -export interface MatchItem { - url: string; - openInNewTab: boolean; - value: string; - display?: string; -} - -interface LeapStore { - rawInput: string; - searchInput: string; - matches: MatchItem[]; - selectedMatch?: MatchItem; - selection: React.ReactNode; - select: (selection: React.ReactNode, input?: string) => void; -} - -export const useLeapStore = create((set) => ({ - rawInput: '', - searchInput: '', - matches: [], - selectedMatch: undefined, - selection: null, - select: (selection: React.ReactNode, input?: string) => - set({ - rawInput: input || '', - searchInput: input || '', - selection - }) -})); - -window.leap = useLeapStore.getState; - -export type MenuState = - | 'closed' - | 'search' - | 'notifications' - | 'help-and-support' - | 'system-preferences' - | 'upgrading'; - -interface NavProps { - menu?: MenuState; -} - -export const Nav: FunctionComponent = ({ menu }) => { - const { push } = useHistory(); - const inputRef = useRef(null); - const navRef = useRef(null); - const dialogNavRef = useRef(null); - const systemMenuOpen = useRouteMatch('/system-menu'); - const [dialogContentOpen, setDialogContentOpen] = useState(false); - const select = useLeapStore((state) => state.select); - - const menuState = menu || 'closed'; - const isOpen = menuState !== 'upgrading' && menuState !== 'closed'; - const eitherOpen = isOpen || systemMenuOpen; - - useEffect(() => { - if (!isOpen) { - select(null); - setDialogContentOpen(false); - } - }, [isOpen]); - - const onOpen = useCallback( - (event: Event) => { - event.preventDefault(); - - setDialogContentOpen(true); - if (menu === 'search' && inputRef.current) { - setTimeout(() => { - inputRef.current?.focus(); - }, 0); - } - }, - [menu] - ); - - const onDialogClose = useCallback((open: boolean) => { - if (!open) { - push('/'); - } - }, []); - - const preventClose = useCallback((e) => { - const target = e.target as HTMLElement; - const hasNavAncestor = target.closest('#dialog-nav'); - - if (hasNavAncestor) { - e.preventDefault(); - } - }, []); - - return ( - push('/')}> - {/* Using portal so that we can retain the same nav items both in the dialog and in the base header */} - - - - - -
- - -
-
- - - - - - -
- -
- - ); -}; diff --git a/pkg/grid/src/nav/Notifications.tsx b/pkg/grid/src/nav/Notifications.tsx deleted file mode 100644 index 4b2fb3526..000000000 --- a/pkg/grid/src/nav/Notifications.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import React, { useEffect } from 'react'; -import { ErrorBoundary } from 'react-error-boundary'; -import { Link, NavLink, Route, RouteComponentProps, Switch } from 'react-router-dom'; -import { Button } from '../components/Button'; -import { ErrorAlert } from '../components/ErrorAlert'; -import { useHarkStore } from '../state/hark'; -import { Inbox } from './notifications/Inbox'; - -export const Notifications = ({ history }: RouteComponentProps) => { - const markAllAsRead = () => { - const { archiveAll } = useHarkStore.getState(); - archiveAll(); - }; - - useEffect(() => { - function visibilitychange() { - if (document.visibilityState === 'hidden') { - useHarkStore.getState().opened(); - } - } - document.addEventListener('visibilitychange', visibilitychange); - - return () => { - document.removeEventListener('visibilitychange', visibilitychange); - useHarkStore.getState().opened(); - }; - }, []); - // const select = useLeapStore((s) => s.select); - - return ( - history.push('/leap/notifications')} - > -
-
- - New - - - Archive - - - - -
- - - - - - - - -
-
- ); -}; diff --git a/pkg/grid/src/nav/NotificationsLink.tsx b/pkg/grid/src/nav/NotificationsLink.tsx deleted file mode 100644 index d7c01866e..000000000 --- a/pkg/grid/src/nav/NotificationsLink.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import classNames from 'classnames'; -import React, { useCallback } from 'react'; -import { Timebox } from '@urbit/api'; -import { Link, LinkProps } from 'react-router-dom'; -import { Bullet } from '../components/icons/Bullet'; -import { Cross } from '../components/icons/Cross'; -import { useHarkStore } from '../state/hark'; -import { useLeapStore } from './Nav'; -import { SettingsState, useSettingsState } from '../state/settings'; - -type NotificationsState = 'empty' | 'unread' | 'attention-needed' | 'open'; - -function getNotificationsState(isOpen: boolean, box: Timebox, dnd: boolean): NotificationsState { - const notifications = Object.values(box); - if (isOpen) { - return 'open'; - } - - if (dnd) { - return 'empty'; - } - - if ( - notifications.filter( - ({ bin }) => bin.place.desk === window.desk && ['/lag', 'blocked'].includes(bin.place.path) - ).length > 0 - ) { - return 'attention-needed'; - } - - // TODO: when real structure, this should be actually be unread not just existence - if (notifications.length > 0) { - return 'unread'; - } - - return 'empty'; -} - -type NotificationsLinkProps = Omit, 'to'> & { - navOpen: boolean; - notificationsOpen: boolean; - shouldDim: boolean; -}; - -const selDnd = (s: SettingsState) => s.display.doNotDisturb; - -export const NotificationsLink = ({ - navOpen, - notificationsOpen, - shouldDim -}: NotificationsLinkProps) => { - const unseen = useHarkStore((s) => s.unseen); - const dnd = useSettingsState(selDnd); - const state = getNotificationsState(notificationsOpen, unseen, dnd); - const select = useLeapStore((s) => s.select); - const clearSelection = useCallback(() => select(null), [select]); - - return ( - - {state === 'empty' && } - {state === 'unread' && Object.keys(unseen).length} - {state === 'attention-needed' && ( - - ! Attention needed - - )} - {state === 'open' && ( - <> - - Close - - )} - - ); -}; diff --git a/pkg/grid/src/nav/Search.tsx b/pkg/grid/src/nav/Search.tsx deleted file mode 100644 index ebcd5f4ee..000000000 --- a/pkg/grid/src/nav/Search.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import { Route, RouteComponentProps, Switch } from 'react-router-dom'; -import { ErrorBoundary } from 'react-error-boundary'; -import { TreatyInfo } from './search/TreatyInfo'; -import { Apps } from './search/Apps'; -import { Home } from './search/Home'; -import { Providers } from './search/Providers'; -import { ErrorAlert } from '../components/ErrorAlert'; - -type SearchProps = RouteComponentProps<{ - query?: string; -}>; - -export const Search = ({ match, history }: SearchProps) => { - return ( - history.push('/leap/search')}> - - - - - - - - ); -}; diff --git a/pkg/grid/src/nav/SystemMenu.tsx b/pkg/grid/src/nav/SystemMenu.tsx deleted file mode 100644 index fb2f0c51d..000000000 --- a/pkg/grid/src/nav/SystemMenu.tsx +++ /dev/null @@ -1,156 +0,0 @@ -import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; -import classNames from 'classnames'; -import clipboardCopy from 'clipboard-copy'; -import React, { HTMLAttributes, useCallback, useState } from 'react'; -import { Link, Route, useHistory } from 'react-router-dom'; -import { Pike } from '@urbit/api'; -import { Adjust } from '../components/icons/Adjust'; -import { usePike } from '../state/kiln'; -import { disableDefault, handleDropdownLink } from '../state/util'; -import { useMedia } from '../logic/useMedia'; -import { Cross } from '../components/icons/Cross'; -import { useLeapStore } from './Nav'; - -type SystemMenuProps = HTMLAttributes & { - open: boolean; - subMenuOpen: boolean; - shouldDim: boolean; -}; - -function getHash(pike: Pike): string { - const parts = pike.hash.split('.'); - return parts[parts.length - 1]; -} - -export const SystemMenu = ({ className, open, subMenuOpen, shouldDim }: SystemMenuProps) => { - const { push } = useHistory(); - const [copied, setCopied] = useState(false); - const garden = usePike(window.desk); - const hash = garden ? getHash(garden) : null; - const isMobile = useMedia('(max-width: 639px)'); - const select = useLeapStore((s) => s.select); - const clearSelection = useCallback(() => select(null), [select]); - - const copyHash = useCallback( - (event: Event) => { - event.preventDefault(); - if (!hash) { - return; - } - - setCopied(true); - clipboardCopy(hash); - - setTimeout(() => { - setCopied(false); - }, 1250); - }, - [hash] - ); - - const preventFlash = useCallback((e) => { - const target = e.target as HTMLElement; - - if (target.id !== 'system-menu-overlay') { - e.preventDefault(); - } - }, []); - - return ( - <> -
- setTimeout(() => !isOpen && push('/'), 15)} - > - - {!open && !subMenuOpen && ( - <> - - System Menu - - )} - {(open || subMenuOpen) && ( - <> - - Close - - )} - {/* trigger here just for anchoring the dropdown */} - - - - - - - - System Preferences - - - - Help and Support - - - - About - - {hash && ( - - Base Hash - - {!copied && {hash}} - {copied && 'copied!'} - - - )} - - - - -
- -
- - - ); -}; diff --git a/pkg/grid/src/nav/SystemPreferences.tsx b/pkg/grid/src/nav/SystemPreferences.tsx deleted file mode 100644 index 50e08fc5b..000000000 --- a/pkg/grid/src/nav/SystemPreferences.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import React, { PropsWithChildren, useCallback } from 'react'; -import { Link, Route, RouteComponentProps, Switch, useRouteMatch } from 'react-router-dom'; -import { ErrorBoundary } from 'react-error-boundary'; -import classNames from 'classnames'; -import { NotificationPrefs } from './preferences/NotificationPrefs'; -import { SystemUpdatePrefs } from './preferences/SystemUpdatePrefs'; -import { InterfacePrefs } from './preferences/InterfacePrefs'; -import { SecurityPrefs } from './preferences/SecurityPrefs'; -import { useCharges } from '../state/docket'; -import { AppPrefs } from './preferences/AppPrefs'; -import { DocketImage } from '../components/DocketImage'; -import { ErrorAlert } from '../components/ErrorAlert'; -import { useMedia } from '../logic/useMedia'; -import { LeftArrow } from '../components/icons/LeftArrow'; -import { System } from '../components/icons/System'; -import { Interface } from '../components/icons/Interface'; -import { Notifications } from '../components/icons/Notifications'; -import { Lock } from '../components/icons/Lock'; -import { getAppName } from '../state/util'; - -interface SystemPreferencesSectionProps { - url: string; - active: boolean; -} - -function SystemPreferencesSection({ - url, - active, - children -}: PropsWithChildren) { - return ( -
  • - - {children} - -
  • - ); -} - -export const SystemPreferences = (props: RouteComponentProps<{ submenu: string }>) => { - const { match, history } = props; - const subMatch = useRouteMatch<{ submenu: string; desk?: string }>( - `${match.url}/:submenu/:desk?` - ); - const charges = useCharges(); - const filteredCharges = Object.values(charges).filter((charge) => charge.desk !== window.desk); - const isMobile = useMedia('(max-width: 639px)'); - const settingsPath = isMobile ? `${match.url}/:submenu` : '/'; - - const matchSub = useCallback( - (target: string, desk?: string) => { - if (isMobile) { - return false; - } - - if (!subMatch && target === 'notifications') { - return true; - } - - if (desk && subMatch?.params.desk !== desk) { - return false; - } - - return subMatch?.params.submenu === target; - }, - [match, subMatch] - ); - - const subUrl = useCallback((submenu: string) => `${match.url}/${submenu}`, [match]); - - return ( - history.push('/leap/system-preferences')} - > -
    - - - - -
    - - - - - - - - - Back - -
    -
    -
    -
    - ); -}; diff --git a/pkg/grid/src/nav/notifications/BasicNotification.tsx b/pkg/grid/src/nav/notifications/BasicNotification.tsx deleted file mode 100644 index 1999323c7..000000000 --- a/pkg/grid/src/nav/notifications/BasicNotification.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import React from 'react'; -import cn from 'classnames'; -import { Notification, harkBinToId, HarkContent, HarkLid } from '@urbit/api'; -import { map, take } from 'lodash'; -import { useCharge } from '../../state/docket'; -import { Elbow } from '../../components/icons/Elbow'; -import { ShipName } from '../../components/ShipName'; -import { DeskLink } from '../../components/DeskLink'; -import { useHarkStore } from '../../state/hark'; -import { DocketImage } from '../../components/DocketImage'; -import { Button } from '../../components/Button'; - -interface BasicNotificationProps { - notification: Notification; - lid: HarkLid; -} - -const MAX_CONTENTS = 5; - -const NotificationText = ({ contents }: { contents: HarkContent[] }) => { - return ( - <> - {contents.map((content, idx) => { - if ('ship' in content) { - return ; - } - return content.text; - })} - - ); -}; - -export const BasicNotification = ({ notification, lid }: BasicNotificationProps) => { - const { desk } = notification.bin.place; - const binId = harkBinToId(notification.bin); - const id = `notif-${notification.time}-${binId}`; - - const charge = useCharge(desk); - const first = notification.body?.[0]; - if (!first || !charge) { - return null; - } - const orderedByTime = notification.body.sort((a, b) => a.time - b.time); - const contents = map(orderedByTime, 'content').filter((c) => c.length > 0); - const large = contents.length === 0; - const archive = () => { - useHarkStore.getState().archiveNote(notification.bin, lid); - }; - - const archiveNoFollow = (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - archive(); - }; - - return ( - -
    - -
    {charge?.title || desk}
    - {!large ? : null} -

    - -

    - {!('time' in lid) ? ( -
    - -
    - ) : null} -
    - {contents.length > 0 ? ( -
    - {take(contents, MAX_CONTENTS).map((content, i) => ( -

    - -

    - ))} - {contents.length > MAX_CONTENTS ? ( -

    and {contents.length - MAX_CONTENTS} more

    - ) : null} -
    - ) : null} -
    - ); -}; diff --git a/pkg/grid/src/nav/notifications/Inbox.tsx b/pkg/grid/src/nav/notifications/Inbox.tsx deleted file mode 100644 index 74d5b880b..000000000 --- a/pkg/grid/src/nav/notifications/Inbox.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import React, { useEffect } from 'react'; -import { HarkLid, Notification } from '@urbit/api'; -import { BasicNotification } from './BasicNotification'; -import { BaseBlockedNotification, RuntimeLagNotification } from './SystemNotification'; -import { useNotifications } from '../../state/notifications'; -import { useHarkStore } from '../../state/hark'; -import { OnboardingNotification } from './OnboardingNotification'; - -function renderNotification(notification: Notification, key: string, lid: HarkLid) { - // Special casing - if (notification.bin.place.desk === window.desk) { - if (notification.bin.place.path === '/lag') { - return ; - } - if (notification.bin.path === '/blocked' && notification.bin.place.path === '/desk/base') { - return ; - } - if (notification.bin.place.path === '/onboard') { - return ; - } - } - return ; -} - -const Empty = () => ( -
    - All clear! -
    -); - -export const Inbox = ({ archived = false }) => { - const { unseen, seen } = useNotifications(); - const archive = useHarkStore((s) => s.archive); - - useEffect(() => { - useHarkStore.getState().getMore(); - }, [archived]); - - if (archived ? archive.size === 0 : Object.keys({ ...seen, ...unseen }).length === 0) { - return ; - } - - return ( -
    - {archived ? ( - Array.from(archive).map(([key, box]) => { - return Object.entries(box) - .sort(([, a], [, b]) => b.time - a.time) - .map(([binId, n]) => - renderNotification(n, `${key.toString()}-${binId}`, { time: key.toString() }) - ); - }) - ) : ( - <> -
    Unseen
    -
    - {Object.entries(unseen) - .sort(([, a], [, b]) => b.time - a.time) - .map(([binId, n]) => renderNotification(n, `unseen-${binId}`, { unseen: null }))} -
    -
    Seen
    -
    - {Object.entries(seen) - .sort(([, a], [, b]) => b.time - a.time) - .map(([binId, n]) => renderNotification(n, `seen-${binId}`, { seen: null }))} -
    - - )} -
    - ); -}; diff --git a/pkg/grid/src/nav/notifications/NotificationButton.tsx b/pkg/grid/src/nav/notifications/NotificationButton.tsx deleted file mode 100644 index d8c27c999..000000000 --- a/pkg/grid/src/nav/notifications/NotificationButton.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import type * as Polymorphic from '@radix-ui/react-polymorphic'; -import classNames from 'classnames'; - -type NotificationButtonVariant = 'primary' | 'secondary' | 'destructive'; - -type PolymorphicButton = Polymorphic.ForwardRefComponent< - 'button', - { - variant?: NotificationButtonVariant; - } ->; - -const variants: Record = { - primary: 'text-blue bg-white', - secondary: 'text-black bg-white', - destructive: 'text-red-500 bg-white' -}; - -export const NotificationButton = React.forwardRef( - ({ as: Comp = 'button', variant = 'primary', children, className, ...props }, ref) => { - return ( - - {children} - - ); - } -) as PolymorphicButton; diff --git a/pkg/grid/src/nav/notifications/OnboardingNotification.tsx b/pkg/grid/src/nav/notifications/OnboardingNotification.tsx deleted file mode 100644 index df6a8896e..000000000 --- a/pkg/grid/src/nav/notifications/OnboardingNotification.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import React from 'react'; -import cn from 'classnames'; -import { Link } from 'react-router-dom'; -import { HarkLid, Pikes, getPikePublisher } from '@urbit/api'; -import { Button } from '../../components/Button'; -import { useBrowserId, useCurrentTheme } from '../../state/local'; -import { getDarkColor } from '../../state/util'; -import { usePikes } from '../../state/kiln'; -import { useHarkStore } from '../../state/hark'; -import { useProtocolHandling } from '../../state/settings'; - -const getCards = (pikes: Pikes, protocol: boolean): OnboardingCardProps[] => { - const cards = [ - { - title: 'Terminal', - body: "A web interface to your Urbit's command line (the dojo).", - button: 'Install', - color: '#9CA4B1', - href: '/leap/search/direct/apps/~mister-dister-dozzod-dozzod/webterm', - ship: '~mister-dister-dozzod-dozzod', - desk: 'webterm' - }, - { - title: 'Groups', - body: 'A suite of applications to communicate on Urbit', - button: 'Install', - color: '#D1DDD3', - href: '/leap/search/direct/apps/~lander-dister-dozzod-dozzod/landscape', - ship: '~lander-dister-dozzod-dozzod', - desk: 'landscape' - }, - { - title: 'Bitcoin', - body: ' A Bitcoin Wallet that lets you send and receive Bitcoin directly to and from other Urbit users', - button: 'Install', - color: '#F6EBDB', - href: '/leap/search/direct/apps/~mister-dister-dozzod-dozzod/bitcoin', - ship: '~mister-dister-dozzod-dozzod', - desk: 'bitcoin' - } - ]; - if ('registerProtocolHandler' in window.navigator && !protocol) { - cards.push({ - title: 'Open Urbit-Native Links', - body: 'Enable your Urbit to open links you find in the wild', - button: 'Enable Link Handler', - color: '#82A6CA', - href: '/leap/system-preferences/interface', - desk: '', - ship: '' - }); - } - - return cards.filter((card) => { - return !Object.values(pikes).find( - (pike) => getPikePublisher(pike) === card.ship && pike.sync?.desk === card.desk - ); - }); -}; - -if ('registerProtocolHandler' in window.navigator) { -} - -interface OnboardingCardProps { - title: string; - button: string; - href: string; - body: string; - color: string; - ship: string; - desk: string; -} - -const OnboardingCard = ({ title, button, href, body, color }: OnboardingCardProps) => ( -
    -
    -

    {title}

    -

    {body}

    -
    - -
    -); - -interface OnboardingNotificationProps { - unread?: boolean; - lid: HarkLid; -} - -export const OnboardingNotification = ({ unread = false, lid }: OnboardingNotificationProps) => { - const theme = useCurrentTheme(); - const pikes = usePikes(); - const browserId = useBrowserId(); - const protocolHandling = useProtocolHandling(browserId); - const cards = getCards(pikes, protocolHandling); - - if (cards.length === 0 && !('time' in lid)) { - useHarkStore.getState().archiveNote( - { - path: '/', - place: { - path: '/onboard', - desk: window.desk - } - }, - lid - ); - return null; - } - - return ( -
    -
    -
    - - System -
    -
    -

    Hello there, and welcome!

    -
    -
    -
    - { - /* eslint-disable-next-line react/no-array-index-key */ - cards.map((card, i) => ( - - )) - } -
    -
    - ); -}; diff --git a/pkg/grid/src/nav/notifications/SystemNotification.tsx b/pkg/grid/src/nav/notifications/SystemNotification.tsx deleted file mode 100644 index 0a123fcec..000000000 --- a/pkg/grid/src/nav/notifications/SystemNotification.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import { pick, partition } from 'lodash'; -import React, { useCallback } from 'react'; -import { HarkBin, HarkLid, kilnBump, Pike } from '@urbit/api'; -import { useHistory } from 'react-router-dom'; -import { AppList } from '../../components/AppList'; -import { Button } from '../../components/Button'; -import { Dialog, DialogClose, DialogContent, DialogTrigger } from '../../components/Dialog'; -import { Elbow } from '../../components/icons/Elbow'; -import api from '../../state/api'; -import { useCharges } from '../../state/docket'; -import useKilnState, { usePike } from '../../state/kiln'; - -import { NotificationButton } from './NotificationButton'; -import { disableDefault } from '../../state/util'; -import { useHarkStore } from '../../state/hark'; - -export const RuntimeLagNotification = () => ( -
    -
    -
    - - System -
    -
    - -

    The runtime blocked a System Update

    -
    -
    -
    -

    - In order to proceed with the System Update, you’ll need to upgrade the runtime. If you are - using a hosted ship, you should contact your hosting provider. -

    -
    -
    -); - -function pikeIsBlocked(newKelvin: number, pike: Pike) { - return pike.zest === 'live' && !pike.wefts?.find(({ kelvin }) => kelvin === newKelvin); -} - -export const BaseBlockedNotification = ({ bin, lid }: { bin: HarkBin, lid: HarkLid }) => { - const basePike = usePike('base'); - const { push } = useHistory(); - // TODO: assert weft.name === 'zuse'?? - const newKelvin = basePike?.wefts[0]?.kelvin ?? 417; - const charges = useCharges(); - const [blocked] = useKilnState((s) => { - const [b, u] = partition(Object.entries(s.pikes), ([, pike]) => pikeIsBlocked(newKelvin, pike)); - return [b.map(([d]) => d), u.map(([d]) => d)] as const; - }); - const { toggleInstall } = useKilnState(); - - const blockedCharges = Object.values(pick(charges, blocked)); - const count = blockedCharges.length; - - const handlePauseOTAs = useCallback(async () => { - await useHarkStore.getState().archiveNote(bin, lid); - }, []); - - const handleArchiveApps = useCallback(async () => { - await api.poke(kilnBump()); - await useHarkStore.getState().archiveNote(bin, lid); - - push('/leap/upgrading'); - }, []); - - return ( -
    -
    -
    - - System -
    -
    - -

    The following ({count}) apps blocked a System Update:

    -
    -
    - -
    -

    - In order to proceed with the System Update, you’ll need to temporarily suspend these apps. - This will render them unusable, but with data intact. -

    -

    - Suspended apps will automatically resume operation when their developer - provides an update. -

    -
    -
    - - Dismiss - -

    Delay System Update

    -

    - Are you sure you want to remain on an old version of Urbit - until these apps have been updated? -

    -
    - - Cancel - - - Remain on Old Version - -
    -
    -
    - - - Suspend ({count}) Apps and Apply Update - - -

    Suspend ({count}) Apps and Apply System Update

    -

    - The following apps will be suspended until their developer provides an update. -

    - -
    - - Cancel - - - Suspend Apps and Upgrade - -
    -
    -
    -
    -
    - ); -}; diff --git a/pkg/grid/src/nav/preferences/AppPrefs.tsx b/pkg/grid/src/nav/preferences/AppPrefs.tsx deleted file mode 100644 index 3cc00e1b9..000000000 --- a/pkg/grid/src/nav/preferences/AppPrefs.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import { RouteComponentProps } from 'react-router-dom'; -import SourceSetter from '../../components/SourceSetter'; -import { useCharge } from '../../state/docket'; -import useKilnState, { usePike } from '../../state/kiln'; -import { getAppName } from '../../state/util'; - -export const AppPrefs = ({ match }: RouteComponentProps<{ desk: string }>) => { - const { desk } = match.params; - const charge = useCharge(desk); - const appName = getAppName(charge); - const pike = usePike(desk); - const srcShip = pike?.sync?.ship; - const { toggleSync } = useKilnState(); - - return ( - - ); -}; diff --git a/pkg/grid/src/nav/preferences/InterfacePrefs.tsx b/pkg/grid/src/nav/preferences/InterfacePrefs.tsx deleted file mode 100644 index 9690d35a6..000000000 --- a/pkg/grid/src/nav/preferences/InterfacePrefs.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react'; -import { Setting } from '../../components/Setting'; -import { - setBrowserSetting, - useBrowserSettings, - useProtocolHandling, - useSettingsState -} from '../../state/settings'; -import { useBrowserId } from '../../state/local'; - -export function InterfacePrefs() { - const settings = useBrowserSettings(); - const browserId = useBrowserId(); - const protocolHandling = useProtocolHandling(browserId); - const secure = window.location.protocol === 'https:' || window.location.hostname === 'localhost'; - const linkHandlingAllowed = secure && 'registerProtocolHandler' in window.navigator; - const setProtocolHandling = (setting: boolean) => { - const newSettings = setBrowserSetting(settings, { protocolHandling: setting }, browserId); - useSettingsState - .getState() - .putEntry('browserSettings', 'settings', JSON.stringify(newSettings)); - }; - - const toggleProtoHandling = async () => { - if (!protocolHandling && window?.navigator?.registerProtocolHandler) { - try { - window.navigator.registerProtocolHandler( - 'web+urbitgraph', - '/apps/grid/perma?ext=%s', - 'Urbit Links' - ); - setProtocolHandling(true); - } catch (e) { - console.error(e); - } - } else if (protocolHandling && window.navigator?.unregisterProtocolHandler) { - try { - window.navigator.unregisterProtocolHandler('web+urbitgraph', '/apps/grid/perma?ext=%s'); - setProtocolHandling(false); - } catch (e) { - console.error(e); - } - } - }; - - return ( - <> -

    Interface Settings

    -
    - -

    - Automatically open urbit links when using this browser. - {!linkHandlingAllowed && ( - <> - - Unavailable with this browser/connection. - - - )} -

    -
    -
    - - ); -} diff --git a/pkg/grid/src/nav/preferences/NotificationPrefs.tsx b/pkg/grid/src/nav/preferences/NotificationPrefs.tsx deleted file mode 100644 index 61ef404b4..000000000 --- a/pkg/grid/src/nav/preferences/NotificationPrefs.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { setMentions } from '@urbit/api'; -import React from 'react'; -import { Setting } from '../../components/Setting'; -import { pokeOptimisticallyN } from '../../state/base'; -import { HarkState, reduceGraph, useHarkStore } from '../../state/hark'; -import { useBrowserId } from '../../state/local'; -import { - useSettingsState, - useBrowserNotifications, - useBrowserSettings, - SettingsState, - setBrowserSetting -} from '../../state/settings'; - -const selDnd = (s: SettingsState) => s.display.doNotDisturb; -async function toggleDnd() { - const state = useSettingsState.getState(); - const curr = selDnd(state); - await state.putEntry('display', 'doNotDisturb', !curr); -} - -const selMentions = (s: HarkState) => s.notificationsGraphConfig.mentions; -async function toggleMentions() { - const state = useHarkStore.getState(); - await pokeOptimisticallyN(useHarkStore, setMentions(!selMentions(state)), reduceGraph); -} - -export const NotificationPrefs = () => { - const doNotDisturb = useSettingsState(selDnd); - const mentions = useHarkStore(selMentions); - const settings = useBrowserSettings(); - const browserId = useBrowserId(); - const browserNotifications = useBrowserNotifications(browserId); - const secure = window.location.protocol === 'https:' || window.location.hostname === 'localhost'; - const notificationsAllowed = secure && 'Notification' in window; - - const setBrowserNotifications = (setting: boolean) => { - const newSettings = setBrowserSetting(settings, { browserNotifications: setting }, browserId); - useSettingsState - .getState() - .putEntry('browserSettings', 'settings', JSON.stringify(newSettings)); - }; - - const toggleNotifications = async () => { - if (!browserNotifications) { - Notification.requestPermission(); - setBrowserNotifications(true); - } else { - setBrowserNotifications(false); - } - }; - - return ( - <> -

    Notifications

    -
    - -

    - Blocks Urbit notifications in Landscape from appearing as badges and prevents browser - notifications if enabled. -

    -
    - -

    - Show desktop notifications in this browser. - {!secure && ( - <> - - Unavailable with this browser/connection. - - - )} -

    -
    - -

    Notify me if someone mentions my @p in a channel I've joined

    -
    -
    - - ); -}; diff --git a/pkg/grid/src/nav/preferences/SecurityPrefs.tsx b/pkg/grid/src/nav/preferences/SecurityPrefs.tsx deleted file mode 100644 index 10ab9d42e..000000000 --- a/pkg/grid/src/nav/preferences/SecurityPrefs.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, { useState } from 'react'; -import classNames from 'classnames'; -import { Button } from '../../components/Button'; -import { Checkbox } from '../../components/Checkbox'; - -export const SecurityPrefs = () => { - const [allSessions, setAllSessions] = useState(false); - - return ( - <> -

    Security

    -
    -
    -

    Logout

    -
    - setAllSessions((prev) => !prev)} - > - Log out of all sessions. - -
    - {allSessions && } - -
    -
    -
    -
    - - ); -}; diff --git a/pkg/grid/src/nav/preferences/SystemUpdatePrefs.tsx b/pkg/grid/src/nav/preferences/SystemUpdatePrefs.tsx deleted file mode 100644 index b08bd32dc..000000000 --- a/pkg/grid/src/nav/preferences/SystemUpdatePrefs.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import _ from 'lodash'; -import React from 'react'; -import SourceSetter from '../../components/SourceSetter'; -import useKilnState, { usePike } from '../../state/kiln'; - -export const SystemUpdatePrefs = () => { - const desk = 'base'; - const appName = 'your Urbit'; - const pike = usePike(desk); - const srcShip = pike?.sync?.ship; - const { toggleInstall } = useKilnState(); - - return ( - - ); -}; diff --git a/pkg/grid/src/nav/search/Apps.tsx b/pkg/grid/src/nav/search/Apps.tsx deleted file mode 100644 index 8bd04da58..000000000 --- a/pkg/grid/src/nav/search/Apps.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import React, { useCallback, useEffect, useMemo } from 'react'; -import { RouteComponentProps } from 'react-router-dom'; -import fuzzy from 'fuzzy'; -import { Treaty } from '@urbit/api'; -import { ShipName } from '../../components/ShipName'; -import { useAllyTreaties } from '../../state/docket'; -import { useLeapStore } from '../Nav'; -import { AppList } from '../../components/AppList'; -import { addRecentDev } from './Home'; -import { Spinner } from '../../components/Spinner'; - -type AppsProps = RouteComponentProps<{ ship: string }>; - -export const Apps = ({ match }: AppsProps) => { - const { searchInput, selectedMatch, select } = useLeapStore((state) => ({ - searchInput: state.searchInput, - select: state.select, - selectedMatch: state.selectedMatch - })); - const provider = match?.params.ship; - const { treaties, status } = useAllyTreaties(provider); - - useEffect(() => { - if (provider) { - addRecentDev(provider); - } - }, [provider]); - - const results = useMemo(() => { - if (!treaties) { - return undefined; - } - const values = Object.values(treaties); - return fuzzy - .filter( - searchInput, - values.map((v) => v.title) - ) - .sort((a, b) => { - const left = a.string.startsWith(searchInput) ? a.score + 1 : a.score; - const right = b.string.startsWith(searchInput) ? b.score + 1 : b.score; - - return right - left; - }) - .map((result) => values[result.index]); - }, [treaties, searchInput]); - const count = results?.length; - - const getAppPath = useCallback( - (app: Treaty) => `${match?.path.replace(':ship', provider)}/${app.ship}/${app.desk}`, - [match] - ); - - useEffect(() => { - select( - <> - Apps by - - ); - }, [provider]); - - useEffect(() => { - if (results) { - useLeapStore.setState({ - matches: results.map((r) => ({ - url: getAppPath(r), - openInNewTab: false, - value: r.desk, - display: r.title - })) - }); - } - }, [results]); - - const showNone = - status === 'error' || ((status === 'success' || status === 'initial') && results?.length === 0); - - return ( -
    - {status === 'loading' && ( - - Finding software... - - )} - {results && results.length > 0 && ( - <> -
    -

    - Software developed by -

    -

    - {count} result{count === 1 ? '' : 's'} -

    -
    - -

    That's it!

    - - )} - {showNone && ( -

    - Unable to find software developed by -

    - )} -
    - ); -}; diff --git a/pkg/grid/src/nav/search/Home.tsx b/pkg/grid/src/nav/search/Home.tsx deleted file mode 100644 index a5db6b462..000000000 --- a/pkg/grid/src/nav/search/Home.tsx +++ /dev/null @@ -1,169 +0,0 @@ -import produce from 'immer'; -import create from 'zustand'; -import _ from 'lodash'; -import React, { useEffect } from 'react'; -import { persist } from 'zustand/middleware'; -import { MatchItem, useLeapStore } from '../Nav'; -import { providerMatch } from './Providers'; -import { AppList } from '../../components/AppList'; -import { ProviderList } from '../../components/ProviderList'; -import { AppLink } from '../../components/AppLink'; -import { ShipName } from '../../components/ShipName'; -import { ProviderLink } from '../../components/ProviderLink'; -import useDocketState, { ChargesWithDesks, useCharges } from '../../state/docket'; -import { - clearStorageMigration, - createStorageKey, - getAppHref, - storageVersion -} from '../../state/util'; -import useContactState from '../../state/contact'; - -export interface RecentsStore { - recentApps: string[]; - recentDevs: string[]; - addRecentApp: (desk: string) => void; - addRecentDev: (ship: string) => void; - removeRecentApp: (desk: string) => void; -} - -export const useRecentsStore = create( - persist( - (set) => ({ - recentApps: [], - recentDevs: [], - addRecentApp: (desk: string) => { - set( - produce((draft: RecentsStore) => { - const hasApp = draft.recentApps.find((testDesk) => testDesk === desk); - if (!hasApp) { - draft.recentApps.unshift(desk); - } - - draft.recentApps = _.take(draft.recentApps, 3); - }) - ); - }, - addRecentDev: (dev) => { - set( - produce((draft: RecentsStore) => { - const hasDev = draft.recentDevs.includes(dev); - if (!hasDev) { - draft.recentDevs.unshift(dev); - } - - draft.recentDevs = _.take(draft.recentDevs, 3); - }) - ); - }, - removeRecentApp: (desk: string) => { - set( - produce((draft: RecentsStore) => { - _.remove(draft.recentApps, (test) => test === desk); - }) - ); - } - }), - { - whitelist: ['recentApps', 'recentDevs'], - name: createStorageKey('recents-store'), - version: storageVersion, - migrate: clearStorageMigration - } - ) -); - -window.recents = useRecentsStore.getState; - -export function addRecentDev(dev: string) { - return useRecentsStore.getState().addRecentDev(dev); -} - -export function addRecentApp(app: string) { - return useRecentsStore.getState().addRecentApp(app); -} - -function getApps(desks: string[], charges: ChargesWithDesks) { - return desks.filter((desk) => desk in charges).map((desk) => charges[desk]); -} - -export const Home = () => { - const selectedMatch = useLeapStore((state) => state.selectedMatch); - const { recentApps, recentDevs } = useRecentsStore(); - const charges = useCharges(); - const groups = charges?.landscape; - const contacts = useContactState((s) => s.contacts); - const defaultAlly = useDocketState((s) => - s.defaultAlly ? { shipName: s.defaultAlly, ...contacts[s.defaultAlly] } : null - ); - const providerList = recentDevs.map((d) => ({ shipName: d, ...contacts[d] })); - const apps = getApps(recentApps, charges); - - useEffect(() => { - const appMatches = apps.map((app) => ({ - url: getAppHref(app.href), - openInNewTab: true, - value: app.desk, - display: app.title - })); - const devs = recentDevs.map(providerMatch); - - useLeapStore.setState({ - matches: ([] as MatchItem[]).concat(appMatches, devs) - }); - }, [recentApps, recentDevs]); - - return ( -
    -

    - Recent Apps -

    - {apps.length === 0 && ( -
    -

    Apps you use will be listed here, in the order you used them.

    -

    You can click/tap/keyboard on a listed app to open it.

    - {groups && ( - addRecentApp('groups')} - /> - )} -
    - )} - {apps.length > 0 && ( - - )} -
    -

    - Recent Developers -

    - {recentDevs.length === 0 && ( -
    -

    Urbit app developers you search for will be listed here.

    - {defaultAlly && ( - <> -

    - Try out app discovery by visiting below. -

    - addRecentDev(defaultAlly.shipName)} - /> - - )} -
    - )} - {recentDevs.length > 0 && ( - - )} -
    - ); -}; diff --git a/pkg/grid/src/nav/search/Providers.tsx b/pkg/grid/src/nav/search/Providers.tsx deleted file mode 100644 index 5c32e36bd..000000000 --- a/pkg/grid/src/nav/search/Providers.tsx +++ /dev/null @@ -1,160 +0,0 @@ -import React, { useEffect, useMemo } from 'react'; -import { RouteComponentProps } from 'react-router-dom'; -import fuzzy from 'fuzzy'; -import { Provider, deSig } from '@urbit/api'; -import * as ob from 'urbit-ob'; -import { MatchItem, useLeapStore } from '../Nav'; -import { useAllies, useCharges } from '../../state/docket'; -import { ProviderList } from '../../components/ProviderList'; -import useContactState from '../../state/contact'; -import { AppList } from '../../components/AppList'; -import { getAppHref } from '../../state/util'; - -type ProvidersProps = RouteComponentProps<{ ship: string }>; - -export function providerMatch(provider: Provider | string): MatchItem { - const value = typeof provider === 'string' ? provider : provider.shipName; - const display = typeof provider === 'string' ? undefined : provider.nickname; - - return { - value, - display, - url: `/leap/search/${value}/apps`, - openInNewTab: false - }; -} - -function fuzzySort(search: string) { - return (a: fuzzy.FilterResult, b: fuzzy.FilterResult): number => { - const left = a.string.startsWith(search) ? a.score + 1 : a.score; - const right = b.string.startsWith(search) ? b.score + 1 : b.score; - - return right - left; - }; -} - -export const Providers = ({ match }: ProvidersProps) => { - const selectedMatch = useLeapStore((state) => state.selectedMatch); - const provider = match?.params.ship; - const contacts = useContactState((s) => s.contacts); - const charges = useCharges(); - const allies = useAllies(); - const search = provider || ''; - const chargeArray = Object.entries(charges); - const appResults = useMemo( - () => - charges - ? fuzzy - .filter( - search, - chargeArray.map(([desk, charge]) => charge.title + desk) - ) - .sort(fuzzySort(search)) - .map((el) => chargeArray[el.index][1]) - : [], - [charges, search] - ); - - const patp = `~${deSig(search) || ''}`; - const isValidPatp = ob.isValidPatp(patp); - - const results = useMemo(() => { - if (!allies) { - return []; - } - const exact = - isValidPatp && !Object.keys(allies).includes(patp) - ? [ - { - shipName: patp, - ...contacts[patp] - } - ] - : []; - return [ - ...exact, - ...fuzzy - .filter( - search, - Object.entries(allies).map(([ship]) => ship) - ) - .sort(fuzzySort(search)) - .map((el) => ({ shipName: el.original, ...contacts[el.original] })) - ]; - }, [allies, search, contacts]); - - const count = results?.length; - - useEffect(() => { - if (search) { - useLeapStore.setState({ rawInput: search }); - } - }, []); - - useEffect(() => { - if (results) { - const providerMatches = results ? results.map(providerMatch) : []; - const appMatches = appResults - ? appResults.map((app) => ({ - url: getAppHref(app.href), - openInNewTab: true, - value: app.desk, - display: app.title - })) - : []; - - const newProviderMatches = isValidPatp - ? [ - { - url: `/leap/search/${patp}/apps`, - value: patp, - display: patp, - openInNewTab: false - } - ] - : []; - - useLeapStore.setState({ - matches: ([] as MatchItem[]).concat(appMatches, providerMatches, newProviderMatches) - }); - } - }, [results, patp, isValidPatp]); - - return ( -
    - {appResults && !(results?.length > 0 && appResults.length === 0) && ( -
    -

    - Installed Apps -

    - -
    - )} - {results && !(appResults?.length > 0 && results.length === 0) && ( -
    -
    -

    Searching Software Providers

    -

    - {count} result{count === 1 ? '' : 's'} -

    -
    - -
    - )} -

    That's it!

    -
    - ); -}; diff --git a/pkg/grid/src/nav/search/TreatyInfo.tsx b/pkg/grid/src/nav/search/TreatyInfo.tsx deleted file mode 100644 index ac305e0d7..000000000 --- a/pkg/grid/src/nav/search/TreatyInfo.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React, { useEffect } from 'react'; -import { useParams } from 'react-router-dom'; -import { AppInfo } from '../../components/AppInfo'; -import { Spinner } from '../../components/Spinner'; -import useDocketState, { useCharge, useTreaty } from '../../state/docket'; -import { usePike } from '../../state/kiln'; -import { getAppName } from '../../state/util'; -import { useLeapStore } from '../Nav'; - -export const TreatyInfo = () => { - const select = useLeapStore((state) => state.select); - const { host, desk } = useParams<{ host: string; desk: string }>(); - const treaty = useTreaty(host, desk); - const pike = usePike(desk); - const charge = useCharge(desk); - const name = getAppName(treaty); - - useEffect(() => { - if (!charge) { - useDocketState.getState().requestTreaty(host, desk); - } - }, [host, desk]); - - useEffect(() => { - select(<>{name}); - useLeapStore.setState({ matches: [] }); - }, [name]); - - if (!treaty) { - // TODO: maybe replace spinner with skeletons - return ( -
    - -
    - ); - } - return ; -}; diff --git a/pkg/grid/src/pages/Grid.tsx b/pkg/grid/src/pages/Grid.tsx deleted file mode 100644 index 858cae3bf..000000000 --- a/pkg/grid/src/pages/Grid.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import React, { FunctionComponent, useEffect } from 'react'; -import { ErrorBoundary } from 'react-error-boundary'; -import { Route, useHistory, useParams } from 'react-router-dom'; -import { ErrorAlert } from '../components/ErrorAlert'; -import { MenuState, Nav } from '../nav/Nav'; -import useKilnState from '../state/kiln'; -import { RemoveApp } from '../tiles/RemoveApp'; -import { SuspendApp } from '../tiles/SuspendApp'; -import { TileGrid } from '../tiles/TileGrid'; - -import { TileInfo } from '../tiles/TileInfo'; - -interface RouteProps { - menu?: MenuState; -} - -export const Grid: FunctionComponent = () => { - const { push } = useHistory(); - const { menu } = useParams(); - - useEffect(() => { - // TOOD: rework - // Heuristically detect reload completion and redirect - async function attempt(count = 0) { - if (count > 5) { - window.location.reload(); - } - const start = performance.now(); - await useKilnState.getState().fetchPikes(); - await useKilnState.getState().fetchPikes(); - if (performance.now() - start > 5000) { - attempt(count + 1); - } else { - push('/'); - } - } - if (menu === 'upgrading') { - attempt(); - } - }, [menu]); - - return ( -
    -
    -
    - -
    - - push('/')}> - - - - - - - - - - -
    -
    - ); -}; diff --git a/pkg/grid/src/pages/PermalinkRoutes.tsx b/pkg/grid/src/pages/PermalinkRoutes.tsx deleted file mode 100644 index 5a412c18f..000000000 --- a/pkg/grid/src/pages/PermalinkRoutes.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { Pikes } from '@urbit/api'; -import React, { useEffect } from 'react'; -import { Switch, Route, Redirect, RouteComponentProps } from 'react-router-dom'; -import { Spinner } from '../components/Spinner'; -import { useQuery } from '../logic/useQuery'; -import { useCharge } from '../state/docket'; -import { useKilnLoaded, usePikes } from '../state/kiln'; -import { getAppHref } from '../state/util'; - -function getDeskByForeignRef(pikes: Pikes, ship: string, desk: string): string | undefined { - const found = Object.entries(pikes).find( - ([, pike]) => pike.sync?.ship === ship && pike.sync?.desk === desk - ); - return found ? found[0] : undefined; -} - -type AppLinkProps = RouteComponentProps<{ - ship: string; - desk: string; - link: string; -}>; - -function AppLink({ match, history, location }: AppLinkProps) { - const { ship, desk, link = '' } = match.params; - const pikes = usePikes(); - const ourDesk = getDeskByForeignRef(pikes, ship, desk); - - if (ourDesk) { - return ; - } - return ; -} - -function AppLinkNotFound({ match }: AppLinkProps) { - const { ship, desk } = match.params; - return ; -} - -function AppLinkInvalid() { - return ( -
    -

    Link was malformed

    -

    The link you tried to follow was invalid

    -
    - ); -} -function AppLinkRedirect({ desk, link }: { desk: string; link: string }) { - const charge = useCharge(desk); - - useEffect(() => { - if (!charge) { - return; - } - - const query = new URLSearchParams({ - 'grid-link': encodeURIComponent(`/${link}`) - }); - - const url = `${getAppHref(charge.href)}?${query.toString()}`; - window.open(url, desk); - }, [charge]); - - return ; -} - -const LANDSCAPE_DESK = 'landscape'; -const LANDSCAPE_HOST = '~lander-dister-dozzod-dozzod'; - -function LandscapeLink({ match }: RouteComponentProps<{ link: string }>) { - const { link } = match.params; - - return ; -} - -export function PermalinkRoutes() { - const loaded = useKilnLoaded(); - - const { query } = useQuery(); - - if (query.has('ext')) { - const ext = query.get('ext')!; - const url = `/perma${ext.slice(16)}`; - return ; - } - - if (!loaded) { - return ; - } - - return ( - - - - - - ); -} diff --git a/pkg/grid/src/state/api.ts b/pkg/grid/src/state/api.ts deleted file mode 100644 index 2e4058fa8..000000000 --- a/pkg/grid/src/state/api.ts +++ /dev/null @@ -1,24 +0,0 @@ -import Urbit from '@urbit/http-api'; -import { useMockData } from './util'; - -declare global { - interface Window { - ship: string; - } -} - -const api = useMockData - ? ({ - poke: async () => {}, - subscribe: async () => {}, - subscribeOnce: async () => {}, - ship: '', - scry: async () => {} - } as unknown as Urbit) - : new Urbit('', ''); -if (import.meta.env.DEV || useMockData) { - api.verbose = true; -} -api.ship = useMockData ? 'dopzod' : window.ship; - -export default api; diff --git a/pkg/grid/src/state/base.ts b/pkg/grid/src/state/base.ts deleted file mode 100644 index 5041cf649..000000000 --- a/pkg/grid/src/state/base.ts +++ /dev/null @@ -1,196 +0,0 @@ -/* eslint-disable no-param-reassign */ -import { applyPatches, Patch, produceWithPatches, setAutoFreeze, enablePatches } from 'immer'; -import { compose } from 'lodash/fp'; -import _ from 'lodash'; -import create, { GetState, SetState, UseStore } from 'zustand'; -import { persist } from 'zustand/middleware'; -import Urbit, { FatalError, SubscriptionRequestInterface } from '@urbit/http-api'; -import { Poke } from '@urbit/api'; -import api from './api'; -import { clearStorageMigration, createStorageKey, storageVersion, useMockData } from './util'; - -setAutoFreeze(false); -enablePatches(); - -export const stateSetter = >( - fn: (state: Readonly>) => void, - set: (newState: T & BaseState) => void, - get: () => T & BaseState -): void => { - const old = get(); - const [state] = produceWithPatches(old, fn) as readonly [T & BaseState, any, Patch[]]; - // console.log(patches); - set(state); -}; - -export const optStateSetter = >( - fn: (state: T & BaseState) => void, - set: (newState: T & BaseState) => void, - get: () => T & BaseState -): string => { - const old = get(); - const id = _.uniqueId(); - const [state, , patches] = produceWithPatches(old, fn) as readonly [ - T & BaseState, - any, - Patch[] - ]; - set({ ...state, patches: { ...state.patches, [id]: patches } }); - return id; -}; - -export const reduceState = , U>( - state: UseStore>, - data: U, - reducers: ((data: U, state: S & BaseState) => S & BaseState)[] -): void => { - const reducer = compose(reducers.map((r) => (sta) => r(data, sta))); - state.getState().set((s) => { - reducer(s); - }); -}; - -export const reduceStateN = , U>( - state: S & BaseState, - data: U, - reducers: ((data: U, state: S & BaseState) => S & BaseState)[] -): void => { - const reducer = compose(reducers.map((r) => (sta) => r(data, sta))); - state.set(reducer); -}; - -export const optReduceState = , U>( - state: UseStore>, - data: U, - reducers: ((data: U, state: S & BaseState) => BaseState & S)[] -): string => { - const reducer = compose(reducers.map((r) => (sta) => r(data, sta))); - return state.getState().optSet((s) => { - reducer(s); - }); -}; - -/* eslint-disable-next-line import/no-mutable-exports */ -export let stateStorageKeys: string[] = []; - -export const stateStorageKey = (stateName: string): string => { - const key = createStorageKey(`${stateName}State`); - stateStorageKeys = [...new Set([...stateStorageKeys, key])]; - return key; -}; - -(window as any).clearStates = () => { - stateStorageKeys.forEach((key) => { - localStorage.removeItem(key); - }); -}; - -export interface BaseState> { - rollback: (id: string) => void; - patches: { - [id: string]: Patch[]; - }; - set: (fn: (state: StateType & BaseState) => void) => void; - addPatch: (id: string, ...patch: Patch[]) => void; - removePatch: (id: string) => void; - optSet: (fn: (state: StateType & BaseState) => void) => string; - initialize: (api: Urbit) => Promise; -} - -export function createSubscription( - app: string, - path: string, - e: (data: any) => void -): SubscriptionRequestInterface { - const request = { - app, - path, - event: e, - err: () => {}, - quit: () => { - throw new FatalError("subscription clogged"); - } - }; - // TODO: err, quit handling (resubscribe?) - return request; -} - -export const createState = >( - name: string, - properties: T | ((set: SetState>, get: GetState>) => T), - blacklist: (keyof BaseState | keyof T)[] = [], - subscriptions: (( - set: SetState>, - get: GetState> - ) => SubscriptionRequestInterface)[] = [] -): UseStore> => - create>( - persist>( - (set, get) => ({ - initialize: async (airlock: Urbit) => { - await Promise.all(subscriptions.map((sub) => airlock.subscribe(sub(set, get)))); - }, - set: (fn) => stateSetter(fn, set, get), - optSet: (fn) => { - return optStateSetter(fn, set, get); - }, - patches: {}, - addPatch: (id: string, patch: Patch[]) => { - set((s) => ({ ...s, patches: { ...s.patches, [id]: patch } })); - }, - removePatch: (id: string) => { - set((s) => ({ ...s, patches: _.omit(s.patches, id) })); - }, - rollback: (id: string) => { - set((state) => { - const applying = state.patches[id]; - return { ...applyPatches(state, applying), patches: _.omit(state.patches, id) }; - }); - }, - ...(typeof properties === 'function' ? (properties as any)(set, get) : properties) - }), - { - blacklist, - name: stateStorageKey(name), - version: storageVersion, - migrate: clearStorageMigration - } - ) - ); - -export async function doOptimistically>( - state: UseStore>, - action: A, - call: (a: A) => Promise, - reduce: ((a: A, fn: S & BaseState) => S & BaseState)[] -) { - let num: string | undefined; - try { - num = optReduceState(state, action, reduce); - await call(action); - state.getState().removePatch(num); - } catch (e) { - console.error(e); - if (num) { - state.getState().rollback(num); - } - } -} - -export async function pokeOptimisticallyN>( - state: UseStore>, - poke: Poke, - reduce: ((a: A, fn: S & BaseState) => S & BaseState)[] -) { - let num: string | undefined; - try { - num = optReduceState(state, poke.json, reduce); - await (useMockData ? new Promise((res) => setTimeout(res, 500)) : api.poke(poke)); - state.getState().removePatch(num); - } catch (e) { - console.error(e); - if (num) { - state.getState().rollback(num); - } - } -} diff --git a/pkg/grid/src/state/contact.ts b/pkg/grid/src/state/contact.ts deleted file mode 100644 index 40bf49bdb..000000000 --- a/pkg/grid/src/state/contact.ts +++ /dev/null @@ -1,134 +0,0 @@ -/* eslint-disable no-param-reassign */ -import { Contact, ContactEditFieldPrim, ContactUpdate, deSig, Patp, Rolodex } from '@urbit/api'; -import { useCallback } from 'react'; -import _ from 'lodash'; -import { BaseState, createState, createSubscription, reduceStateN } from './base'; -import { useMockData } from './util'; -import { mockContacts } from './mock-data'; - -export interface BaseContactState { - contacts: Rolodex; - isContactPublic: boolean; - nackedContacts: Set; - [ref: string]: unknown; -} - -type ContactState = BaseContactState & BaseState; - -const initial = (json: ContactUpdate, state: ContactState): ContactState => { - const data = _.get(json, 'initial', false); - if (data) { - state.contacts = data.rolodex; - state.isContactPublic = data['is-public']; - } - return state; -}; - -const add = (json: ContactUpdate, state: ContactState): ContactState => { - const data = _.get(json, 'add', false); - if (data) { - state.contacts[data.ship] = data.contact; - } - return state; -}; - -const remove = (json: ContactUpdate, state: ContactState): ContactState => { - const data = _.get(json, 'remove', false); - if (data && data.ship in state.contacts) { - delete state.contacts[data.ship]; - } - return state; -}; - -export const edit = (json: ContactUpdate, state: ContactState): ContactState => { - const data = _.get(json, 'edit', false); - const ship = `~${deSig(data.ship)}`; - if (data && ship in state.contacts) { - const [field] = Object.keys(data['edit-field']); - if (!field) { - return state; - } - - const value = data['edit-field'][field]; - if (field === 'add-group') { - if (typeof value !== 'string') { - state.contacts[ship].groups.push(`/ship/${Object.values(value).join('/')}`); - } else if (!state.contacts[ship].groups.includes(value)) { - state.contacts[ship].groups.push(value); - } - } else if (field === 'remove-group') { - if (typeof value !== 'string') { - state.contacts[ship].groups = state.contacts[ship].groups.filter( - (g) => g !== `/ship/${Object.values(value).join('/')}` - ); - } else { - state.contacts[ship].groups = state.contacts[ship].groups.filter((g) => g !== value); - } - } else { - const k = field as ContactEditFieldPrim; - state.contacts[ship][k] = value; - } - } - return state; -}; - -const setPublic = (json: ContactUpdate, state: ContactState): ContactState => { - const data = _.get(json, 'set-public', state.isContactPublic); - state.isContactPublic = data; - return state; -}; - -export const reduceNacks = ( - json: { resource?: { res: string } }, - state: ContactState -): ContactState => { - const data = json?.resource; - if (data) { - state.nackedContacts.add(`~${data.res}`); - } - return state; -}; - -export const reduce = [initial, add, remove, edit, setPublic]; - -const useContactState = createState( - 'Contact', - { - contacts: {}, - nackedContacts: new Set(), - isContactPublic: false - }, - ['nackedContacts'], - [ - (set, get) => - createSubscription('contact-pull-hook', '/nacks', (e) => { - const data = e?.resource; - if (data) { - reduceStateN(get(), data, [reduceNacks]); - } - }), - (set, get) => - createSubscription('contact-store', '/all', (e) => { - const data = _.get(e, 'contact-update', false); - if (data) { - reduceStateN(get(), data, reduce); - } - }) - ] -); - -if (useMockData) { - useContactState.setState({ contacts: mockContacts }); -} - -export function useContact(ship: string) { - return useContactState( - useCallback((s) => s.contacts[`~${deSig(ship)}`] as Contact | null, [ship]) - ); -} - -export function useOurContact() { - return useContact(`~${window.ship}`); -} - -export default useContactState; diff --git a/pkg/grid/src/state/docket.ts b/pkg/grid/src/state/docket.ts deleted file mode 100644 index 779ab4c18..000000000 --- a/pkg/grid/src/state/docket.ts +++ /dev/null @@ -1,364 +0,0 @@ -import create, { SetState } from 'zustand'; -import produce from 'immer'; -import { useCallback, useEffect, useState } from 'react'; -import { omit, pick } from 'lodash'; -import { - Allies, - Charge, - ChargeUpdateInitial, - scryAllies, - scryAllyTreaties, - scryCharges, - scryDefaultAlly, - Treaty, - Docket, - Treaties, - chadIsRunning, - AllyUpdateIni, - AllyUpdateNew, - TreatyUpdateIni, - TreatyUpdate, - docketInstall, - ChargeUpdate, - kilnRevive, - kilnSuspend, - allyShip -} from '@urbit/api'; -import api from './api'; -import { mockAllies, mockCharges, mockTreaties } from './mock-data'; -import { fakeRequest, normalizeUrbitColor, useMockData } from './util'; -import { Status } from '../logic/useAsyncCall'; - -export interface ChargeWithDesk extends Charge { - desk: string; -} - -export interface ChargesWithDesks { - [ref: string]: ChargeWithDesk; -} - -export interface DocketWithDesk extends Docket { - desk: string; -} - -interface DocketState { - charges: ChargesWithDesks; - treaties: Treaties; - allies: Allies; - defaultAlly: string | null; - fetchCharges: () => Promise; - fetchDefaultAlly: () => Promise; - requestTreaty: (ship: string, desk: string) => Promise; - fetchAllies: () => Promise; - fetchAllyTreaties: (ally: string) => Promise; - toggleDocket: (desk: string) => Promise; - installDocket: (ship: string, desk: string) => Promise; - uninstallDocket: (desk: string) => Promise; - // - addAlly: (ship: string) => Promise; - set: SetState; -} - -const useDocketState = create((set, get) => ({ - defaultAlly: useMockData ? '~zod' : null, - fetchDefaultAlly: async () => { - const defaultAlly = await api.scry(scryDefaultAlly); - set({ defaultAlly }); - }, - fetchCharges: async () => { - const charg = useMockData - ? await fakeRequest(mockCharges) - : (await api.scry(scryCharges)).initial; - - const charges = Object.entries(charg).reduce((obj: ChargesWithDesks, [key, value]) => { - // eslint-disable-next-line no-param-reassign - obj[key] = normalizeDocket(value as ChargeWithDesk, key); - return obj; - }, {}); - - set({ charges }); - }, - fetchAllies: async () => { - const allies = useMockData ? mockAllies : (await api.scry(scryAllies)).ini; - set({ allies }); - return allies; - }, - fetchAllyTreaties: async (ally: string) => { - let treaties = useMockData - ? mockTreaties - : (await api.scry(scryAllyTreaties(ally))).ini; - treaties = normalizeDockets(treaties); - set((s) => ({ treaties: { ...s.treaties, ...treaties } })); - return treaties; - }, - requestTreaty: async (ship: string, desk: string) => { - const { treaties } = get(); - if (useMockData) { - set({ treaties: await fakeRequest(treaties) }); - return treaties[desk]; - } - - const key = `${ship}/${desk}`; - if (key in treaties) { - return treaties[key]; - } - - const result = await api.subscribeOnce('treaty', `/treaty/${key}`, 20000); - const treaty = { ...normalizeDocket(result, desk), ship }; - set((state) => ({ - treaties: { ...state.treaties, [key]: treaty } - })); - return treaty; - }, - installDocket: async (ship: string, desk: string) => { - const treaty = get().treaties[`${ship}/${desk}`]; - if (!treaty) { - throw new Error('Bad install'); - } - set((state) => addCharge(state, desk, { ...treaty, chad: { install: null } })); - if (useMockData) { - await new Promise((res) => setTimeout(() => res(), 10000)); - set((state) => addCharge(state, desk, { ...treaty, chad: { glob: null } })); - } - - return api.poke(docketInstall(ship, desk)); - }, - uninstallDocket: async (desk: string) => { - set((state) => delCharge(state, desk)); - if (useMockData) { - return; - } - await api.poke({ - app: 'docket', - mark: 'docket-uninstall', - json: desk - }); - }, - toggleDocket: async (desk: string) => { - if (useMockData) { - set( - produce((draft) => { - const charge = draft.charges[desk]; - charge.chad = chadIsRunning(charge.chad) ? { suspend: null } : { glob: null }; - }) - ); - } - const { charges } = get(); - const charge = charges[desk]; - if (!charge) { - return; - } - const suspended = 'suspend' in charge.chad; - if (suspended) { - await api.poke(kilnRevive(desk)); - } else { - await api.poke(kilnSuspend(desk)); - } - }, - treaties: useMockData ? normalizeDockets(mockTreaties) : {}, - charges: {}, - allies: useMockData ? mockAllies : {}, - addAlly: async (ship) => { - set((draft) => { - draft.allies[ship] = []; - }); - - return api.poke(allyShip(ship)); - }, - set -})); - -function normalizeDocket(docket: T, desk: string): T { - return { - ...docket, - desk, - color: normalizeUrbitColor(docket.color) - }; -} - -function normalizeDockets(dockets: Record): Record { - return Object.entries(dockets).reduce((obj: Record, [key, value]) => { - const [, desk] = key.split('/'); - // eslint-disable-next-line no-param-reassign - obj[key] = normalizeDocket(value, desk); - return obj; - }, {}); -} - -function addCharge(state: DocketState, desk: string, charge: Charge) { - return { charges: { ...state.charges, [desk]: normalizeDocket(charge as ChargeWithDesk, desk) } }; -} - -function delCharge(state: DocketState, desk: string) { - return { charges: omit(state.charges, desk) }; -} - -api.subscribe({ - app: 'docket', - path: '/charges', - event: (data: ChargeUpdate) => { - useDocketState.setState((state) => { - if ('add-charge' in data) { - const { desk, charge } = data['add-charge']; - return addCharge(state, desk, charge); - } - - if ('del-charge' in data) { - const desk = data['del-charge']; - return delCharge(state, desk); - } - - return { charges: state.charges }; - }); - } -}); - -api.subscribe({ - app: 'treaty', - path: '/treaties', - event: (data: TreatyUpdate) => { - useDocketState.getState().set((draft) => { - if ('add' in data) { - const { ship, desk } = data.add; - const treaty = normalizeDocket(data.add, desk); - draft.treaties[`${ship}/${desk}`] = treaty; - } - - if ('ini' in data) { - const treaties = normalizeDockets(data.ini); - draft.treaties = { ...draft.treaties, ...treaties }; - } - }); - } -}); - -api.subscribe({ - app: 'treaty', - path: '/allies', - event: (data: AllyUpdateNew) => { - useDocketState.getState().set((draft) => { - if ('new' in data) { - const { ship, alliance } = data.new; - draft.allies[ship] = alliance; - } - }); - } -}); - -const selCharges = (s: DocketState) => { - return s.charges; -}; - -export function useCharges() { - return useDocketState(selCharges); -} - -export function useCharge(desk: string) { - return useDocketState(useCallback((state) => state.charges[desk], [desk])); -} - -const selRequest = (s: DocketState) => s.requestTreaty; -export function useRequestDocket() { - return useDocketState(selRequest); -} - -const selAllies = (s: DocketState) => s.allies; -export function useAllies() { - return useDocketState(selAllies); -} - -export function useAllyTreaties(ship: string) { - const allies = useAllies(); - const isAllied = ship in allies; - const [status, setStatus] = useState('initial'); - const [treaties, setTreaties] = useState(); - - useEffect(() => { - if (Object.keys(allies).length > 0 && !isAllied) { - setStatus('loading'); - useDocketState.getState().addAlly(ship); - } - }, [allies, isAllied, ship]); - - useEffect(() => { - async function fetchTreaties() { - if (isAllied) { - setStatus('loading'); - try { - const newTreaties = await useDocketState.getState().fetchAllyTreaties(ship); - - if (Object.keys(newTreaties).length > 0) { - setTreaties(newTreaties); - setStatus('success'); - } - } catch { - setStatus('error'); - } - } - } - - fetchTreaties(); - }, [ship, isAllied]); - - const storeTreaties = useDocketState( - useCallback( - (s) => { - const charter = s.allies[ship]; - return pick(s.treaties, ...(charter || [])); - }, - [ship] - ) - ); - - useEffect(() => { - const timeout = setTimeout(() => { - setStatus('error'); - }, 30 * 1000); // wait 30 secs before timing out - - if (Object.keys(storeTreaties).length > 0) { - setTreaties(storeTreaties); - setStatus('success'); - clearTimeout(timeout); - } - - return () => { - clearTimeout(timeout); - }; - }, [storeTreaties]); - - return { - isAllied, - treaties, - status - }; -} - -export function useTreaty(host: string, desk: string) { - return useDocketState( - useCallback( - (s) => { - const ref = `${host}/${desk}`; - return s.treaties[ref]; - }, - [host, desk] - ) - ); -} - -export function allyForTreaty(ship: string, desk: string) { - const ref = `${ship}/${desk}`; - const { allies } = useDocketState.getState(); - const ally = Object.entries(allies).find(([, allied]) => allied.includes(ref))?.[0]; - return ally; -} - -export const landscapeTreatyHost = import.meta.env.LANDSCAPE_HOST as string; - -// xx useful for debugging -window.docket = useDocketState.getState; - -if (useMockData) { - window.desk = 'garden'; -} - -export default useDocketState; diff --git a/pkg/grid/src/state/hark-types.ts b/pkg/grid/src/state/hark-types.ts deleted file mode 100644 index e9d54636f..000000000 --- a/pkg/grid/src/state/hark-types.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * I know this doesn't match our current hark type scheme, but since we're talking - * about changing that I decided to just throw something together to at least test - * this flow for updates. - */ - -export interface RuntimeLagNotification { - type: 'runtime-lag'; -} - -export interface BaseBlockedNotification { - type: 'system-updates-blocked'; - desks: string[]; -} - -export interface BasicNotification { - type: 'basic'; - time: string; - message: string; -} - -export type Notification = BasicNotification | BaseBlockedNotification | RuntimeLagNotification; diff --git a/pkg/grid/src/state/hark.ts b/pkg/grid/src/state/hark.ts deleted file mode 100644 index ab0c8e678..000000000 --- a/pkg/grid/src/state/hark.ts +++ /dev/null @@ -1,264 +0,0 @@ -/* eslint-disable no-param-reassign */ -import { - BigIntOrderedMap, - makePatDa, - decToUd, - unixToDa, - Timebox, - harkBinToId, - opened, - HarkBin, - HarkLid, - archive, - HarkContent, - NotificationGraphConfig, - archiveAll -} from '@urbit/api'; -/* eslint-disable-next-line camelcase */ -import { unstable_batchedUpdates } from 'react-dom'; -import produce from 'immer'; -import _ from 'lodash'; -import api from './api'; -import { getBrowserSetting, parseBrowserSettings, useSettingsState } from './settings'; -import { BaseState, createState, createSubscription, reduceStateN } from './base'; -import { mockNotifications } from './mock-data'; -import { useMockData } from './util'; -import { useLocalState } from './local'; - -export interface HarkState { - seen: Timebox; - unseen: Timebox; - archive: BigIntOrderedMap; - set: (f: (s: HarkState) => void) => void; - opened: () => Promise; - notificationsGraphConfig: NotificationGraphConfig; - archiveAll: () => Promise; - archiveNote: (bin: HarkBin, lid: HarkLid) => Promise; - getMore: () => Promise; - webNotes: { - [binId: string]: Notification[]; - }; - [ref: string]: unknown; -} - -type BaseHarkState = BaseState & HarkState; - -function updateState( - key: string, - transform: (state: BaseHarkState, data: any) => void -): (json: any, state: BaseHarkState) => BaseHarkState { - return (json: any, state: BaseHarkState) => { - if (_.has(json, key)) { - transform(state, _.get(json, key, undefined)); - } - return state; - }; -} - -export const reduceGraph = [ - updateState('initial', (draft, data) => { - draft.notificationsGraphConfig = data; - }), - updateState('set-mentions', (draft, data) => { - draft.notificationsGraphConfig.mentions = data; - }) -]; - -export const useHarkStore = createState( - 'Hark', - (set, get) => ({ - seen: {}, - unseen: useMockData ? mockNotifications : {}, - archive: new BigIntOrderedMap(), - webNotes: {}, - notificationsGraphConfig: { - watchOnSelf: false, - mentions: false, - watching: [] - }, - - set: (f) => { - const newState = produce(get(), f); - set(newState); - }, - archiveAll: async () => { - get().set((draft) => { - draft.unseen = {}; - draft.seen = {}; - }); - await api.poke(archiveAll); - }, - archiveNote: async (bin, lid) => { - get().set((draft) => { - const seen = 'seen' in lid ? 'seen' : 'unseen'; - const binId = harkBinToId(bin); - delete draft[seen][binId]; - }); - if (useMockData) { - return; - } - await api.poke(archive(bin, lid)); - }, - opened: async () => { - reduceHark({ opened: null }); - - await api.poke(opened); - }, - getMore: async () => { - const { archive: arch } = get(); - const idx = decToUd((arch?.peekSmallest()?.[0] || unixToDa(Date.now() * 1000)).toString()); - const update = await api.scry({ - app: 'hark-store', - path: `/recent/inbox/${idx}/5` - }); - reduceHark(update); - } - }), - ['archive', 'unseen', 'seen'], - [ - (set, get) => - createSubscription('hark-graph-hook', '/updates', (j) => { - const graphHookData = _.get(j, 'hark-graph-hook-update', false); - if (graphHookData) { - reduceStateN(get(), graphHookData, reduceGraph); - } - }), - () => - createSubscription('hark-store', '/updates', (u) => { - /* eslint-ignore-next-line camelcase */ - unstable_batchedUpdates(() => { - reduceHark(u); - }); - }) - ] -); - -function reduceHark(u: any) { - const { set } = useHarkStore.getState(); - if (!u) { - return; - } - if ('more' in u) { - u.more.forEach((upd: any) => { - reduceHark(upd); - }); - } else if ('all-stats' in u) { - // TODO: probably ignore? - } else if ('added' in u) { - set((draft) => { - const { bin } = u.added; - const binId = harkBinToId(bin); - draft.unseen[binId] = u.added; - }); - } else if ('timebox' in u) { - const { timebox } = u; - const { lid, notifications } = timebox; - if ('archive' in lid) { - set((draft) => { - const time = makePatDa(lid.archive); - const old = draft.archive.get(time) || {}; - notifications.forEach((note: any) => { - const binId = harkBinToId(note.bin); - old[binId] = note; - }); - draft.archive = draft.archive.set(time, old); - }); - } else { - set((draft) => { - const seen = 'seen' in lid ? 'seen' : 'unseen'; - notifications.forEach((note: any) => { - const binId = harkBinToId(note.bin); - draft[seen][binId] = note; - }); - }); - } - } else if ('archived' in u) { - const { lid, notification } = u.archived; - set((draft) => { - const seen = 'seen' in lid ? 'seen' : 'unseen'; - const binId = harkBinToId(notification.bin); - delete draft[seen][binId]; - const time = makePatDa(u.archived.time); - const timebox = draft.archive?.get(time) || {}; - timebox[binId] = notification; - draft.archive = draft.archive.set(time, timebox); - }); - } else if ('opened' in u) { - set((draft) => { - const bins = Object.keys(draft.unseen); - bins.forEach((bin) => { - const old = draft.seen[bin]; - const curr = draft.unseen[bin]; - curr.body = [...curr.body, ...(old?.body || [])]; - draft.seen[bin] = curr; - delete draft.unseen[bin]; - }); - }); - } else if ('del-place' in u) { - const { path, desk } = u['del-place']; - const pathId = `${desk}${path}`; - const wipeBox = (t: Timebox) => { - Object.keys(t).forEach((bin) => { - if (bin.startsWith(pathId)) { - delete t[bin]; - } - }); - }; - set((draft) => { - wipeBox(draft.unseen); - wipeBox(draft.seen); - draft.archive.keys().forEach((key) => { - wipeBox(draft.archive.get(key)!); - }); - }); - } -} - -api.subscribe({ - app: 'hark-store', - path: '/updates', - event: (u: any) => { - /* eslint-ignore-next-line camelcase */ - unstable_batchedUpdates(() => { - reduceHark(u); - }); - } -}); - -function harkContentsToPlainText(contents: HarkContent[]) { - return contents - .map((c) => { - if ('ship' in c) { - return c.ship; - } - return c.text; - }) - .join(''); -} - -api.subscribe({ - app: 'hark-store', - path: '/notes', - event: (u: any) => { - if ('add-note' in u) { - const { browserSettings, display } = useSettingsState.getState(); - const { browserId } = useLocalState.getState(); - const settings = parseBrowserSettings(browserSettings.settings); - const browserNotifications = getBrowserSetting(settings, browserId)?.browserNotifications; - - if (!browserNotifications || display.doNotDisturb) { - return; - } - const { bin, body } = u['add-note']; - const binId = harkBinToId(bin); - const { title, content } = body; - - const note = new Notification(harkContentsToPlainText(title), { - body: harkContentsToPlainText(content), - tag: binId, - renotify: true - }); - note.onclick = () => {}; - } - } -}); diff --git a/pkg/grid/src/state/kiln.ts b/pkg/grid/src/state/kiln.ts deleted file mode 100644 index 352535c64..000000000 --- a/pkg/grid/src/state/kiln.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { - scryLag, - getPikes, - Pikes, - Pike, - kilnUnsync, - kilnSync, - kilnUninstall, - kilnInstall -} from '@urbit/api'; -import create from 'zustand'; -import produce from 'immer'; -import { useCallback } from 'react'; -import api from './api'; -import { fakeRequest, useMockData } from './util'; -import { mockPikes } from './mock-data'; - -interface KilnState { - pikes: Pikes; - loaded: boolean; - lag: boolean; - fetchLag: () => Promise; - fetchPikes: () => Promise; - toggleInstall: (desk: string, ship: string) => Promise; - toggleSync: (desk: string, ship: string) => Promise; - set: (s: KilnState) => void; - initializeKiln: () => Promise; -} -const useKilnState = create((set, get) => ({ - pikes: useMockData ? mockPikes : {}, - lag: !!useMockData, - loaded: false, - fetchPikes: async () => { - if (useMockData) { - await fakeRequest({}, 500); - set({ loaded: true }); - return; - } - const pikes = await api.scry(getPikes); - set({ pikes, loaded: true }); - }, - fetchLag: async () => { - const lag = await api.scry(scryLag); - set({ lag }); - }, - toggleInstall: async (desk: string, ship: string) => { - const synced = !!get().pikes[desk].sync; - await (useMockData - ? fakeRequest('') - : api.poke(synced ? kilnUninstall(desk) : kilnInstall(ship, 'kids', desk))); - await get().fetchPikes(); - }, - toggleSync: async (desk: string, ship: string) => { - const synced = !!get().pikes[desk].sync; - await (useMockData - ? fakeRequest('') - : api.poke(synced ? kilnUnsync(ship, desk) : kilnSync(ship, desk))); - await get().fetchPikes(); - }, - set: produce(set), - initializeKiln: async () => { - await get().fetchLag(); - await get().fetchPikes(); - } -})); - -const selPikes = (s: KilnState) => s.pikes; -export function usePikes(): Pikes { - return useKilnState(selPikes); -} - -export function usePike(desk: string): Pike | undefined { - return useKilnState(useCallback((s) => s.pikes[desk], [desk])); -} - -const selLag = (s: KilnState) => s.lag; -export function useLag() { - return useKilnState(selLag); -} - -const selLoaded = (s: KilnState) => s.loaded; -export function useKilnLoaded() { - return useKilnState(selLoaded); -} - -export default useKilnState; diff --git a/pkg/grid/src/state/local.ts b/pkg/grid/src/state/local.ts deleted file mode 100644 index b26891412..000000000 --- a/pkg/grid/src/state/local.ts +++ /dev/null @@ -1,37 +0,0 @@ -import create from 'zustand'; -import { persist } from 'zustand/middleware'; -import produce from 'immer'; -import { clearStorageMigration, createStorageKey, storageVersion } from './util'; - -interface LocalState { - browserId: string; - currentTheme: 'light' | 'dark'; - set: (f: (s: LocalState) => void) => void; -} - -export const useLocalState = create( - persist( - (set, get) => ({ - set: (f) => set(produce(get(), f)), - currentTheme: 'light', - browserId: '' - }), - { - name: createStorageKey('local'), - version: storageVersion, - migrate: clearStorageMigration - } - ) -); - -const selBrowserId = (s: LocalState) => s.browserId; -export function useBrowserId() { - return useLocalState(selBrowserId); -} - -const selCurrentTheme = (s: LocalState) => s.currentTheme; -export function useCurrentTheme() { - return useLocalState(selCurrentTheme); -} - -export const setLocalState = (f: (s: LocalState) => void) => useLocalState.getState().set(f); diff --git a/pkg/grid/src/state/mock-data.ts b/pkg/grid/src/state/mock-data.ts deleted file mode 100644 index f360483bc..000000000 --- a/pkg/grid/src/state/mock-data.ts +++ /dev/null @@ -1,374 +0,0 @@ -import { - Allies, - Charges, - DocketHrefGlob, - Treaties, - Treaty, - Notification, - HarkContent, - HarkBody, - unixToDa, - Contact, - Contacts, - Timebox, - harkBinToId, - Pikes -} from '@urbit/api'; -import _ from 'lodash'; -import systemUrl from '../assets/system.png'; - -export const appMetaData: Pick = { - cass: { - da: '~2021.9.13..05.41.04..ae65', - ud: 1 - }, - hash: '0v6.nj6ls.l7unh.l9bhk.d839n.n8nlq.m2dmc.fj80i.pvqun.uhg6g.1kk0h', - website: 'https://tlon.io', - license: 'MIT', - version: '2.0.1' -}; - -const makeHref = (base: string): DocketHrefGlob => ({ glob: { base } }); - -export const mockTreaties: Treaties = { - '~zod/garden': { - ship: '~zod', - desk: 'garden', - title: 'System', - info: 'Your Urbit Home', - href: makeHref('garden'), - color: '#E2C050', - ...appMetaData - }, - '~zod/groups': { - ship: '~zod', - desk: 'groups', - title: 'Groups', - info: 'Simple Software for Community Assembly', - href: makeHref('groups'), - color: '#CDE7EF', - ...appMetaData - }, - '~zod/messages': { - title: 'Messages', - ship: '~zod', - desk: 'messages', - href: makeHref('messages'), - info: 'A lengthier description of the app down here', - color: '#8BE789', - ...appMetaData - }, - '~zod/calls': { - title: 'Calls', - ship: '~zod', - desk: 'calls', - href: makeHref('calls'), - info: 'A lengthier description of the app down here', - color: '#C2D6BE', - ...appMetaData - }, - '~zod/bitcoin-wallet': { - title: 'Bitcoin Wallet', - ship: '~zod', - desk: 'bitcoin-wallet', - href: makeHref('bitcoin-wallet'), - info: 'A lengthier description of the app down here', - color: '#F0AE70', - ...appMetaData - }, - '~zod/system': { - title: 'System', - ship: '~zod', - desk: 'system', - href: makeHref('system'), - info: 'A lengthier description of the app down here', - color: '#2D0118', - image: systemUrl, - ...appMetaData - }, - '~zod/my-apps': { - title: 'My Apps', - ship: '~zod', - desk: 'my-apps', - href: makeHref('my-apps'), - info: 'A lengthier description of the app down here', - color: '#D8B14E', - ...appMetaData - }, - '~zod/go': { - title: 'Go', - ship: '~zod', - desk: 'go', - href: makeHref('go'), - info: 'A lengthier description of the app down here', - color: '#A58E52', - ...appMetaData - }, - '~zod/terminal': { - title: 'Terminal', - ship: '~zod', - desk: 'terminal', - href: makeHref('terminal'), - info: 'A lengthier description of the app down here', - color: '#2D382B', - ...appMetaData - }, - '~zod/pomodoro': { - title: 'Pomodoro', - ship: '~zod', - desk: 'pomodoro', - href: makeHref('pomodoro'), - info: 'A lengthier description of the app down here', - color: '#EE5432', - ...appMetaData - }, - '~zod/clocks': { - title: 'Clocks', - ship: '~zod', - desk: 'clocks', - href: makeHref('clocks'), - info: 'A lengthier description of the app down here', - color: '#DCDCDC', - ...appMetaData - }, - '~zod/uniswap': { - title: 'Uniswap', - ship: '~zod', - desk: 'uniswap', - href: makeHref('uniswap'), - info: 'A lengthier description of the app down here', - color: '#FDA1FF', - ...appMetaData - }, - '~zod/inbox': { - title: 'Inbox', - ship: '~zod', - desk: 'inbox', - href: makeHref('inbox'), - color: '#FEFFBA', - ...appMetaData - } -}; - -export const mockCharges: Charges = _.reduce( - mockTreaties, - (acc, val, key) => { - const [, desk] = key.split('/'); - const chad = { glob: null }; - if (desk === 'inbox') { - return acc; - } - - if (desk === 'calls') { - return { ...acc, [desk]: { ...val, chad: { hung: 'glob failed' } } }; - } - - if (desk === 'messages') { - return { ...acc, [desk]: { ...val, chad: { install: null } } }; - } - - return { ...acc, [desk]: { ...val, chad } }; - }, - {} as Charges -); - -const charter = Object.keys(mockTreaties); - -export const mockAllies: Allies = [ - '~zod', - '~nocsyx-lassul', - '~nachus-hollyn', - '~nalbel_litzod', - '~litmus^ritten', - '~nalput_litzod', - '~nalrex_bannus', - '~nalrys' -].reduce((acc, val) => ({ ...acc, [val]: charter }), {}); - -function ship(s: string) { - return { ship: s }; -} - -function text(t: string) { - return { text: t }; -} - -function createDmNotification(...content: HarkContent[]): HarkBody { - return { - title: [ship('~hastuc-dibtux'), text(' messaged you')], - time: unixToDa(Date.now() - 3_600).toJSNumber(), - content, - binned: '/', - link: '/' - }; -} - -function createBitcoinNotif(amount: string) { - return { - title: [ship('~silnem'), text(` sent you ${amount}`)], - time: unixToDa(Date.now() - 3_600).toJSNumber(), - content: [], - binned: '/', - link: '/' - }; -} - -function createGroupNotif(to: string): HarkBody { - return { - title: [ship('~ridlur-figbud'), text(` invited you to ${to}`)], - content: [], - time: unixToDa(Date.now() - 3_600).toJSNumber(), - binned: '/', - link: '/' - }; -} - -window.desk = window.desk || 'garden'; - -function createMockSysNotification(path: string, body: HarkBody[] = []) { - return { - bin: { - place: { - desk: window.desk, - path - }, - path: '/' - }, - time: Date.now() - 3_600, - body - }; -} - -const lag = createMockSysNotification('/lag'); -const blocked = { - bin: { - place: { - desk: window.desk, - path: '/desk/base' - }, - path: '/blocked' - }, - time: Date.now() - 3_600, - body: [] -}; -const onboard = createMockSysNotification('/onboard'); - -const updateNotification = createMockSysNotification('/desk/bitcoin', [ - { - title: [{ text: 'App "Bitcoin" updated to version 1.0.1' }], - time: 0, - content: [], - link: '/desk/bitcoin', - binned: '/' - } -]); - -export function createMockNotification(desk: string, body: HarkBody[]): Notification { - return { - bin: { - place: { - desk, - path: '/' - }, - path: '/' - }, - time: Date.now() - 3_600, - body - }; -} - -export const mockNotifications: Timebox = _.keyBy( - [ - lag, - blocked, - onboard, - updateNotification, - createMockNotification('groups', [ - createDmNotification(text('ie the hook agent responsible for marking the notifications')), - createDmNotification(ship('~hastuc-dibtux'), text(' sent a link')) - ]), - createMockNotification('bitcoin-wallet', [createBitcoinNotif('0.025 BTC')]), - createMockNotification('groups', [createGroupNotif('a Group: Tlon Corporation')]) - ], - (not) => harkBinToId(not.bin) -); - -const contact: Contact = { - nickname: '', - bio: '', - status: '', - color: '#000000', - avatar: null, - cover: null, - groups: [], - 'last-updated': 0 -}; - -export const mockContacts: Contacts = { - '~zod': { - ...contact, - nickname: 'Tlon Corporation' - }, - '~nocsyx-lassul': { - ...contact, - status: 'technomancing an electron wrapper for urbit', - color: '#4c00ff' - }, - '~nachus-hollyn': { - ...contact, - avatar: 'https://i.pinimg.com/originals/20/62/59/2062590a440f717a2ae1065ad8e8a4c7.gif' - }, - '~nalbel_litzod': { - ...contact, - nickname: 'Queen', - color: '#0a1b0a' - }, - '~litmus^ritten': { - ...contact - }, - '~nalput_litzod': { - ...contact - }, - '~nalrex_bannus': { - ...contact, - status: 'Script, command and inspect your Urbit. Use TUI applications' - }, - '~nalrys': { - ...contact, - status: 'hosting coming soon', - color: '#130c06' - } -}; - -export const mockPikes: Pikes = { - kids: { - sync: null, - zest: 'dead', - wefts: [], - hash: '0v19.q7u27.omps3.fbhf4.53rai.co157.pben7.pu94n.63v4p.3kcb7.iafj0' - }, - garden: { - sync: { - desk: 'garden', - ship: '~mister-dister-dozzod-dozzod' - }, - zest: 'live', - wefts: [], - hash: '0v18.hbbs6.onu15.skjkv.qrfgl.vf4oo.0igo5.2q0d3.6r3r8.2dkmo.oa04m' - }, - landscape: { - sync: { - desk: 'landscape', - ship: '~lander-dister-dozzod-dozzod' - }, - zest: 'live', - wefts: [], - hash: '0v1t.qln8k.cskmt.cn6lv.gu335.jfba6.kte90.iqqn3.aj67b.t389a.8imuo' - }, - base: { - sync: null, - zest: 'live', - wefts: [], - hash: '0v1e.b5auh.6u82i.hqk1r.22kli.4ubef.a1cbo.3g532.6l49k.g0i8e.t6eid' - } -}; diff --git a/pkg/grid/src/state/notifications.ts b/pkg/grid/src/state/notifications.ts deleted file mode 100644 index 95bf5ec4d..000000000 --- a/pkg/grid/src/state/notifications.ts +++ /dev/null @@ -1,13 +0,0 @@ -import shallow from 'zustand/shallow'; -import { useHarkStore } from './hark'; - -export const useNotifications = () => { - const [unseen, seen] = useHarkStore((s) => [s.unseen, s.seen], shallow); - const hasAnyNotifications = Object.keys(seen).length > 0 || Object.keys(unseen).length > 0; - - return { - unseen, - seen, - hasAnyNotifications - }; -}; diff --git a/pkg/grid/src/state/settings.ts b/pkg/grid/src/state/settings.ts deleted file mode 100644 index bda7a0dd0..000000000 --- a/pkg/grid/src/state/settings.ts +++ /dev/null @@ -1,173 +0,0 @@ -/* eslint-disable no-param-reassign */ -import { - SettingsUpdate, - Value, - putEntry as doPutEntry, - getDeskSettings, - DeskData -} from '@urbit/api'; -import _ from 'lodash'; -import { - BaseState, - createState, - createSubscription, - pokeOptimisticallyN, - reduceStateN -} from './base'; -import api from './api'; - -interface BrowserSetting { - browserId: string; - browserNotifications: boolean; - protocolHandling: boolean; -} - -interface BaseSettingsState { - display: { - theme: 'light' | 'dark' | 'auto'; - doNotDisturb: boolean; - }; - tiles: { - order: string[]; - }; - loaded: boolean; - browserSettings: { - settings: Stringified; - }; - putEntry: (bucket: string, key: string, value: Value) => Promise; - fetchAll: () => Promise; - [ref: string]: unknown; -} - -export type SettingsState = BaseSettingsState & BaseState; - -function putBucket(json: SettingsUpdate, state: SettingsState): SettingsState { - const data = _.get(json, 'put-bucket', false); - if (data) { - state[data['bucket-key']] = data.bucket; - } - return state; -} - -function delBucket(json: SettingsUpdate, state: SettingsState): SettingsState { - const data = _.get(json, 'del-bucket', false); - if (data) { - delete state[data['bucket-key']]; - } - return state; -} - -function putEntry(json: SettingsUpdate, state: any): SettingsState { - const data: Record = _.get(json, 'put-entry', false); - if (data) { - if (!state[data['bucket-key']]) { - state[data['bucket-key']] = {}; - } - state[data['bucket-key']][data['entry-key']] = data.value; - } - return state; -} - -function delEntry(json: SettingsUpdate, state: any): SettingsState { - const data = _.get(json, 'del-entry', false); - if (data) { - delete state[data['bucket-key']][data['entry-key']]; - } - return state; -} - -export const reduceUpdate = [putBucket, delBucket, putEntry, delEntry]; - -export const useSettingsState = createState( - 'Settings', - (set, get) => ({ - display: { - theme: 'auto', - doNotDisturb: true - }, - tiles: { - order: [] - }, - browserSettings: { - settings: '' as Stringified - }, - loaded: false, - putEntry: async (bucket, key, val) => { - const poke = doPutEntry(window.desk, bucket, key, val); - await pokeOptimisticallyN(useSettingsState, poke, reduceUpdate); - }, - fetchAll: async () => { - const result = (await api.scry(getDeskSettings(window.desk))).desk; - const newState = { - ..._.mergeWith(get(), result, (obj, src) => (_.isArray(src) ? src : undefined)), - loaded: true - }; - set(newState); - } - }), - [], - [ - (set, get) => - createSubscription('settings-store', `/desk/${window.desk}`, (e) => { - const data = _.get(e, 'settings-event', false); - if (data) { - reduceStateN(get(), data, reduceUpdate); - set({ loaded: true }); - } - }) - ] -); - -const selTheme = (s: SettingsState) => s.display.theme; -export function useTheme() { - return useSettingsState(selTheme); -} - -export function parseBrowserSettings(settings: Stringified): BrowserSetting[] { - return settings !== '' ? JSON.parse(settings) : []; -} - -export function getBrowserSetting( - settings: BrowserSetting[], - browserId: string -): BrowserSetting | undefined { - return settings.find((el) => el.browserId === browserId); -} - -export function setBrowserSetting( - settings: BrowserSetting[], - newSetting: Partial, - browserId: string -): BrowserSetting[] { - const oldSettings = settings.slice(0); - const oldSettingIndex = oldSettings.findIndex((s) => s.browserId === browserId); - const setting = { - ...oldSettings[oldSettingIndex], - browserId, - ...newSetting - }; - - if (oldSettingIndex >= 0) { - oldSettings.splice(oldSettingIndex, 1); - } - - return [...oldSettings, setting]; -} - -const selBrowserSettings = (s: SettingsState) => s.browserSettings.settings; -export function useBrowserSettings(): BrowserSetting[] { - const settings = useSettingsState(selBrowserSettings); - return parseBrowserSettings(settings); -} - -export function useProtocolHandling(browserId: string): boolean { - const settings = useBrowserSettings(); - const browserSetting = getBrowserSetting(settings, browserId); - return browserSetting?.protocolHandling ?? false; -} - -export function useBrowserNotifications(browserId: string): boolean { - const settings = useBrowserSettings(); - const browserSetting = getBrowserSetting(settings, browserId); - return browserSetting?.browserNotifications ?? false; -} diff --git a/pkg/grid/src/state/util.ts b/pkg/grid/src/state/util.ts deleted file mode 100644 index 9b57981e5..000000000 --- a/pkg/grid/src/state/util.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { Docket, DocketHref, Treaty } from '@urbit/api'; -import { hsla, parseToHsla } from 'color2k'; -import _ from 'lodash'; - -export const useMockData = import.meta.env.MODE === 'mock'; - -export async function fakeRequest(data: T, time = 300): Promise { - return new Promise((resolve) => { - setTimeout(() => { - resolve(data); - }, time); - }); -} - -export function getAppHref(href: DocketHref) { - return 'site' in href ? href.site : `/apps/${href.glob.base}/`; -} - -export function getAppName(app: (Docket & { desk: string }) | Treaty | undefined): string { - if (!app) { - return ''; - } - - return app.title || app.desk; -} - -export function disableDefault(e: T): void { - e.preventDefault(); -} - -// hack until radix-ui fixes this behavior -export function handleDropdownLink(setOpen?: (open: boolean) => void): (e: Event) => void { - return (e: Event) => { - e.stopPropagation(); - e.preventDefault(); - setTimeout(() => setOpen?.(false), 15); - }; -} - -export function deSig(ship: string): string { - if (!ship) { - return ''; - } - return ship.replace('~', ''); -} - -export function normalizeUrbitColor(color: string): string { - if (color.startsWith('#')) { - return color; - } - - const colorString = color.slice(2).replace('.', '').toUpperCase(); - const lengthAdjustedColor = _.padEnd(colorString, 6, _.last(colorString)); - return `#${lengthAdjustedColor}`; -} - -export function getDarkColor(color: string): string { - const hslaColor = parseToHsla(color); - return hsla(hslaColor[0], hslaColor[1], 1 - hslaColor[2], 1); -} - -export function createStorageKey(name: string): string { - return `~${window.ship}/${window.desk}/${name}`; -} - -// for purging storage with version updates -export function clearStorageMigration() { - return {} as T; -} - -export const storageVersion = parseInt(import.meta.env.VITE_STORAGE_VERSION, 10); diff --git a/pkg/grid/src/storage-wipe.ts b/pkg/grid/src/storage-wipe.ts deleted file mode 100644 index a1d0d6b16..000000000 --- a/pkg/grid/src/storage-wipe.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { createStorageKey } from './state/util'; - -const key = createStorageKey(`storage-wipe-${import.meta.env.VITE_LAST_WIPE}`); -const wiped = localStorage.getItem(key); - -// Loaded before everything, this clears local storage just once. -// Change VITE_LAST_WIPE in .env to date of wipe - -if (!wiped) { - localStorage.clear(); - localStorage.setItem(key, 'true'); -} diff --git a/pkg/grid/src/styles/base.css b/pkg/grid/src/styles/base.css deleted file mode 100644 index b48a6d8d3..000000000 --- a/pkg/grid/src/styles/base.css +++ /dev/null @@ -1,42 +0,0 @@ -body { - scrollbar-width: thin; - scrollbar-color: #e5e5e5 transparent; -} - -body::-webkit-scrollbar-thumb { - background-color: #e5e5e5; -} - -body::-webkit-scrollbar-track { - background: transparent; -} - -@media (prefers-color-scheme: dark) { - body { - scrollbar-color: #333333 transparent; - } - - body::-webkit-scrollbar-thumb { - background-color: #333333; - } -} - -.h1 { - @apply text-2xl sm:text-3xl font-bold leading-relaxed tracking-tighter; -} - -.h2 { - @apply text-xl sm:text-2xl font-semibold leading-snug tracking-tight; -} - -.h3 { - @apply text-lg sm:text-xl font-semibold leading-relaxed tracking-tight; -} - -.h4 { - @apply text-sm sm:text-base font-semibold leading-normal tracking-tight; -} - -.default-ring { - @apply focus-visible:ring-2 ring-blue-400 ring-opacity-80 focus-visible:outline-none; -} diff --git a/pkg/grid/src/styles/components.css b/pkg/grid/src/styles/components.css deleted file mode 100644 index b0cebc598..000000000 --- a/pkg/grid/src/styles/components.css +++ /dev/null @@ -1,39 +0,0 @@ -.circle-button { - @apply inline-flex items-center justify-center h-12 w-12 font-semibold rounded-full; -} - -.button { - @apply inline-flex items-center justify-center px-4 py-2 font-semibold text-base tracking-tight rounded-lg cursor-pointer; -} - -.dialog-container { - @apply fixed z-40 top-1/2 left-1/2 p-4 transform -translate-x-1/2 -translate-y-1/2; -} - -.dialog { - @apply relative max-h-[calc(100vh-2rem)] max-w-[calc(100vw-2rem)] p-5 sm:p-8 bg-white rounded-3xl overflow-auto; -} - -.dialog-inner-container { - @apply h-full p-4 md:p-8 space-y-8 overflow-y-auto; -} - -.dropdown { - @apply min-w-52 p-4 rounded-xl; -} - -.inner-section { - @apply p-3 bg-gray-50 rounded-xl; -} - -.input { - @apply px-4 py-2 w-full text-base sm:text-sm bg-white rounded-xl; -} - -.notification { - @apply p-4 bg-gray-50 rounded-xl; -} - -.spinner { - @apply inline-flex items-center w-6 h-6 animate-spin; -} diff --git a/pkg/grid/src/styles/grids.css b/pkg/grid/src/styles/grids.css deleted file mode 100644 index 6ec24acc7..000000000 --- a/pkg/grid/src/styles/grids.css +++ /dev/null @@ -1,65 +0,0 @@ -.note-grid-content { - display: grid; - grid-template-columns: 1.5rem 1fr 4rem; - grid-template-rows: 1.5rem 1.5rem; - grid-gap: 0.5rem; - padding: 1rem; - grid-template-areas: - 'icon title actions ' - 'arrow head head' - '. body body'; -} - -.note-grid-no-content { - display: grid; - width: 100%; - padding: 1rem; - grid-template-columns: 3.5rem 1fr 4rem; - grid-column-gap: 0.75rem; - align-items: center; - grid-template-areas: - 'icon title actions' - 'icon head head'; -} -.note-grid-title { - grid-area: title; -} - -.note-grid-icon { - grid-area: icon; -} - -.note-grid-body { - grid-area: body; -} - -.note-grid-head { - grid-area: head; -} - -.note-grid-arrow { - grid-area: arrow; -} - -.note-grid-actions { - grid-area: actions; -} - -@media (min-width: 640px) { - .note-grid-content { - grid-template-columns: 1.5rem 1fr 6rem; - grid-template-rows: 1.5rem 1.5rem; - grid-template-areas: - 'icon title actions ' - 'arrow head actions' - '. body actions'; - } - - .note-grid-no-content { - grid-template-rows: 1.75rem 1.75rem; - grid-template-columns: 3.5rem 1fr 6rem; - grid-template-areas: - 'icon title actions' - 'icon head actions'; - } -} diff --git a/pkg/grid/src/styles/index.css b/pkg/grid/src/styles/index.css deleted file mode 100644 index 419a82058..000000000 --- a/pkg/grid/src/styles/index.css +++ /dev/null @@ -1,10 +0,0 @@ -@import 'tailwindcss/base'; -@import './base.css'; - -@import 'tailwindcss/components'; -@import './components.css'; - -@import 'tailwindcss/utilities'; -@import './utilities.css'; - -@import './grids.css'; diff --git a/pkg/grid/src/styles/utilities.css b/pkg/grid/src/styles/utilities.css deleted file mode 100644 index ddbe64ce6..000000000 --- a/pkg/grid/src/styles/utilities.css +++ /dev/null @@ -1,7 +0,0 @@ -.scroll-full-width { - width: calc(100% - var(--removed-body-scroll-bar-size)); -} - -.scroll-left-50 { - left: calc(50% - (var(--removed-body-scroll-bar-size) / 2)); -} diff --git a/pkg/grid/src/tiles/RemoveApp.tsx b/pkg/grid/src/tiles/RemoveApp.tsx deleted file mode 100644 index a2357d03d..000000000 --- a/pkg/grid/src/tiles/RemoveApp.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React, { useCallback } from 'react'; -import { useHistory, useParams } from 'react-router-dom'; -import { Button } from '../components/Button'; -import { Dialog, DialogClose, DialogContent } from '../components/Dialog'; -import { useRecentsStore } from '../nav/search/Home'; -import useDocketState, { useCharges } from '../state/docket'; -import { getAppName } from '../state/util'; - -export const RemoveApp = () => { - const history = useHistory(); - const { desk } = useParams<{ desk: string }>(); - const charges = useCharges(); - const docket = charges[desk]; - const uninstallDocket = useDocketState((s) => s.uninstallDocket); - - // TODO: add optimistic updates - const handleRemoveApp = useCallback(() => { - uninstallDocket(desk); - useRecentsStore.getState().removeRecentApp(desk); - }, [desk]); - - return ( - !open && history.push('/')}> - -

    Uninstall “{getAppName(docket)}”?

    -

    - The app tile will be removed from Landscape, all processes will be stopped and their data archived, and the app will stop receiving updates. -

    -

    - If the app is reinstalled, the archived data will be restored and you'll be able to pick up where you left off. -

    -
    - - Cancel - - - Uninstall - -
    -
    -
    - ); -}; diff --git a/pkg/grid/src/tiles/SuspendApp.tsx b/pkg/grid/src/tiles/SuspendApp.tsx deleted file mode 100644 index a31c65cfd..000000000 --- a/pkg/grid/src/tiles/SuspendApp.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React, { useCallback } from 'react'; -import { Redirect, useHistory, useParams } from 'react-router-dom'; -import { Button } from '../components/Button'; -import { Dialog, DialogClose, DialogContent } from '../components/Dialog'; -import { useRecentsStore } from '../nav/search/Home'; -import useDocketState, { useCharges } from '../state/docket'; -import { getAppName } from '../state/util'; - -export const SuspendApp = () => { - const history = useHistory(); - const { desk } = useParams<{ desk: string }>(); - const charges = useCharges(); - const charge = charges[desk]; - - // TODO: add optimistic updates - const handleSuspendApp = useCallback(() => { - useDocketState.getState().toggleDocket(desk); - useRecentsStore.getState().removeRecentApp(desk); - }, [desk]); - - if ('suspend' in charge.chad) { - return ; - } - - return ( - !open && history.push('/')}> - -

    Suspend “{getAppName(charge)}”

    -

    - All processes will be stopped and data archived. The app will continue to receive updates from its publisher. -

    -

    - When unsuspended, archived data will be loaded and all processes will resume running, so you can pick up where you left off. -

    -
    - - Cancel - - - Suspend - -
    -
    -
    - ); -}; diff --git a/pkg/grid/src/tiles/Tile.tsx b/pkg/grid/src/tiles/Tile.tsx deleted file mode 100644 index bc2bfe86c..000000000 --- a/pkg/grid/src/tiles/Tile.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import classNames from 'classnames'; -import React, { FunctionComponent } from 'react'; -import { useDrag } from 'react-dnd'; -import { chadIsRunning } from '@urbit/api'; -import { TileMenu } from './TileMenu'; -import { Spinner } from '../components/Spinner'; -import { getAppHref } from '../state/util'; -import { useRecentsStore } from '../nav/search/Home'; -import { ChargeWithDesk } from '../state/docket'; -import { useTileColor } from './useTileColor'; -import { usePike } from '../state/kiln'; -import { Bullet } from '../components/icons/Bullet'; -import { dragTypes } from './TileGrid'; - -type TileProps = { - charge: ChargeWithDesk; - desk: string; - disabled?: boolean; -}; - -export const Tile: FunctionComponent = ({ charge, desk, disabled = false }) => { - const addRecentApp = useRecentsStore((state) => state.addRecentApp); - const { title, image, color, chad, href } = charge; - const pike = usePike(desk); - const { lightText, tileColor, menuColor, suspendColor, suspendMenuColor } = useTileColor(color); - const loading = !disabled && 'install' in chad; - const suspended = disabled || 'suspend' in chad; - const hung = 'hung' in chad; - // TODO should held zest be considered inactive? suspended? also, null sync? - const active = !disabled && chadIsRunning(chad); - const link = getAppHref(href); - const backgroundColor = suspended ? suspendColor : active ? tileColor || 'purple' : suspendColor; - - const [{ isDragging }, drag] = useDrag(() => ({ - type: dragTypes.TILE, - item: { desk }, - collect: (monitor) => ({ - isDragging: !!monitor.isDragging() - }) - })); - - return ( - addRecentApp(desk)} - onAuxClick={() => addRecentApp(desk)} - > -
    -
    - {pike?.zest === 'held' && !disabled && ( - - )} - {!active && ( - <> - {loading && } - - {suspended ? 'Suspended' : loading ? 'Installing' : hung ? 'Errored' : null} - - - )} -
    - - {title && ( -
    -

    {title}

    -
    - )} - {image && !loading && ( - - )} -
    -
    - ); -}; diff --git a/pkg/grid/src/tiles/TileContainer.tsx b/pkg/grid/src/tiles/TileContainer.tsx deleted file mode 100644 index 4d1943375..000000000 --- a/pkg/grid/src/tiles/TileContainer.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import classNames from 'classnames'; -import { uniq, without } from 'lodash'; -import React, { FunctionComponent } from 'react'; -import { useDrop } from 'react-dnd'; -import { useSettingsState } from '../state/settings'; -import { dragTypes, selTiles } from './TileGrid'; - -interface TileContainerProps { - desk: string; -} - -export const TileContainer: FunctionComponent = ({ desk, children }) => { - const { order } = useSettingsState(selTiles); - const [{ isOver }, drop] = useDrop<{ desk: string }, undefined, { isOver: boolean }>( - () => ({ - accept: dragTypes.TILE, - drop: ({ desk: itemDesk }) => { - if (!itemDesk || itemDesk === desk) { - return undefined; - } - // [1, 2, 3, 4] 1 -> 3 - // [2, 3, 4] - const beforeSlot = order.indexOf(itemDesk) < order.indexOf(desk); - const orderWithoutOriginal = without(order, itemDesk); - const slicePoint = orderWithoutOriginal.indexOf(desk); - // [2, 3] [4] - const left = orderWithoutOriginal.slice(0, beforeSlot ? slicePoint + 1 : slicePoint); - const right = orderWithoutOriginal.slice(slicePoint); - // concat([2, 3], [1], [4]) - const newOrder = uniq(left.concat([itemDesk], right)); - // [2, 3, 1, 4] - console.log({ order, left, right, slicePoint, newOrder }); - useSettingsState.getState().putEntry('tiles', 'order', newOrder); - - return undefined; - }, - collect: (monitor) => ({ - isOver: !!monitor.isOver() - }) - }), - [desk, order] - ); - - return ( -
    - {children} -
    - ); -}; diff --git a/pkg/grid/src/tiles/TileGrid.tsx b/pkg/grid/src/tiles/TileGrid.tsx deleted file mode 100644 index 7daf88a41..000000000 --- a/pkg/grid/src/tiles/TileGrid.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import React, { useEffect } from 'react'; -import { DndProvider } from 'react-dnd'; -import { HTML5Backend } from 'react-dnd-html5-backend'; -import { TouchBackend } from 'react-dnd-touch-backend'; -import { uniq } from 'lodash'; -import { ChargeWithDesk, useCharges } from '../state/docket'; -import { Tile } from './Tile'; -import { MenuState } from '../nav/Nav'; -import { SettingsState, useSettingsState } from '../state/settings'; -import { TileContainer } from './TileContainer'; -import { useMedia } from '../logic/useMedia'; - -export interface TileData { - desk: string; - charge: ChargeWithDesk; - position: number; - dragging: boolean; -} - -interface TileGridProps { - menu?: MenuState; -} - -export const dragTypes = { - TILE: 'tile' -}; - -export const selTiles = (s: SettingsState) => ({ - order: s.tiles.order, - loaded: s.loaded -}); - -export const TileGrid = ({ menu }: TileGridProps) => { - const charges = useCharges(); - const chargesLoaded = Object.keys(charges).length > 0; - const { order, loaded } = useSettingsState(selTiles); - const isMobile = useMedia('(pointer: coarse)'); - - useEffect(() => { - const hasKeys = order && !!order.length; - const chargeKeys = Object.keys(charges); - const hasChargeKeys = chargeKeys.length > 0; - - if (!loaded) { - return; - } - - // Correct order state, fill if none, remove duplicates, and remove - // old uninstalled app keys - if (!hasKeys && hasChargeKeys) { - useSettingsState.getState().putEntry('tiles', 'order', chargeKeys); - } else if (order.length < chargeKeys.length) { - useSettingsState.getState().putEntry('tiles', 'order', uniq(order.concat(chargeKeys))); - } else if (order.length > chargeKeys.length && hasChargeKeys) { - useSettingsState - .getState() - .putEntry('tiles', 'order', uniq(order.filter((key) => key in charges).concat(chargeKeys))); - } - }, [charges, order, loaded]); - - if (!chargesLoaded) { - return Loading...; - } - - return ( - -
    - {order - .filter((d) => d !== window.desk && d in charges) - .map((desk) => ( - - - - ))} -
    -
    - ); -}; diff --git a/pkg/grid/src/tiles/TileInfo.tsx b/pkg/grid/src/tiles/TileInfo.tsx deleted file mode 100644 index 0ff2a4efa..000000000 --- a/pkg/grid/src/tiles/TileInfo.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import { useHistory, useParams } from 'react-router-dom'; -import { Dialog, DialogContent } from '../components/Dialog'; -import { AppInfo } from '../components/AppInfo'; -import { useCharge } from '../state/docket'; -import { usePike } from '../state/kiln'; - -export const TileInfo = () => { - const { desk } = useParams<{ desk: string }>(); - const { push } = useHistory(); - const charge = useCharge(desk); - const pike = usePike(desk); - - if (!charge) { - return null; - } - - return ( - !open && push('/')}> - - - - - ); -}; diff --git a/pkg/grid/src/tiles/TileMenu.tsx b/pkg/grid/src/tiles/TileMenu.tsx deleted file mode 100644 index 5a811301a..000000000 --- a/pkg/grid/src/tiles/TileMenu.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import React, { useCallback, useState } from 'react'; -import type * as Polymorphic from '@radix-ui/react-polymorphic'; -import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; -import classNames from 'classnames'; -import { Link } from 'react-router-dom'; -import { Chad, chadIsRunning } from '@urbit/api'; -import useDocketState from '../state/docket'; -import { disableDefault, handleDropdownLink } from '../state/util'; - -export interface TileMenuProps { - desk: string; - lightText: boolean; - menuColor: string; - chad: Chad; - className?: string; -} - -const MenuIcon = ({ className }: { className: string }) => ( - - - - - -); - -type ItemComponent = Polymorphic.ForwardRefComponent< - Polymorphic.IntrinsicElement, - Polymorphic.OwnProps ->; - -const Item = React.forwardRef(({ children, ...props }, ref) => ( - - {children} - -)) as ItemComponent; - -export const TileMenu = ({ desk, chad, menuColor, lightText, className }: TileMenuProps) => { - const [open, setOpen] = useState(false); - const toggleDocket = useDocketState((s) => s.toggleDocket); - const menuBg = { backgroundColor: menuColor }; - const linkOnSelect = useCallback(handleDropdownLink(setOpen), []); - const active = chadIsRunning(chad); - const suspended = 'suspend' in chad; - - return ( - setOpen(isOpen)}> - queryClient.setQueryData(['apps', name], app)} - > - - Menu - - - - - - App Info - - - - - {active && ( - - Suspend App - - )} - {suspended && toggleDocket(desk)}>Resume App} - - Uninstall App - - - - - - ); -}; diff --git a/pkg/grid/src/tiles/useTileColor.tsx b/pkg/grid/src/tiles/useTileColor.tsx deleted file mode 100644 index a9320c336..000000000 --- a/pkg/grid/src/tiles/useTileColor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { darken, hsla, lighten, parseToHsla, readableColorIsBlack } from 'color2k'; -import { useCurrentTheme } from '../state/local'; -import { getDarkColor } from '../state/util'; - -function bgAdjustedColor(color: string, darkBg: boolean): string { - return darkBg ? lighten(color, 0.1) : darken(color, 0.1); -} - -function getMenuColor(color: string, darkBg: boolean): string { - const hslaColor = parseToHsla(color); - const satAdjustedColor = hsla(hslaColor[0], Math.max(0.2, hslaColor[1]), hslaColor[2], 1); - - return bgAdjustedColor(satAdjustedColor, darkBg); -} - -// makes tiles look broken because they blend into BG -function disallowWhiteTiles(color: string): string { - const hslaColor = parseToHsla(color); - return hslaColor[2] >= 0.95 ? darken(color, hslaColor[2] - 0.95) : color; -} - -export const useTileColor = (color: string) => { - const theme = useCurrentTheme(); - const darkTheme = theme === 'dark'; - const allowedColor = disallowWhiteTiles(color); - const tileColor = darkTheme ? getDarkColor(allowedColor) : allowedColor; - const darkBg = !readableColorIsBlack(tileColor); - const lightText = darkBg !== darkTheme; // if not same, light text - const suspendColor = darkTheme ? 'rgb(26,26,26)' : 'rgb(220,220,220)'; - - return { - theme, - tileColor, - menuColor: getMenuColor(tileColor, darkBg), - suspendColor, - suspendMenuColor: bgAdjustedColor(suspendColor, darkTheme), - lightText - }; -}; diff --git a/pkg/grid/src/vite-env.d.ts b/pkg/grid/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2a..000000000 --- a/pkg/grid/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/pkg/grid/src/window.ts b/pkg/grid/src/window.ts deleted file mode 100644 index 9a6993bc1..000000000 --- a/pkg/grid/src/window.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { useLeapStore } from './nav/Nav'; -import { useRecentsStore } from './nav/search/Home'; -import useDocketState from './state/docket'; - -declare global { - interface Window { - ship: string; - desk: string; - recents: typeof useRecentsStore.getState; - docket: typeof useDocketState.getState; - leap: typeof useLeapStore.getState; - } -} - -export {}; diff --git a/pkg/grid/tailwind.config.js b/pkg/grid/tailwind.config.js deleted file mode 100644 index 218adbecd..000000000 --- a/pkg/grid/tailwind.config.js +++ /dev/null @@ -1,215 +0,0 @@ -const defaultTheme = require('tailwindcss/defaultTheme'); -const resolveConfig = require('tailwindcss/resolveConfig'); -const { Theme, ThemeManager } = require('tailwindcss-theming/api'); - -const themableProperties = [ - 'spacing', - 'fontFamily', - //'fontSize', would require change in tailwindcss-theming - 'fontWeight', - 'letterSpacing', - 'lineHeight', - 'borderRadius', - 'borderWidth', - 'boxShadow' -]; - -function variablizeTheme(themeConfig, theme) { - themableProperties.forEach((prop) => { - const propSet = themeConfig[prop]; - Object.entries(propSet).forEach(([key, value]) => { - theme.setVariable(key, value, prop, prop); - }); - }); -} - -const config = resolveConfig({ - theme: { - fontFamily: { - sans: [ - 'Inter', - 'Inter UI', - '-apple-system', - 'BlinkMacSystemFont', - 'San Francisco', - 'Helvetica Neue', - 'Arial', - 'sans-serif' - ], - mono: ['Source Code Pro', 'Roboto mono', 'Courier New', 'monospace'] - }, - extend: { - lineHeight: { - tight: 1.2, - snug: 1.33334, - relaxed: 1.66667 - } - } - } -}); - -const base = new Theme().addColors({ - transparent: 'transparent', - white: '#FFFFFF', - black: '#000000', - gray: { - 50: '#F2F2F2', - 100: '#E5E5E5', - 200: '#CCCCCC', - 300: '#B3B3B3', - 400: '#999999', - 500: '#808080', - 600: '#666666', - 700: '#4D4D4D', - 800: '#333333', - 900: '#1A1A1A' - }, - blue: { - 50: '#EFF9FF', - 100: '#C8EDFF', - 200: '#A0E1FF', - 300: '#5FBFFF', - 400: '#219DFF', - 500: '#0F75D8', - 600: '#0252B2', - 700: '#00388B', - 800: '#002364', - 900: '#00133E' - }, - red: { - 50: '#FFF4F2', - 100: '#FFDED6', - 200: '#FFC8B9', - 300: '#FC9B84', - 400: '#F57456', - 500: '#EE5432', - 600: '#D03B22', - 700: '#B12918', - 800: '#931C13', - 900: '#751410' - }, - orange: { - 50: '#FFF4EF', - 100: '#FFE2CE', - 200: '#FFCEAB', - 300: '#FFA56F', - 400: '#FF7E36', - 500: '#D85E1E', - 600: '#B2420C', - 700: '#8B2B00', - 800: '#641E00', - 900: '#3E1100' - }, - green: { - 100: '#E6F5F0', - 200: '#B3E2D1', - 300: '#009F65' - }, - yellow: { - 100: '#FFF9E6', - 200: '#FFEEB3', - 300: '#FFDD66', - 400: '#FFC700' - } -}); -variablizeTheme(config.theme, base); - -const dark = new Theme() - .setName('dark') - .targetable() - .addColors({ - transparent: 'transparent', - white: '#000000', - black: '#FFFFFF', - gray: { - 50: '#1A1A1A', - 100: '#333333', - 200: '#4D4D4D', - 300: '#666666', - 400: '#808080', - 500: '#999999', - 600: '#B3B3B3', - 700: '#CCCCCC', - 800: '#E5E5E5', - 900: '#F2F2F2' - }, - red: { - 50: '#751410', - 100: '#931C13', - 200: '#B12918', - 300: '#D03B22', - 400: '#EE5432', - 500: '#F57456', - 600: '#FC9B84', - 700: '#FFC8B9', - 800: '#FFDED6', - 900: '#FFF4F2' - }, - blue: { - 50: '#00133E', - 100: '#002364', - 200: '#00388B', - 300: '#0252B2', - 400: '#0F75D8', - 500: '#219DFF', - 600: '#5FBFFF', - 700: '#A0E1FF', - 800: '#C8EDFF', - 900: '#EFF9FF' - }, - orange: { - 50: '#3E1100', - 100: '#641E00', - 200: '#8B2B00', - 300: '#B2420C', - 400: '#D85E1E', - 500: '#FF7E36', - 600: '#FFA56F', - 700: '#FFCEAB', - 800: '#FFE2CE', - 900: '#FFF4EF' - }, - green: { - 100: '#182722', - 200: '#134231', - 300: '#009F65' - }, - yellow: { - 100: '#312B18', - 200: '#5F4E13', - 300: '#A4820B', - 400: '#FFC700' - } - }); - -const themes = new ThemeManager().setDefaultTheme(base).addTheme(dark); - -module.exports = { - mode: 'jit', - purge: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], - darkMode: 'class', // or 'media' or 'class' - theme: { - extend: { - minWidth: (theme) => theme('spacing') - } - }, - screens: { - ...defaultTheme.screens, - xl: '1440px', - '2xl': '2200px' - }, - variants: { - extend: { - opacity: ['hover-none'], - display: ['group-hover'] - } - }, - plugins: [ - require('@tailwindcss/aspect-ratio'), - require('tailwindcss-touch')(), - require('tailwindcss-theming')({ - themes, - strategy: 'class' - }) - ] -}; diff --git a/pkg/grid/tsconfig.json b/pkg/grid/tsconfig.json deleted file mode 100644 index 013e6c54f..000000000 --- a/pkg/grid/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "allowJs": false, - "skipLibCheck": false, - "esModuleInterop": false, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "ESNext", - "moduleResolution": "Node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react" - }, - "include": ["./src"] -} diff --git a/pkg/grid/vite.config.ts b/pkg/grid/vite.config.ts deleted file mode 100644 index 45c862692..000000000 --- a/pkg/grid/vite.config.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { loadEnv, defineConfig } from 'vite'; -import analyze from 'rollup-plugin-analyzer'; -import { visualizer } from 'rollup-plugin-visualizer'; -import reactRefresh from '@vitejs/plugin-react-refresh'; -import { urbitPlugin } from '@urbit/vite-plugin-urbit'; -import { execSync } from 'child_process'; - -// https://vitejs.dev/config/ -export default ({ mode }) => { - process.env.VITE_STORAGE_VERSION = Date.now().toString(); - - Object.assign(process.env, loadEnv(mode, process.cwd())); - const SHIP_URL = process.env.SHIP_URL || process.env.VITE_SHIP_URL || 'http://localhost:8080'; - console.log(SHIP_URL); - - return defineConfig({ - base: mode === 'mock' ? undefined : '/apps/grid/', - server: mode === 'mock' ? undefined : { https: true }, - build: - mode !== 'profile' - ? undefined - : { - rollupOptions: { - plugins: [ - analyze({ - limit: 20 - }), - visualizer() - ] - } - }, - plugins: - mode === 'mock' - ? [] - : [urbitPlugin({ base: 'grid', target: SHIP_URL, secure: false }), reactRefresh()] - }); -}; diff --git a/pkg/hs/natpmp-static/LICENSE b/pkg/hs/natpmp-static/LICENSE deleted file mode 100644 index 7fff2c26a..000000000 --- a/pkg/hs/natpmp-static/LICENSE +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) 2007-2011, Thomas BERNARD -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - diff --git a/pkg/hs/natpmp-static/README.txt b/pkg/hs/natpmp-static/README.txt deleted file mode 100644 index 87e6e25e3..000000000 --- a/pkg/hs/natpmp-static/README.txt +++ /dev/null @@ -1,5 +0,0 @@ -This is a vendored copy of libnatpmp-20150609, along with haskell bindings to -the library. Only the C code which was needed for these bindings was copied out -of the distribution. - -Original code: http://miniupnp.free.fr/libnatpmp.html diff --git a/pkg/hs/natpmp-static/Setup.hs b/pkg/hs/natpmp-static/Setup.hs deleted file mode 100644 index 9a994af67..000000000 --- a/pkg/hs/natpmp-static/Setup.hs +++ /dev/null @@ -1,2 +0,0 @@ -import Distribution.Simple -main = defaultMain diff --git a/pkg/hs/natpmp-static/cbits/binding.c b/pkg/hs/natpmp-static/cbits/binding.c deleted file mode 100644 index 50f3d4f09..000000000 --- a/pkg/hs/natpmp-static/cbits/binding.c +++ /dev/null @@ -1,77 +0,0 @@ -/* $Id: natpmpc.c,v 1.13 2012/08/21 17:23:38 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2011, Thomas BERNARD -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. -*/ - -#include -#include -#include - -#include -#include -#include "natpmp.h" - -// Additional binding code in C to make this more convenient to call from -// Haskell. libnatpmp expects that code which uses it to select() on an -// internal socket, which we don't want to expose to the Haskell bindings user. -// -// This is mostly an adaptation of the code in the demo natpmpc.c to use the -// select() loop. -int readNatResponseSynchronously(natpmp_t* natpmp, natpmpresp_t * response) -{ - fd_set fds; - struct timeval timeout; - int r; - int sav_errno; - - do { - FD_ZERO(&fds); - FD_SET(natpmp->s, &fds); - getnatpmprequesttimeout(natpmp, &timeout); - r = select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - sav_errno = errno; - if(r<0) { - /* fprintf(stderr, "select(): errno=%d '%s'\n", */ - /* sav_errno, strerror(sav_errno)); */ - return 1; - } - r = readnatpmpresponseorretry(natpmp, response); - sav_errno = errno; - /* printf("readnatpmpresponseorretry returned %d (%s)\n", */ - /* r, r==0?"OK":(r==NATPMP_TRYAGAIN?"TRY AGAIN":"FAILED")); */ -/* if(r<0 && r!=NATPMP_TRYAGAIN) { */ -/* #ifdef ENABLE_STRNATPMPERR */ -/* fprintf(stderr, "readnatpmpresponseorretry() failed : %s\n", */ -/* strnatpmperr(r)); */ -/* #endif */ -/* fprintf(stderr, " errno=%d '%s'\n", */ -/* sav_errno, strerror(sav_errno)); */ -/* } */ - } while(r==NATPMP_TRYAGAIN); - - return r; -} diff --git a/pkg/hs/natpmp-static/cbits/binding.h b/pkg/hs/natpmp-static/cbits/binding.h deleted file mode 100644 index f781c8a20..000000000 --- a/pkg/hs/natpmp-static/cbits/binding.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __NATPMP_BINDING_H__ -#define __NATPMP_BINDING_H__ - -#include "natpmp.h" - -int readNatResponseSynchronously(natpmp_t* natpmp, natpmpresp_t * response); - -#endif diff --git a/pkg/hs/natpmp-static/cbits/getgateway.c b/pkg/hs/natpmp-static/cbits/getgateway.c deleted file mode 100644 index dfb9f3e21..000000000 --- a/pkg/hs/natpmp-static/cbits/getgateway.c +++ /dev/null @@ -1,573 +0,0 @@ -/* $Id: getgateway.c,v 1.25 2014/04/22 10:28:57 nanard Exp $ */ -/* libnatpmp - -Copyright (c) 2007-2014, Thomas BERNARD -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. -*/ -#include -#include -#ifndef WIN32 -#include -#endif -#if !defined(_MSC_VER) -#include -#endif -/* There is no portable method to get the default route gateway. - * So below are four (or five ?) differents functions implementing this. - * Parsing /proc/net/route is for linux. - * sysctl is the way to access such informations on BSD systems. - * Many systems should provide route information through raw PF_ROUTE - * sockets. - * In MS Windows, default gateway is found by looking into the registry - * or by using GetBestRoute(). */ -#ifdef __linux__ -#define USE_PROC_NET_ROUTE -#undef USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -#endif - -#if defined(BSD) || defined(__FreeBSD_kernel__) -#undef USE_PROC_NET_ROUTE -#define USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -#endif - -#ifdef __APPLE__ -#undef USE_PROC_NET_ROUTE -#undef USE_SOCKET_ROUTE -#define USE_SYSCTL_NET_ROUTE -#endif - -#if (defined(sun) && defined(__SVR4)) -#undef USE_PROC_NET_ROUTE -#define USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -#endif - -#ifdef WIN32 -#undef USE_PROC_NET_ROUTE -#undef USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -//#define USE_WIN32_CODE -#define USE_WIN32_CODE_2 -#endif - -#ifdef __CYGWIN__ -#undef USE_PROC_NET_ROUTE -#undef USE_SOCKET_ROUTE -#undef USE_SYSCTL_NET_ROUTE -#define USE_WIN32_CODE -#include -#include -#include -#include -#endif - -#ifdef __HAIKU__ -#include -#include -#include -#include -#define USE_HAIKU_CODE -#endif - -#ifdef USE_SYSCTL_NET_ROUTE -#include -#include -#include -#include -#endif -#ifdef USE_SOCKET_ROUTE -#include -#include -#include -#include -#include -#endif - -#ifdef USE_WIN32_CODE -#include -#include -#define MAX_KEY_LENGTH 255 -#define MAX_VALUE_LENGTH 16383 -#endif - -#ifdef USE_WIN32_CODE_2 -#include -#include -#endif - -#include "getgateway.h" - -#ifndef WIN32 -#define SUCCESS (0) -#define FAILED (-1) -#endif - -#ifdef USE_PROC_NET_ROUTE -/* - parse /proc/net/route which is as follow : - -Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT -wlan0 0001A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 -eth0 0000FEA9 00000000 0001 0 0 0 0000FFFF 0 0 0 -wlan0 00000000 0101A8C0 0003 0 0 0 00000000 0 0 0 -eth0 00000000 00000000 0001 0 0 1000 00000000 0 0 0 - - One header line, and then one line by route by route table entry. -*/ -int getdefaultgateway(in_addr_t * addr) -{ - unsigned long d, g; - char buf[256]; - int line = 0; - FILE * f; - char * p; - f = fopen("/proc/net/route", "r"); - if(!f) - return FAILED; - while(fgets(buf, sizeof(buf), f)) { - if(line > 0) { /* skip the first line */ - p = buf; - /* skip the interface name */ - while(*p && !isspace(*p)) - p++; - while(*p && isspace(*p)) - p++; - if(sscanf(p, "%lx%lx", &d, &g)==2) { - if(d == 0 && g != 0) { /* default */ - *addr = g; - fclose(f); - return SUCCESS; - } - } - } - line++; - } - /* default route not found ! */ - if(f) - fclose(f); - return FAILED; -} -#endif /* #ifdef USE_PROC_NET_ROUTE */ - - -#ifdef USE_SYSCTL_NET_ROUTE - -#define ROUNDUP(a) \ - ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) - -int getdefaultgateway(in_addr_t * addr) -{ -#if 0 - /* net.route.0.inet.dump.0.0 ? */ - int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, - NET_RT_DUMP, 0, 0/*tableid*/}; -#endif - /* net.route.0.inet.flags.gateway */ - int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, - NET_RT_FLAGS, RTF_GATEWAY}; - size_t l; - char * buf, * p; - struct rt_msghdr * rt; - struct sockaddr * sa; - struct sockaddr * sa_tab[RTAX_MAX]; - int i; - int r = FAILED; - if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) { - return FAILED; - } - if(l>0) { - buf = malloc(l); - if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) { - free(buf); - return FAILED; - } - for(p=buf; prtm_msglen) { - rt = (struct rt_msghdr *)p; - sa = (struct sockaddr *)(rt + 1); - for(i=0; irtm_addrs & (1 << i)) { - sa_tab[i] = sa; - sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len)); - } else { - sa_tab[i] = NULL; - } - } - if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY)) - && sa_tab[RTAX_DST]->sa_family == AF_INET - && sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) { - if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) { - *addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr; - r = SUCCESS; - } - } - } - free(buf); - } - return r; -} -#endif /* #ifdef USE_SYSCTL_NET_ROUTE */ - - -#ifdef USE_SOCKET_ROUTE -/* Thanks to Darren Kenny for this code */ -#define NEXTADDR(w, u) \ - if (rtm_addrs & (w)) {\ - l = sizeof(struct sockaddr); memmove(cp, &(u), l); cp += l;\ - } - -#define rtm m_rtmsg.m_rtm - -struct { - struct rt_msghdr m_rtm; - char m_space[512]; -} m_rtmsg; - -int getdefaultgateway(in_addr_t *addr) -{ - int s, seq, l, rtm_addrs, i; - pid_t pid; - struct sockaddr so_dst, so_mask; - char *cp = m_rtmsg.m_space; - struct sockaddr *gate = NULL, *sa; - struct rt_msghdr *msg_hdr; - - pid = getpid(); - seq = 0; - rtm_addrs = RTA_DST | RTA_NETMASK; - - memset(&so_dst, 0, sizeof(so_dst)); - memset(&so_mask, 0, sizeof(so_mask)); - memset(&rtm, 0, sizeof(struct rt_msghdr)); - - rtm.rtm_type = RTM_GET; - rtm.rtm_flags = RTF_UP | RTF_GATEWAY; - rtm.rtm_version = RTM_VERSION; - rtm.rtm_seq = ++seq; - rtm.rtm_addrs = rtm_addrs; - - so_dst.sa_family = AF_INET; - so_mask.sa_family = AF_INET; - - NEXTADDR(RTA_DST, so_dst); - NEXTADDR(RTA_NETMASK, so_mask); - - rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; - - s = socket(PF_ROUTE, SOCK_RAW, 0); - - if (write(s, (char *)&m_rtmsg, l) < 0) { - close(s); - return FAILED; - } - - do { - l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); - } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); - - close(s); - - msg_hdr = &rtm; - - cp = ((char *)(msg_hdr + 1)); - if (msg_hdr->rtm_addrs) { - for (i = 1; i; i <<= 1) - if (i & msg_hdr->rtm_addrs) { - sa = (struct sockaddr *)cp; - if (i == RTA_GATEWAY ) - gate = sa; - - cp += sizeof(struct sockaddr); - } - } else { - return FAILED; - } - - - if (gate != NULL ) { - *addr = ((struct sockaddr_in *)gate)->sin_addr.s_addr; - return SUCCESS; - } else { - return FAILED; - } -} -#endif /* #ifdef USE_SOCKET_ROUTE */ - -#ifdef USE_WIN32_CODE -LIBSPEC int getdefaultgateway(in_addr_t * addr) -{ - HKEY networkCardsKey; - HKEY networkCardKey; - HKEY interfacesKey; - HKEY interfaceKey; - DWORD i = 0; - DWORD numSubKeys = 0; - TCHAR keyName[MAX_KEY_LENGTH]; - DWORD keyNameLength = MAX_KEY_LENGTH; - TCHAR keyValue[MAX_VALUE_LENGTH]; - DWORD keyValueLength = MAX_VALUE_LENGTH; - DWORD keyValueType = REG_SZ; - TCHAR gatewayValue[MAX_VALUE_LENGTH]; - DWORD gatewayValueLength = MAX_VALUE_LENGTH; - DWORD gatewayValueType = REG_MULTI_SZ; - int done = 0; - - //const char * networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"; - //const char * interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; -#ifdef UNICODE - LPCTSTR networkCardsPath = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"; - LPCTSTR interfacesPath = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; -#define STR_SERVICENAME L"ServiceName" -#define STR_DHCPDEFAULTGATEWAY L"DhcpDefaultGateway" -#define STR_DEFAULTGATEWAY L"DefaultGateway" -#else - LPCTSTR networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"; - LPCTSTR interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; -#define STR_SERVICENAME "ServiceName" -#define STR_DHCPDEFAULTGATEWAY "DhcpDefaultGateway" -#define STR_DEFAULTGATEWAY "DefaultGateway" -#endif - // The windows registry lists its primary network devices in the following location: - // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards - // - // Each network device has its own subfolder, named with an index, with various properties: - // -NetworkCards - // -5 - // -Description = Broadcom 802.11n Network Adapter - // -ServiceName = {E35A72F8-5065-4097-8DFE-C7790774EE4D} - // -8 - // -Description = Marvell Yukon 88E8058 PCI-E Gigabit Ethernet Controller - // -ServiceName = {86226414-5545-4335-A9D1-5BD7120119AD} - // - // The above service name is the name of a subfolder within: - // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces - // - // There may be more subfolders in this interfaces path than listed in the network cards path above: - // -Interfaces - // -{3a539854-6a70-11db-887c-806e6f6e6963} - // -DhcpIPAddress = 0.0.0.0 - // -[more] - // -{E35A72F8-5065-4097-8DFE-C7790774EE4D} - // -DhcpIPAddress = 10.0.1.4 - // -DhcpDefaultGateway = 10.0.1.1 - // -[more] - // -{86226414-5545-4335-A9D1-5BD7120119AD} - // -DhcpIpAddress = 10.0.1.5 - // -DhcpDefaultGateay = 10.0.1.1 - // -[more] - // - // In order to extract this information, we enumerate each network card, and extract the ServiceName value. - // This is then used to open the interface subfolder, and attempt to extract a DhcpDefaultGateway value. - // Once one is found, we're done. - // - // It may be possible to simply enumerate the interface folders until we find one with a DhcpDefaultGateway value. - // However, the technique used is the technique most cited on the web, and we assume it to be more correct. - - if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predifined key - networkCardsPath, // Name of registry subkey to open - 0, // Reserved - must be zero - KEY_READ, // Mask - desired access rights - &networkCardsKey)) // Pointer to output key - { - // Unable to open network cards keys - return -1; - } - - if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predefined key - interfacesPath, // Name of registry subkey to open - 0, // Reserved - must be zero - KEY_READ, // Mask - desired access rights - &interfacesKey)) // Pointer to output key - { - // Unable to open interfaces key - RegCloseKey(networkCardsKey); - return -1; - } - - // Figure out how many subfolders are within the NetworkCards folder - RegQueryInfoKey(networkCardsKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - - //printf( "Number of subkeys: %u\n", (unsigned int)numSubKeys); - - // Enumrate through each subfolder within the NetworkCards folder - for(i = 0; i < numSubKeys && !done; i++) - { - keyNameLength = MAX_KEY_LENGTH; - if(ERROR_SUCCESS == RegEnumKeyEx(networkCardsKey, // Open registry key - i, // Index of subkey to retrieve - keyName, // Buffer that receives the name of the subkey - &keyNameLength, // Variable that receives the size of the above buffer - NULL, // Reserved - must be NULL - NULL, // Buffer that receives the class string - NULL, // Variable that receives the size of the above buffer - NULL)) // Variable that receives the last write time of subkey - { - if(RegOpenKeyEx(networkCardsKey, keyName, 0, KEY_READ, &networkCardKey) == ERROR_SUCCESS) - { - keyValueLength = MAX_VALUE_LENGTH; - if(ERROR_SUCCESS == RegQueryValueEx(networkCardKey, // Open registry key - STR_SERVICENAME, // Name of key to query - NULL, // Reserved - must be NULL - &keyValueType, // Receives value type - (LPBYTE)keyValue, // Receives value - &keyValueLength)) // Receives value length in bytes - { -// printf("keyValue: %s\n", keyValue); - if(RegOpenKeyEx(interfacesKey, keyValue, 0, KEY_READ, &interfaceKey) == ERROR_SUCCESS) - { - gatewayValueLength = MAX_VALUE_LENGTH; - if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey, // Open registry key - STR_DHCPDEFAULTGATEWAY, // Name of key to query - NULL, // Reserved - must be NULL - &gatewayValueType, // Receives value type - (LPBYTE)gatewayValue, // Receives value - &gatewayValueLength)) // Receives value length in bytes - { - // Check to make sure it's a string - if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1)) - { - //printf("gatewayValue: %s\n", gatewayValue); - done = 1; - } - } - else if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey, // Open registry key - STR_DEFAULTGATEWAY, // Name of key to query - NULL, // Reserved - must be NULL - &gatewayValueType, // Receives value type - (LPBYTE)gatewayValue,// Receives value - &gatewayValueLength)) // Receives value length in bytes - { - // Check to make sure it's a string - if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1)) - { - //printf("gatewayValue: %s\n", gatewayValue); - done = 1; - } - } - RegCloseKey(interfaceKey); - } - } - RegCloseKey(networkCardKey); - } - } - } - - RegCloseKey(interfacesKey); - RegCloseKey(networkCardsKey); - - if(done) - { -#if UNICODE - char tmp[32]; - for(i = 0; i < 32; i++) { - tmp[i] = (char)gatewayValue[i]; - if(!tmp[i]) - break; - } - tmp[31] = '\0'; - *addr = inet_addr(tmp); -#else - *addr = inet_addr(gatewayValue); -#endif - return 0; - } - - return -1; -} -#endif /* #ifdef USE_WIN32_CODE */ - -#ifdef USE_WIN32_CODE_2 -int getdefaultgateway(in_addr_t *addr) -{ - MIB_IPFORWARDROW ip_forward; - memset(&ip_forward, 0, sizeof(ip_forward)); - if(GetBestRoute(inet_addr("0.0.0.0"), 0, &ip_forward) != NO_ERROR) - return -1; - *addr = ip_forward.dwForwardNextHop; - return 0; -} -#endif /* #ifdef USE_WIN32_CODE_2 */ - -#ifdef USE_HAIKU_CODE -int getdefaultgateway(in_addr_t *addr) -{ - int fd, ret = -1; - struct ifconf config; - void *buffer = NULL; - struct ifreq *interface; - - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - return -1; - } - if (ioctl(fd, SIOCGRTSIZE, &config, sizeof(config)) != 0) { - goto fail; - } - if (config.ifc_value < 1) { - goto fail; /* No routes */ - } - if ((buffer = malloc(config.ifc_value)) == NULL) { - goto fail; - } - config.ifc_len = config.ifc_value; - config.ifc_buf = buffer; - if (ioctl(fd, SIOCGRTTABLE, &config, sizeof(config)) != 0) { - goto fail; - } - for (interface = buffer; - (uint8_t *)interface < (uint8_t *)buffer + config.ifc_len; ) { - struct route_entry route = interface->ifr_route; - int intfSize; - if (route.flags & (RTF_GATEWAY | RTF_DEFAULT)) { - *addr = ((struct sockaddr_in *)route.gateway)->sin_addr.s_addr; - ret = 0; - break; - } - intfSize = sizeof(route) + IF_NAMESIZE; - if (route.destination != NULL) { - intfSize += route.destination->sa_len; - } - if (route.mask != NULL) { - intfSize += route.mask->sa_len; - } - if (route.gateway != NULL) { - intfSize += route.gateway->sa_len; - } - interface = (struct ifreq *)((uint8_t *)interface + intfSize); - } -fail: - free(buffer); - close(fd); - return ret; -} -#endif /* #ifdef USE_HAIKU_CODE */ - -#if !defined(USE_PROC_NET_ROUTE) && !defined(USE_SOCKET_ROUTE) && !defined(USE_SYSCTL_NET_ROUTE) && !defined(USE_WIN32_CODE) && !defined(USE_WIN32_CODE_2) && !defined(USE_HAIKU_CODE) -int getdefaultgateway(in_addr_t * addr) -{ - return -1; -} -#endif diff --git a/pkg/hs/natpmp-static/cbits/getgateway.h b/pkg/hs/natpmp-static/cbits/getgateway.h deleted file mode 100644 index 5d3df7312..000000000 --- a/pkg/hs/natpmp-static/cbits/getgateway.h +++ /dev/null @@ -1,49 +0,0 @@ -/* $Id: getgateway.h,v 1.8 2014/04/22 09:15:40 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2014, Thomas BERNARD -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. -*/ -#ifndef __GETGATEWAY_H__ -#define __GETGATEWAY_H__ - -#ifdef WIN32 -#if !defined(_MSC_VER) || _MSC_VER >= 1600 -#include -#else -typedef unsigned long uint32_t; -typedef unsigned short uint16_t; -#endif -#define in_addr_t uint32_t -#endif -/* #include "declspec.h" */ - -/* getdefaultgateway() : - * return value : - * 0 : success - * -1 : failure */ -/* LIBSPEC */int getdefaultgateway(in_addr_t * addr); - -#endif diff --git a/pkg/hs/natpmp-static/cbits/natpmp.c b/pkg/hs/natpmp-static/cbits/natpmp.c deleted file mode 100644 index 289c36445..000000000 --- a/pkg/hs/natpmp-static/cbits/natpmp.c +++ /dev/null @@ -1,387 +0,0 @@ -/* $Id: natpmp.c,v 1.20 2015/05/27 12:43:15 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2015, Thomas BERNARD -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. -*/ -#ifdef __linux__ -#define _BSD_SOURCE 1 -#endif -#include -#include -#if !defined(_MSC_VER) -#include -#endif -#ifdef WIN32 -#include -#include -#include -#include -#define EWOULDBLOCK WSAEWOULDBLOCK -#define ECONNREFUSED WSAECONNREFUSED -#include "wingettimeofday.h" -#define gettimeofday natpmp_gettimeofday -#else -#include -#include -#include -#include -#include -#define closesocket close -#endif -#include "natpmp.h" -#include "getgateway.h" -#include - -LIBSPEC int initnatpmp(natpmp_t * p, int forcegw, in_addr_t forcedgw) -{ -#ifdef WIN32 - u_long ioctlArg = 1; -#else - int flags; -#endif - struct sockaddr_in addr; - if(!p) - return NATPMP_ERR_INVALIDARGS; - memset(p, 0, sizeof(natpmp_t)); - p->s = socket(PF_INET, SOCK_DGRAM, 0); - if(p->s < 0) - return NATPMP_ERR_SOCKETERROR; -#ifdef WIN32 - if(ioctlsocket(p->s, FIONBIO, &ioctlArg) == SOCKET_ERROR) - return NATPMP_ERR_FCNTLERROR; -#else - if((flags = fcntl(p->s, F_GETFL, 0)) < 0) - return NATPMP_ERR_FCNTLERROR; - if(fcntl(p->s, F_SETFL, flags | O_NONBLOCK) < 0) - return NATPMP_ERR_FCNTLERROR; -#endif - - if(forcegw) { - p->gateway = forcedgw; - } else { - if(getdefaultgateway(&(p->gateway)) < 0) - return NATPMP_ERR_CANNOTGETGATEWAY; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(NATPMP_PORT); - addr.sin_addr.s_addr = p->gateway; - if(connect(p->s, (struct sockaddr *)&addr, sizeof(addr)) < 0) - return NATPMP_ERR_CONNECTERR; - return 0; -} - -LIBSPEC int closenatpmp(natpmp_t * p) -{ - if(!p) - return NATPMP_ERR_INVALIDARGS; - if(closesocket(p->s) < 0) - return NATPMP_ERR_CLOSEERR; - return 0; -} - -int sendpendingrequest(natpmp_t * p) -{ - int r; -/* struct sockaddr_in addr;*/ - if(!p) - return NATPMP_ERR_INVALIDARGS; -/* memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(NATPMP_PORT); - addr.sin_addr.s_addr = p->gateway; - r = (int)sendto(p->s, p->pending_request, p->pending_request_len, 0, - (struct sockaddr *)&addr, sizeof(addr));*/ - r = (int)send(p->s, (const char *)p->pending_request, p->pending_request_len, 0); - return (r<0) ? NATPMP_ERR_SENDERR : r; -} - -int sendnatpmprequest(natpmp_t * p) -{ - int n; - if(!p) - return NATPMP_ERR_INVALIDARGS; - /* TODO : check if no request is already pending */ - p->has_pending_request = 1; - p->try_number = 1; - n = sendpendingrequest(p); - gettimeofday(&p->retry_time, NULL); // check errors ! - p->retry_time.tv_usec += 250000; /* add 250ms */ - if(p->retry_time.tv_usec >= 1000000) { - p->retry_time.tv_usec -= 1000000; - p->retry_time.tv_sec++; - } - return n; -} - -LIBSPEC int getnatpmprequesttimeout(natpmp_t * p, struct timeval * timeout) -{ - struct timeval now; - if(!p || !timeout) - return NATPMP_ERR_INVALIDARGS; - if(!p->has_pending_request) - return NATPMP_ERR_NOPENDINGREQ; - if(gettimeofday(&now, NULL) < 0) - return NATPMP_ERR_GETTIMEOFDAYERR; - timeout->tv_sec = p->retry_time.tv_sec - now.tv_sec; - timeout->tv_usec = p->retry_time.tv_usec - now.tv_usec; - if(timeout->tv_usec < 0) { - timeout->tv_usec += 1000000; - timeout->tv_sec--; - } - return 0; -} - -LIBSPEC int sendpublicaddressrequest(natpmp_t * p) -{ - if(!p) - return NATPMP_ERR_INVALIDARGS; - //static const unsigned char request[] = { 0, 0 }; - p->pending_request[0] = 0; - p->pending_request[1] = 0; - p->pending_request_len = 2; - // TODO: return 0 instead of sizeof(request) ?? - return sendnatpmprequest(p); -} - -LIBSPEC int sendnewportmappingrequest(natpmp_t * p, int protocol, - uint16_t privateport, uint16_t publicport, - uint32_t lifetime) -{ - if(!p || (protocol!=NATPMP_PROTOCOL_TCP && protocol!=NATPMP_PROTOCOL_UDP)) - return NATPMP_ERR_INVALIDARGS; - p->pending_request[0] = 0; - p->pending_request[1] = protocol; - p->pending_request[2] = 0; - p->pending_request[3] = 0; - /* break strict-aliasing rules : - *((uint16_t *)(p->pending_request + 4)) = htons(privateport); */ - p->pending_request[4] = (privateport >> 8) & 0xff; - p->pending_request[5] = privateport & 0xff; - /* break stric-aliasing rules : - *((uint16_t *)(p->pending_request + 6)) = htons(publicport); */ - p->pending_request[6] = (publicport >> 8) & 0xff; - p->pending_request[7] = publicport & 0xff; - /* break stric-aliasing rules : - *((uint32_t *)(p->pending_request + 8)) = htonl(lifetime); */ - p->pending_request[8] = (lifetime >> 24) & 0xff; - p->pending_request[9] = (lifetime >> 16) & 0xff; - p->pending_request[10] = (lifetime >> 8) & 0xff; - p->pending_request[11] = lifetime & 0xff; - p->pending_request_len = 12; - return sendnatpmprequest(p); -} - -LIBSPEC int readnatpmpresponse(natpmp_t * p, natpmpresp_t * response) -{ - unsigned char buf[16]; - struct sockaddr_in addr; - socklen_t addrlen = sizeof(addr); - int n; - if(!p) - return NATPMP_ERR_INVALIDARGS; - n = recvfrom(p->s, (char *)buf, sizeof(buf), 0, - (struct sockaddr *)&addr, &addrlen); - if(n<0) -#ifdef WIN32 - switch(WSAGetLastError()) { -#else - switch(errno) { -#endif - /*case EAGAIN:*/ - case EWOULDBLOCK: - n = NATPMP_TRYAGAIN; - break; - case ECONNREFUSED: - n = NATPMP_ERR_NOGATEWAYSUPPORT; - break; - default: - n = NATPMP_ERR_RECVFROM; - } - /* check that addr is correct (= gateway) */ - else if(addr.sin_addr.s_addr != p->gateway) - n = NATPMP_ERR_WRONGPACKETSOURCE; - else { - response->resultcode = ntohs(*((uint16_t *)(buf + 2))); - response->epoch = ntohl(*((uint32_t *)(buf + 4))); - if(buf[0] != 0) - n = NATPMP_ERR_UNSUPPORTEDVERSION; - else if(buf[1] < 128 || buf[1] > 130) - n = NATPMP_ERR_UNSUPPORTEDOPCODE; - else if(response->resultcode != 0) { - switch(response->resultcode) { - case 1: - n = NATPMP_ERR_UNSUPPORTEDVERSION; - break; - case 2: - n = NATPMP_ERR_NOTAUTHORIZED; - break; - case 3: - n = NATPMP_ERR_NETWORKFAILURE; - break; - case 4: - n = NATPMP_ERR_OUTOFRESOURCES; - break; - case 5: - n = NATPMP_ERR_UNSUPPORTEDOPCODE; - break; - default: - n = NATPMP_ERR_UNDEFINEDERROR; - } - } else { - response->type = buf[1] & 0x7f; - if(buf[1] == 128) - //response->publicaddress.addr = *((uint32_t *)(buf + 8)); - response->pnu.publicaddress.addr.s_addr = *((uint32_t *)(buf + 8)); - else { - response->pnu.newportmapping.privateport = ntohs(*((uint16_t *)(buf + 8))); - response->pnu.newportmapping.mappedpublicport = ntohs(*((uint16_t *)(buf + 10))); - response->pnu.newportmapping.lifetime = ntohl(*((uint32_t *)(buf + 12))); - } - n = 0; - } - } - return n; -} - -int readnatpmpresponseorretry(natpmp_t * p, natpmpresp_t * response) -{ - int n; - if(!p || !response) - return NATPMP_ERR_INVALIDARGS; - if(!p->has_pending_request) - return NATPMP_ERR_NOPENDINGREQ; - n = readnatpmpresponse(p, response); - if(n<0) { - if(n==NATPMP_TRYAGAIN) { - struct timeval now; - gettimeofday(&now, NULL); // check errors ! - if(timercmp(&now, &p->retry_time, >=)) { - int delay, r; - // NOTE: This used to be 9, and was changed for the haskell - // bindings to be 5. - if(p->try_number >= 5) { - return NATPMP_ERR_NOGATEWAYSUPPORT; - } - /*printf("retry! %d\n", p->try_number);*/ - - // NOTE: Changed how delays are calculated. Waiting up to four - // minutes for a packet that might never get a response is not - // a good user experience. Instead, retry up to 2 seconds. - // - // delay = 250 * (1<try_number); // ms - delay = 250 * p->try_number; // ms - /*for(i=0; itry_number; i++) - delay += delay;*/ - p->retry_time.tv_sec += (delay / 1000); - p->retry_time.tv_usec += (delay % 1000) * 1000; - if(p->retry_time.tv_usec >= 1000000) { - p->retry_time.tv_usec -= 1000000; - p->retry_time.tv_sec++; - } - p->try_number++; - r = sendpendingrequest(p); - if(r<0) - return r; - } - } - } else { - p->has_pending_request = 0; - } - return n; -} - -#ifdef ENABLE_STRNATPMPERR -LIBSPEC const char * strnatpmperr(int r) -{ - const char * s; - switch(r) { - case NATPMP_ERR_INVALIDARGS: - s = "invalid arguments"; - break; - case NATPMP_ERR_SOCKETERROR: - s = "socket() failed"; - break; - case NATPMP_ERR_CANNOTGETGATEWAY: - s = "cannot get default gateway ip address"; - break; - case NATPMP_ERR_CLOSEERR: -#ifdef WIN32 - s = "closesocket() failed"; -#else - s = "close() failed"; -#endif - break; - case NATPMP_ERR_RECVFROM: - s = "recvfrom() failed"; - break; - case NATPMP_ERR_NOPENDINGREQ: - s = "no pending request"; - break; - case NATPMP_ERR_NOGATEWAYSUPPORT: - s = "the gateway does not support nat-pmp"; - break; - case NATPMP_ERR_CONNECTERR: - s = "connect() failed"; - break; - case NATPMP_ERR_WRONGPACKETSOURCE: - s = "packet not received from the default gateway"; - break; - case NATPMP_ERR_SENDERR: - s = "send() failed"; - break; - case NATPMP_ERR_FCNTLERROR: - s = "fcntl() failed"; - break; - case NATPMP_ERR_GETTIMEOFDAYERR: - s = "gettimeofday() failed"; - break; - case NATPMP_ERR_UNSUPPORTEDVERSION: - s = "unsupported nat-pmp version error from server"; - break; - case NATPMP_ERR_UNSUPPORTEDOPCODE: - s = "unsupported nat-pmp opcode error from server"; - break; - case NATPMP_ERR_UNDEFINEDERROR: - s = "undefined nat-pmp server error"; - break; - case NATPMP_ERR_NOTAUTHORIZED: - s = "not authorized"; - break; - case NATPMP_ERR_NETWORKFAILURE: - s = "network failure"; - break; - case NATPMP_ERR_OUTOFRESOURCES: - s = "nat-pmp server out of resources"; - break; - default: - s = "Unknown libnatpmp error"; - } - return s; -} -#endif - diff --git a/pkg/hs/natpmp-static/cbits/natpmp.h b/pkg/hs/natpmp-static/cbits/natpmp.h deleted file mode 100644 index 3f721b7b9..000000000 --- a/pkg/hs/natpmp-static/cbits/natpmp.h +++ /dev/null @@ -1,221 +0,0 @@ -/* $Id: natpmp.h,v 1.20 2014/04/22 09:15:40 nanard Exp $ */ -/* libnatpmp -Copyright (c) 2007-2014, Thomas BERNARD -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. -*/ -#ifndef __NATPMP_H__ -#define __NATPMP_H__ - -/* NAT-PMP Port as defined by the NAT-PMP draft */ -#define NATPMP_PORT (5351) - -#define ENABLE_STRNATPMPERR - -#include -#if !defined(_MSC_VER) -#include -#endif /* !defined(_MSC_VER) */ - -#ifdef WIN32 -#include -#if !defined(_MSC_VER) || _MSC_VER >= 1600 -#include -#else /* !defined(_MSC_VER) || _MSC_VER >= 1600 */ -typedef unsigned long uint32_t; -typedef unsigned short uint16_t; -#endif /* !defined(_MSC_VER) || _MSC_VER >= 1600 */ -#define in_addr_t uint32_t -#include "declspec.h" -#else /* WIN32 */ -#define LIBSPEC -#include -#endif /* WIN32 */ - -/* causes problem when installing. Maybe should it be inlined ? */ -/* #include "declspec.h" */ - -typedef struct { - int s; /* socket */ - in_addr_t gateway; /* default gateway (IPv4) */ - int has_pending_request; - unsigned char pending_request[12]; - int pending_request_len; - int try_number; - struct timeval retry_time; -} natpmp_t; - -typedef struct { - uint16_t type; /* NATPMP_RESPTYPE_* */ - uint16_t resultcode; /* NAT-PMP response code */ - uint32_t epoch; /* Seconds since start of epoch */ - union { - struct { - //in_addr_t addr; - struct in_addr addr; - } publicaddress; - struct { - uint16_t privateport; - uint16_t mappedpublicport; - uint32_t lifetime; - } newportmapping; - } pnu; -} natpmpresp_t; - -/* possible values for type field of natpmpresp_t */ -#define NATPMP_RESPTYPE_PUBLICADDRESS (0) -#define NATPMP_RESPTYPE_UDPPORTMAPPING (1) -#define NATPMP_RESPTYPE_TCPPORTMAPPING (2) - -/* Values to pass to sendnewportmappingrequest() */ -#define NATPMP_PROTOCOL_UDP (1) -#define NATPMP_PROTOCOL_TCP (2) - -/* return values */ -/* NATPMP_ERR_INVALIDARGS : invalid arguments passed to the function */ -#define NATPMP_ERR_INVALIDARGS (-1) -/* NATPMP_ERR_SOCKETERROR : socket() failed. check errno for details */ -#define NATPMP_ERR_SOCKETERROR (-2) -/* NATPMP_ERR_CANNOTGETGATEWAY : can't get default gateway IP */ -#define NATPMP_ERR_CANNOTGETGATEWAY (-3) -/* NATPMP_ERR_CLOSEERR : close() failed. check errno for details */ -#define NATPMP_ERR_CLOSEERR (-4) -/* NATPMP_ERR_RECVFROM : recvfrom() failed. check errno for details */ -#define NATPMP_ERR_RECVFROM (-5) -/* NATPMP_ERR_NOPENDINGREQ : readnatpmpresponseorretry() called while - * no NAT-PMP request was pending */ -#define NATPMP_ERR_NOPENDINGREQ (-6) -/* NATPMP_ERR_NOGATEWAYSUPPORT : the gateway does not support NAT-PMP */ -#define NATPMP_ERR_NOGATEWAYSUPPORT (-7) -/* NATPMP_ERR_CONNECTERR : connect() failed. check errno for details */ -#define NATPMP_ERR_CONNECTERR (-8) -/* NATPMP_ERR_WRONGPACKETSOURCE : packet not received from the network gateway */ -#define NATPMP_ERR_WRONGPACKETSOURCE (-9) -/* NATPMP_ERR_SENDERR : send() failed. check errno for details */ -#define NATPMP_ERR_SENDERR (-10) -/* NATPMP_ERR_FCNTLERROR : fcntl() failed. check errno for details */ -#define NATPMP_ERR_FCNTLERROR (-11) -/* NATPMP_ERR_GETTIMEOFDAYERR : gettimeofday() failed. check errno for details */ -#define NATPMP_ERR_GETTIMEOFDAYERR (-12) - -/* */ -#define NATPMP_ERR_UNSUPPORTEDVERSION (-14) -#define NATPMP_ERR_UNSUPPORTEDOPCODE (-15) - -/* Errors from the server : */ -#define NATPMP_ERR_UNDEFINEDERROR (-49) -#define NATPMP_ERR_NOTAUTHORIZED (-51) -#define NATPMP_ERR_NETWORKFAILURE (-52) -#define NATPMP_ERR_OUTOFRESOURCES (-53) - -/* NATPMP_TRYAGAIN : no data available for the moment. try again later */ -#define NATPMP_TRYAGAIN (-100) - -#ifdef __cplusplus -extern "C" { -#endif - -/* initnatpmp() - * initialize a natpmp_t object - * With forcegw=1 the gateway is not detected automaticaly. - * Return values : - * 0 = OK - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_SOCKETERROR - * NATPMP_ERR_FCNTLERROR - * NATPMP_ERR_CANNOTGETGATEWAY - * NATPMP_ERR_CONNECTERR */ -LIBSPEC int initnatpmp(natpmp_t * p, int forcegw, in_addr_t forcedgw); - -/* closenatpmp() - * close resources associated with a natpmp_t object - * Return values : - * 0 = OK - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_CLOSEERR */ -LIBSPEC int closenatpmp(natpmp_t * p); - -/* sendpublicaddressrequest() - * send a public address NAT-PMP request to the network gateway - * Return values : - * 2 = OK (size of the request) - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_SENDERR */ -LIBSPEC int sendpublicaddressrequest(natpmp_t * p); - -/* sendnewportmappingrequest() - * send a new port mapping NAT-PMP request to the network gateway - * Arguments : - * protocol is either NATPMP_PROTOCOL_TCP or NATPMP_PROTOCOL_UDP, - * lifetime is in seconds. - * To remove a port mapping, set lifetime to zero. - * To remove all port mappings to the host, set lifetime and both ports - * to zero. - * Return values : - * 12 = OK (size of the request) - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_SENDERR */ -LIBSPEC int sendnewportmappingrequest(natpmp_t * p, int protocol, - uint16_t privateport, uint16_t publicport, - uint32_t lifetime); - -/* getnatpmprequesttimeout() - * fills the timeval structure with the timeout duration of the - * currently pending NAT-PMP request. - * Return values : - * 0 = OK - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_GETTIMEOFDAYERR - * NATPMP_ERR_NOPENDINGREQ */ -LIBSPEC int getnatpmprequesttimeout(natpmp_t * p, struct timeval * timeout); - -/* readnatpmpresponseorretry() - * fills the natpmpresp_t structure if possible - * Return values : - * 0 = OK - * NATPMP_TRYAGAIN - * NATPMP_ERR_INVALIDARGS - * NATPMP_ERR_NOPENDINGREQ - * NATPMP_ERR_NOGATEWAYSUPPORT - * NATPMP_ERR_RECVFROM - * NATPMP_ERR_WRONGPACKETSOURCE - * NATPMP_ERR_UNSUPPORTEDVERSION - * NATPMP_ERR_UNSUPPORTEDOPCODE - * NATPMP_ERR_NOTAUTHORIZED - * NATPMP_ERR_NETWORKFAILURE - * NATPMP_ERR_OUTOFRESOURCES - * NATPMP_ERR_UNSUPPORTEDOPCODE - * NATPMP_ERR_UNDEFINEDERROR */ -LIBSPEC int readnatpmpresponseorretry(natpmp_t * p, natpmpresp_t * response); - -#ifdef ENABLE_STRNATPMPERR -LIBSPEC const char * strnatpmperr(int t); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/pkg/hs/natpmp-static/hsrc_lib/Network/NatPmp.hsc b/pkg/hs/natpmp-static/hsrc_lib/Network/NatPmp.hsc deleted file mode 100644 index f410625d6..000000000 --- a/pkg/hs/natpmp-static/hsrc_lib/Network/NatPmp.hsc +++ /dev/null @@ -1,266 +0,0 @@ -{-# LANGUAGE ForeignFunctionInterface, DeriveDataTypeable #-} - --- | This module is a thin wrapper above libnatpmp.h and getgateway.h. - -module Network.NatPmp (Error(..), - NatPmpResponse(..), - ProtocolType(..), - NatPmpHandle, - Port, - LifetimeSeconds, - initNatPmp, - closeNatPmp, - getDefaultGateway, - getPublicAddress, - setPortMapping) where - -#include - -#include -#include -#include - -import Prelude -import Foreign -import Foreign.C -import Network.Socket - -import Control.Monad.IO.Unlift (MonadIO(..)) - --- Opaque type for the internals of nat pmp -data NatPmpStruct -type NatPmpHandle = Ptr NatPmpStruct - -type Port = Word16 -type LifetimeSeconds = Word32 - --- The response type, in its internal form. This struct is a C tagged union --- with additional data, but we need to read and write from its C form. -data NatPmpResponse - = NatPmpResponsePublicAddress HostAddress - | NatPmpResponseUdpPortMapping Port Port LifetimeSeconds - | NatPmpResponseTcpPortMapping Port Port LifetimeSeconds - deriving (Show) - -instance Storable NatPmpResponse where - sizeOf _ = #{size natpmpresp_t} - alignment _ = alignment (undefined :: CString) - - peek p = do - t <- uintToEnum <$> (#{peek natpmpresp_t, type} p) - case t of - RTPublicAddress -> - NatPmpResponsePublicAddress <$> - (#{peek natpmpresp_t, pnu.publicaddress.addr} p) - RTUdpPortMapping -> - NatPmpResponseUdpPortMapping - <$> (#{peek natpmpresp_t, pnu.newportmapping.privateport} p) - <*> (#{peek natpmpresp_t, pnu.newportmapping.mappedpublicport} p) - <*> (#{peek natpmpresp_t, pnu.newportmapping.lifetime} p) - RTTcpPortMapping -> - NatPmpResponseTcpPortMapping - <$> (#{peek natpmpresp_t, pnu.newportmapping.privateport} p) - <*> (#{peek natpmpresp_t, pnu.newportmapping.mappedpublicport} p) - <*> (#{peek natpmpresp_t, pnu.newportmapping.lifetime} p) - - poke _ _ = error "Responses are an output data structure; poke makes no sense" - -type NatPmpResponseHandle = Ptr NatPmpResponse - -foreign import ccall unsafe "getgateway.h getdefaultgateway" _get_default_gateway :: Ptr CUInt -> IO CInt - -foreign import ccall unsafe "natpmp.h initnatpmp" _init_nat_pmp :: NatPmpHandle -> CInt -> CInt -> IO CInt -foreign import ccall unsafe "natpmp.h closenatpmp" _close_nat_pmp :: NatPmpHandle -> IO CInt -foreign import ccall unsafe "natpmp.h sendpublicaddressrequest" sendPublicAddressRequest :: NatPmpHandle -> IO CInt -foreign import ccall unsafe "natpmp.h sendnewportmappingrequest" sendNewPortMappingRequest :: NatPmpHandle -> CInt -> CUShort -> CUShort -> CUInt -> IO CInt - -foreign import ccall unsafe "binding.h readNatResponseSynchronously" readNatResponseSynchronously :: NatPmpHandle -> NatPmpResponseHandle -> IO CInt - --- Give the type system some help -_peekCUInt :: Ptr CUInt -> IO CUInt -_peekCUInt = peek - -uintToEnum :: Enum e => CUInt -> e -uintToEnum = toEnum . fromIntegral - -intToEnum :: Enum e => CInt -> e -intToEnum = toEnum . fromIntegral - - --- Fetches the default gateway as an ipv4 address -getDefaultGateway :: IO (Maybe HostAddress) -getDefaultGateway = - alloca $ \(pReturnAddr :: Ptr CUInt) -> do - _get_default_gateway pReturnAddr >>= \case - 0 -> (Just . fromIntegral) <$> _peekCUInt pReturnAddr - _ -> pure Nothing - - -data RespType - = RTPublicAddress - | RTUdpPortMapping - | RTTcpPortMapping - deriving (Eq, Show) - -instance Enum RespType where - fromEnum RTPublicAddress = 0 - fromEnum RTUdpPortMapping = 1 - fromEnum RTTcpPortMapping = 2 - - toEnum 0 = RTPublicAddress - toEnum 1 = RTUdpPortMapping - toEnum 2 = RTTcpPortMapping - toEnum unmatched = error ("RespType.toEnum: Cannot match " ++ show unmatched) - - -data ProtocolType - = PTUdp - | PTTcp - deriving (Eq, Show) - -instance Enum ProtocolType where - fromEnum PTUdp = 1 - fromEnum PTTcp = 2 - - toEnum 1 = PTUdp - toEnum 2 = PTTcp - toEnum x = error ("ProtocolType.toEnum: Cannot match " ++ show x) - - -data Error - = ErrInvalidArgs - | ErrSocketError - | ErrCannotGetGateway - | ErrCloseErr - | ErrRecvFrom - | ErrNoPendingReq - | ErrNoGatewaySupport - | ErrConnectErr - | ErrWrongPacketSource - | ErrSendErr - | ErrFcntlError - | ErrGetTimeOfDayError - -- - | ErrUnsuportedVersion - | ErrUnsupportedOpcode - -- - | ErrUndefinedError - | ErrNotAuthorized - | ErrNetworkFailure - | ErrOutOfResources - -- - | ErrTryAgain - | ErrHaskellBindings - deriving (Eq, Show) - -instance Enum Error where - fromEnum ErrInvalidArgs = -1 - fromEnum ErrSocketError = -2 - fromEnum ErrCannotGetGateway = -3 - fromEnum ErrCloseErr = -4 - fromEnum ErrRecvFrom = -5 - fromEnum ErrNoPendingReq = -6 - fromEnum ErrNoGatewaySupport = -7 - fromEnum ErrConnectErr = -8 - fromEnum ErrWrongPacketSource = -9 - fromEnum ErrSendErr = -10 - fromEnum ErrFcntlError = -11 - fromEnum ErrGetTimeOfDayError = -12 - -- - fromEnum ErrUnsuportedVersion = -14 - fromEnum ErrUnsupportedOpcode = -15 - -- - fromEnum ErrUndefinedError = -49 - fromEnum ErrNotAuthorized = -51 - fromEnum ErrNetworkFailure = -52 - fromEnum ErrOutOfResources = -53 - -- - fromEnum ErrTryAgain = -100 - fromEnum ErrHaskellBindings = -200 - - toEnum (-1) = ErrInvalidArgs - toEnum (-2) = ErrSocketError - toEnum (-3) = ErrCannotGetGateway - toEnum (-4) = ErrCloseErr - toEnum (-5) = ErrRecvFrom - toEnum (-6) = ErrNoPendingReq - toEnum (-7) = ErrNoGatewaySupport - toEnum (-8) = ErrConnectErr - toEnum (-9) = ErrWrongPacketSource - toEnum (-10) = ErrSendErr - toEnum (-11) = ErrFcntlError - toEnum (-12) = ErrGetTimeOfDayError - -- - toEnum (-14) = ErrUnsuportedVersion - toEnum (-15) = ErrUnsupportedOpcode - -- - toEnum (-49) = ErrUndefinedError - toEnum (-51) = ErrNotAuthorized - toEnum (-52) = ErrNetworkFailure - toEnum (-53) = ErrOutOfResources - -- - toEnum (-100) = ErrTryAgain - toEnum (-200) = ErrHaskellBindings - toEnum unmatched = error ("Error.toEnum: Cannot match " ++ show unmatched) - - -initNatPmp :: MonadIO m => m (Either Error NatPmpHandle) -initNatPmp = liftIO do - natpmp <- mallocBytes #{size natpmp_t} - ret <- _init_nat_pmp natpmp 0 0 - case ret of - 0 -> pure $ Right natpmp - _ -> do - free natpmp - pure $ Left $ intToEnum ret - - -closeNatPmp :: MonadIO m => NatPmpHandle -> m (Either Error ()) -closeNatPmp handle = liftIO do - ret <- _close_nat_pmp handle - free handle - case ret of - 0 -> pure $ Right () - _ -> pure $ Left $ intToEnum ret - - --- | Public interface for getting the public IPv4 address -getPublicAddress :: MonadIO m => NatPmpHandle -> m (Either Error HostAddress) -getPublicAddress natpmp = liftIO do - sendRetcode <- sendPublicAddressRequest natpmp - case sendRetcode of - 2 -> alloca $ \(pResponse :: NatPmpResponseHandle) -> do - respRetcode <- readNatResponseSynchronously natpmp pResponse - case respRetcode of - 0 -> peek pResponse >>= \case - NatPmpResponsePublicAddress addr -> pure $ Right addr - _ -> pure $ Left ErrHaskellBindings - _ -> pure $ Left $ intToEnum respRetcode - _ -> pure $ Left $ intToEnum sendRetcode - --- | Requests that the router maps the privatePort on our local computer in our --- private network to publicPort on the public internet. -setPortMapping :: MonadIO m - => NatPmpHandle - -> ProtocolType - -> Port - -> Port - -> LifetimeSeconds - -> m (Either Error ()) -setPortMapping natpmp protocol privatePort publicPort lifetime = liftIO do - let protocolNum = fromEnum protocol - sendResp <- - sendNewPortMappingRequest natpmp - (fromIntegral protocolNum) (CUShort privatePort) (CUShort publicPort) - (CUInt lifetime) - - case sendResp of - 12 -> alloca $ \(pResponse :: NatPmpResponseHandle) -> do - respRetcode <- readNatResponseSynchronously natpmp pResponse - case respRetcode of - 0 -> peek pResponse >>= \case - NatPmpResponseUdpPortMapping _ _ _ -> pure $ Right () - NatPmpResponseTcpPortMapping _ _ _ -> pure $ Right () - _ -> pure $ Left ErrHaskellBindings - _ -> pure $ Left $ intToEnum respRetcode - x -> pure $ Left $ intToEnum x diff --git a/pkg/hs/natpmp-static/natpmp-static.cabal b/pkg/hs/natpmp-static/natpmp-static.cabal deleted file mode 100644 index 9ee268ab7..000000000 --- a/pkg/hs/natpmp-static/natpmp-static.cabal +++ /dev/null @@ -1,89 +0,0 @@ -cabal-version: >=1.10 --- Initial package description 'natpmp-static.cabal' generated by 'cabal --- init'. For further documentation, see --- http://haskell.org/cabal/users-guide/ - -name: natpmp-static -version: 0.1.0.0 -synopsis: Haskell bindings to libnatpmp -description: - libnatpmp is a C library to communicate with routers and request - that they port forward traffic from the outside internet to your - program. - . - natpmp-static has Haskell bindings to libnatpmp to allow Haskell - programs to punch NAT holes in routers, containing a vendored copy - of the libnatpmp code so that we build Urbit's "almost static" - builds which we distribute. - . - See for upstream source. - --- bug-reports: -license: BSD3 -license-file: LICENSE -author: Elliot Glaysher -maintainer: elliot@tlon.io -copyright: (c) 2020 Tlon. -stability: experimental -build-type: Simple - -library - hs-Source-Dirs: hsrc_lib - default-language: Haskell2010 - build-depends: base - , network - , unliftio-core - build-tools: hsc2hs - - Include-dirs: cbits - Includes: natpmp.h getgateway.h - C-Sources: cbits/natpmp.c cbits/getgateway.c cbits/binding.c - cc-options: -Wall -Os -g -fPIC - ghc-options: -Wall -fprof-auto -fPIC - - exposed-modules: Network.NatPmp - -- other-modules: - -- other-extensions: - - default-extensions: ApplicativeDo - , BangPatterns - , BlockArguments - , DataKinds - , DefaultSignatures - , DeriveAnyClass - , DeriveDataTypeable - , DeriveFoldable - , DeriveGeneric - , DeriveTraversable - , DerivingStrategies - , EmptyCase - , EmptyDataDecls - , FlexibleContexts - , FlexibleInstances - , FunctionalDependencies - , GADTs - , GeneralizedNewtypeDeriving - , LambdaCase - , MagicHash - , MultiParamTypeClasses - , NamedFieldPuns - , NoImplicitPrelude - , NumericUnderscores - , OverloadedStrings - , PartialTypeSignatures - , PatternSynonyms - , QuasiQuotes - , Rank2Types - , RankNTypes - , RecordWildCards - , ScopedTypeVariables - , StandaloneDeriving - , TemplateHaskell - , TupleSections - , TypeApplications - , TypeFamilies - , TypeOperators - , UnboxedTuples - , UnicodeSyntax - , ViewPatterns - diff --git a/pkg/hs/proto/.gitignore b/pkg/hs/proto/.gitignore deleted file mode 100644 index d1287e423..000000000 --- a/pkg/hs/proto/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.stack-work/ -proto.cabal -*~ \ No newline at end of file diff --git a/pkg/hs/proto/LICENSE b/pkg/hs/proto/LICENSE deleted file mode 100644 index bf9294e05..000000000 --- a/pkg/hs/proto/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 urbit - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/pkg/hs/proto/app/Main.hs b/pkg/hs/proto/app/Main.hs deleted file mode 100644 index 4ac595db0..000000000 --- a/pkg/hs/proto/app/Main.hs +++ /dev/null @@ -1,41 +0,0 @@ -module Main where - -import ClassyPrelude - -import Control.Lens ((&)) - -import Untyped.Parser hiding (main) -import Untyped.CST -import Untyped.Hoon -import Untyped.Core -import Nock -import SimpleNoun -import Dashboard - -import Text.Show.Pretty (pPrint) - -import qualified Prelude as P - -------------------------------------------------------------------------------- - -main :: IO () -main = (P.head <$> getArgs) >>= compileHoonTest - -compileHoonTest :: Text -> IO () -compileHoonTest ln = do - cst <- parse ln & \case - Left x -> error (unpack x) - Right x -> pure x - -- pPrint cst - hon <- pure $ hone cst - pPrint hon - exp <- pure $ desugar hon - pPrint exp - nok <- pure $ copy exp - putStrLn "==== input ====" - putStrLn ln - putStrLn "==== nock ====" - pPrint nok - putStrLn "==== output ====" - res <- runCare $ nock (A 140) nok - pPrint res diff --git a/pkg/hs/proto/lib/Dashboard.hs b/pkg/hs/proto/lib/Dashboard.hs deleted file mode 100644 index 9812eb343..000000000 --- a/pkg/hs/proto/lib/Dashboard.hs +++ /dev/null @@ -1,135 +0,0 @@ -module Dashboard - ( pattern FastAtom - , pattern FastHint - , Jet - , Dashboard (match) - , Freeboard - , Hashboard - , Fastboard - , Careboard - , runFree - , runHash - , runFast - , runCare - ) where - -import ClassyPrelude - -import Control.Monad.State.Strict - -import SimpleNoun - -type Jet = Noun -> Noun -type JetName = Atom -type Hash = Int - -pattern FastAtom = 1953718630 -- %fast -pattern FastHint id n = - C (A 11) - (C - (C (A FastAtom) (C (A 1) (A id))) - n) - --- | A context in which to run nock which supports jet lookup. -class Monad m => Dashboard m where - -- | Find the jet associated with the formula represented by the given noun, - -- if any. - match :: Noun -> m (Maybe Jet) - --- | A dashboard which doesn't jet. -newtype Freeboard a = Freeboard (Identity a) - deriving newtype Functor - deriving newtype Applicative - deriving newtype Monad - --- | A dashboard which looks for jets by formula hash -newtype Hashboard a = Hashboard (Identity a) - deriving newtype Functor - deriving newtype Applicative - deriving newtype Monad - --- | A dashboard which checks the head of formulas for "fast --- hints" and uses the name contained in such a hint to look for jets. -newtype Fastboard a = Fastboard (Identity a) - deriving newtype Functor - deriving newtype Applicative - deriving newtype Monad - --- | A dashboard which uses both lookup strategies, checking for consistency --- between them and that each fast hint is applied to a unique formula. --- Violations of these principles are written to standard out. -newtype Careboard a = Careboard (StateT (HashMap JetName Noun) IO a) - deriving newtype Functor - deriving newtype Applicative - deriving newtype Monad - -runFree :: Freeboard a -> a -runFree (Freeboard x) = runIdentity x - -runHash :: Hashboard a -> a -runHash (Hashboard x) = runIdentity x - -runFast :: Fastboard a -> a -runFast (Fastboard x) = runIdentity x - -runCare :: Careboard a -> IO a -runCare (Careboard x) = evalStateT x mempty - -instance Dashboard Freeboard where - match _ = Freeboard $ pure Nothing - -instance Dashboard Hashboard where - match = Hashboard . pure . byHash . hash - -instance Dashboard Fastboard where - match = Fastboard . \case - FastHint id n -> pure (byFast id) - _ -> pure Nothing - --- TODO maybe also detect hash collisions -instance Dashboard Careboard where - match = Careboard . \case - n@(FastHint nm _) -> case namely nm of - Just (h, j) -> do - when (h /= hash n) $ - putStrLn ("careboard: jet " <> tshowA nm <> " should have its hash " - <> "updated from " <> tshow h <> " to " <> tshow (hash n)) - get <&> lookup nm >>= \case - Just n' -> - when (n' /= n) $ - putStrLn ("careboard: jet hint " <> tshowA nm <> " has been " - <> "detected on unequal formulae " <> tshow n - <> " and " <> tshow n' <> ", which is very bad") - Nothing -> modify' (insertMap nm n) - pure (Just j) - Nothing -> do - putStrLn ("careboard: unmatched fast hint: " ++ tshowA nm) - pure $ byHash $ hash n - n -> pure $ byHash $ hash n - -byFast :: JetName -> Maybe Jet -byFast = flip lookup fast - where - fast :: HashMap JetName Jet - fast = mapFromList $ map (\(n, _, j) -> (n, j)) jets - -byHash :: Hash -> Maybe Jet -byHash = flip lookup hash - where - hash :: HashMap Hash Jet - hash = mapFromList $ map (\(_, h, j) -> (h, j)) jets - -namely :: JetName -> Maybe (Hash, Jet) -namely = flip lookup fash - where - fash :: HashMap JetName (Hash, Jet) - fash = mapFromList $ map (\(n, h, j) -> (n, (h, j))) jets - -tx = textToAtom - -type Entry = (JetName, Hash, Jet) --- | Your jets here -jets :: [Entry] -jets = - [ (tx "dec", 1520491622440108403, \(A a) -> trace "jetting" $ A (a - 1)) - ] diff --git a/pkg/hs/proto/lib/Deppy/Core.hs b/pkg/hs/proto/lib/Deppy/Core.hs deleted file mode 100644 index 93a2b3260..000000000 --- a/pkg/hs/proto/lib/Deppy/Core.hs +++ /dev/null @@ -1,302 +0,0 @@ -module Deppy.Core where - -import ClassyPrelude - -import Bound -import Data.Deriving (deriveEq1, deriveOrd1, deriveRead1, deriveShow1) -import Data.Maybe (fromJust) -import Data.Set (isSubsetOf) -import qualified Data.Set as Set -import Numeric.Natural - -type Typ = Exp - -data Exp a - = Var a - -- types - | Typ - | Fun (Abs a) - | Cel (Abs a) - | Wut (Set Tag) - -- introduction forms - | Lam (Abs a) - | Cns (Exp a) (Exp a) - | Tag Tag - -- elimination forms - | App (Exp a) (Exp a) - | Hed (Exp a) - | Tal (Exp a) - | Cas (Typ a) (Exp a) (Map Tag (Exp a)) - -- recursion, flow control - | Let (Exp a) (Scope () Exp a) - | Rec (Abs a) - deriving (Functor, Foldable, Traversable) - -type Tag = Natural - -data Abs a = Abs - { spec :: Typ a - , body :: Scope () Exp a - } - deriving (Functor, Foldable, Traversable) - -deriveEq1 ''Abs -deriveOrd1 ''Abs -deriveRead1 ''Abs -deriveShow1 ''Abs ---makeBound ''Abs - -deriveEq1 ''Exp -deriveOrd1 ''Exp -deriveRead1 ''Exp -deriveShow1 ''Exp ---makeBound ''Exp - -deriving instance Eq a => Eq (Abs a) -deriving instance Ord a => Ord (Abs a) -deriving instance Read a => Read (Abs a) -deriving instance Show a => Show (Abs a) - -deriving instance Eq a => Eq (Exp a) -deriving instance Ord a => Ord (Exp a) -deriving instance Read a => Read (Exp a) -deriving instance Show a => Show (Exp a) - -instance Applicative Exp where - pure = Var - (<*>) = ap - -instance Monad Exp where - return = Var - Var a >>= f = f a - Typ >>= _ = Typ - Fun a >>= f = Fun (bindAbs a f) - Cel a >>= f = Cel (bindAbs a f) - Wut ls >>= _ = Wut ls - Lam a >>= f = Lam (bindAbs a f) - Cns x y >>= f = Cns (x >>= f) (y >>= f) - Tag l >>= _ = Tag l - App x y >>= f = App (x >>= f) (y >>= f) - Hed x >>= f = Hed (x >>= f) - Tal x >>= f = Tal (x >>= f) - Cas t x cs >>= f = Cas (t >>= f) (x >>= f) (cs <&> (>>= f)) - Let a b >>= f = Let (a >>= f) (b >>>= f) - Rec a >>= f = Rec (bindAbs a f) - -bindAbs :: Abs a -> (a -> Exp b) -> Abs b -bindAbs (Abs s b) f = Abs (s >>= f) (b >>>= f) - -lam :: Eq a => a -> Typ a -> Exp a -> Exp a -lam v t e = Lam (Abs t (abstract1 v e)) - -fun :: Eq a => a -> Typ a -> Typ a -> Typ a -fun v t u = Fun (Abs t (abstract1 v u)) - -fun_ :: Typ a -> Typ a -> Typ a -fun_ t u = Fun (Abs t (abstract (const Nothing) u)) - -cel :: Eq a => a -> Typ a -> Typ a -> Typ a -cel v t u = Cel (Abs t (abstract1 v u)) - -cel_ :: Typ a -> Typ a -> Typ a -cel_ t u = Cel (Abs t (abstract (const Nothing) u)) - -rec :: Eq a => a -> Typ a -> Exp a -> Exp a -rec v t e = Rec (Abs t (abstract1 v e)) - -ledt :: Eq a => a -> Exp a -> Exp a -> Exp a -ledt v e e' = Let e (abstract1 v e') - -wut = Wut . setFromList - -cas t e cs = Cas t e (mapFromList cs) - -infixl 9 @: -(@:) = App - --- | typing environment -type Env a = a -> Typ a - -extend :: (b -> Typ a) -> Env a -> Env (Var b a) -extend handleNewBindings oldEnv = \case - -- TODO can we use Scope to decrease the cost of this? - B v -> F <$> handleNewBindings v - F v -> F <$> oldEnv v - -extend1 :: Typ a -> Env a -> Env (Var () a) -extend1 t = extend \() -> t - --- | amber rule assumptions -type Asm a = Set (Typ a, Typ a) - -extendAsm :: (Ord a, Ord b) => Asm a -> Asm (Var b a) -extendAsm = Set.map \(t, u) -> (F <$> t, F <$> u) - --- | Remove types that mention variables that are no longer in scope -retractAsm :: (Ord a, Ord b) => Asm (Var b a) -> Asm a -retractAsm = foldMap wither - where - wither = \case - (cleanTyp -> Just t, cleanTyp -> Just u) -> singleton (t, u) - _ -> mempty - cleanTyp = traverse \case - F v -> pure v - B _ -> Nothing - -type Typing = Maybe - --- TODO --- - better errors --- - state monad for Asm (how to handle polymorphic recursion?) -nest :: (Show a, Ord a) => Env a -> Typ a -> Typ a -> Typing () -nest env = fmap void . go env mempty - where - go :: (Show a, Ord a) => Env a -> Asm a -> Typ a -> Typ a -> Typing (Asm a) - -- FIXME use a better more aggro normal form - go env asm0 (whnf -> t0) (whnf -> u0) = - if t0 == u0 || member (t0, u0) asm0 - then pure asm0 - else let asm = Set.insert (t0, u0) asm0 in - case (t0, u0) of - (Typ, Typ) -> pure asm - -- FIXME yeah actually I think this is wrong - -- we're comaring the type of a type variable with - -- (Var v, u) -> go env asm (env v) u - -- (t, Var v) -> go env asm t (env v) - -- following Cardelli 80something, we check the RHSs assuming - -- the putatively *lesser* of the LHSs for both - (Fun (Abs a b), Fun (Abs a' b')) -> do - asm' <- go env asm a' a - retractAsm <$> - go (extend1 a' env) (extendAsm asm') (fromScope b) (fromScope b') - (Cel (Abs a b), Cel (Abs a' b')) -> do - asm' <- go env asm a a' - retractAsm <$> - go (extend1 a env) (extendAsm asm') (fromScope b) (fromScope b') - (Wut ls, Wut ls') -> do - guard (ls `isSubsetOf` ls') - pure asm - -- TODO put into Typing errors - (Lam{}, _) -> error "nest: lambda" - (_, Lam{}) -> error "nest: lambda" - (Cns{}, _) -> error "nest: cons" - (_, Cns{}) -> error "nest: cons" - (Tag{}, _) -> error "nest: tag" - (_, Tag{}) -> error "nest: tag" - -- Special rule for the Cas eliminator to enable sums and products - (Cas _ e cs, Cas _ e' cs') -> do - guard (whnf e == whnf e') - Wut s <- infer env e - -- TODO I should thread changing asm through the traversal - -- but I can't be bothered right now. Perf regression. - asm <$ traverse_ chk (setToList s) - where - chk tag = case (lookup tag cs, lookup tag cs') of - (Just t, Just u) -> go env asm t u - _ -> error "the Spanish inquisition" - (Cas _ e cs, u) -> do - Wut s <- infer env e - -- TODO thread asms - asm <$ traverse_ - (\tag -> go env asm (fromJust $ lookup tag cs) u) - s - (t, Cas _ e cs) -> do - Wut s <- infer env e - -- TODO thread asms - asm <$ traverse_ - (\tag -> go env asm t (fromJust $ lookup tag cs)) - s - (t@Cas{}, u) -> go env asm (whnf t) u - (t, u@Cas{}) -> go env asm t (whnf u) - (t@(Rec (Abs _ b)), u) -> go env asm (instantiate1 t b) u - (t, u@(Rec (Abs _ b))) -> go env asm t (instantiate1 u b) - _ -> Nothing - -check :: (Show a, Ord a) => Env a -> Exp a -> Typ a -> Typing () -check env e t = do - t' <- infer env e - nest env t' t - -infer :: forall a. (Show a, Ord a) => Env a -> Exp a -> Typing (Typ a) -infer env = \case - Var v -> pure $ env v - Typ -> pure Typ - Fun (Abs t b) -> do - Typ <- infer env t - Typ <- infer (extend1 t env) (fromScope b) - pure Typ - Cel (Abs t b) -> do - Typ <- infer env t - Typ <- infer (extend1 t env) (fromScope b) - pure Typ - Wut _ -> pure Typ - Lam (Abs t b) -> do - -- TODO do I need (whnf -> Typ)? (and elsewhere) - Typ <- infer env t - (toScope -> t') <- infer (extend1 t env) (fromScope b) - pure $ Fun (Abs t t') - Cns x y -> do - -- Infer non-dependent pairs; if you want dependency, you must annotate - t <- infer env x - u <- infer env y - pure $ Cel (Abs t (abstract (const Nothing) u)) - Tag t -> pure $ Wut (singleton t) - App x y -> do - Fun (Abs t b) <- infer env x - check env y t - pure $ whnf (instantiate1 y b) - Hed x -> do - Cel (Abs t _) <- infer env x - pure t - Tal x -> do - Cel (Abs _ u) <- infer env x - pure $ instantiate1 (whnf $ Hed $ x) u - Cas t x cs -> do - Typ <- infer env t - Wut ts <- infer env x - -- pretty restrictive - do we want? - guard (ts == keysSet cs) - traverse_ (\e -> check env e t) cs - pure t - -- Let e b -> do - -- -- TODO is below faster, or infer env (instantiate1 e b)? - -- t <- infer env e - -- instantiate1 e $ infer (extend1 t env) (fromScope b) - Rec (Abs t b) -> do - Typ <- infer env t - -- todo can F <$> be made faster? - check (extend1 t env) (fromScope b) (F <$> t) - pure t - -whnf :: (Show a, Eq a) => Exp a -> Exp a -whnf = \case - App (whnf -> Lam (Abs _ b)) x -> whnf $ instantiate1 x b - Hed (whnf -> Cns x _) -> whnf x - Tal (whnf -> Cns _ y) -> whnf y - Cas _ (whnf -> Tag t) cs -> whnf $ fromJust $ lookup t cs - e@(Rec (Abs _ b)) -> whnf $ instantiate1 e b - e -> trace "sadface" e -{- - = Var a - -- types - | Typ - | Fun (Abs a) - | Cel (Abs a) - | Wut (Set Tag) - -- introduction forms - | Lam (Abs a) - | Cns (Exp a) (Exp a) - | Tag Tag - -- elimination forms - | App (Exp a) (Exp a) - | Hed (Exp a) - | Tal (Exp a) - | Cas (Typ a) (Exp a) (Map Tag (Exp a)) - -- recursion - | Rec (Abs a) --} - -nf :: (Show a, Eq a) => Exp a -> Exp a -nf = traceShowId . \case - Typ -> Typ - _ -> undefined diff --git a/pkg/hs/proto/lib/Nock.hs b/pkg/hs/proto/lib/Nock.hs deleted file mode 100644 index 85190f3fc..000000000 --- a/pkg/hs/proto/lib/Nock.hs +++ /dev/null @@ -1,114 +0,0 @@ -module Nock where - -import ClassyPrelude - -import Dashboard -import SimpleNoun - -data Nock - = NC Nock Nock -- ^ ^: autocons - | N0 Axis -- ^ 0, axis: tree addressing - | N1 Noun -- ^ 1, const - | N2 Nock Nock -- ^ 2, compose: compute subject, formula; apply - | N3 Nock -- ^ 3, is cell - | N4 Nock -- ^ 4, succ - | N5 Nock Nock -- ^ 5, eq - | N6 Nock Nock Nock -- ^ 6, if - | N7 Nock Nock -- ^ 7, then: => - | N8 Nock Nock -- ^ 8, push: =+ - | N9 Axis Nock -- ^ 9, invoke - | N10 (Axis, Nock) Nock -- ^ 10, edit - | N11 Hint Nock -- ^ 11, hint - | N12 Nock Nock -- ^ 12, scry - deriving (Eq, Ord, Read, Generic) - -data Hint - = Tag Atom - | Assoc Atom Nock - deriving (Eq, Ord, Read, Show, Generic) - -instance Hashable Nock -instance Hashable Hint - -instance Show Nock where - show = show . nockToNoun - -nockToNoun :: Nock -> Noun -nockToNoun = go - where - go = \case - NC f g -> C (go f) (go g) - N0 a -> C (A 0) (A a) - N1 n -> C (A 1) n - N2 f g -> C (A 2) (C (go f) (go g)) - N3 f -> C (A 3) (go f) - N4 f -> C (A 4) (go f) - N5 f g -> C (A 5) (C (go f) (go g)) - N6 f g h -> C (A 6) (C (go f) (C (go g) (go h))) - N7 f g -> C (A 7) (C (go f) (go g)) - N8 f g -> C (A 8) (C (go f) (go g)) - N9 a f -> C (A 9) (C (A a) (go f)) - N10 (a, f) g -> C (A 10) (C (C (A a) (go f)) (go g)) - N11 (Tag a) f -> C (A 11) (C (A a) (go f)) - N11 (Assoc a f) g -> C (A 11) (C (C (A a) (go f)) (go g)) - N12 f g -> C (A 12) (C (go f) (go g)) - -nounToNock :: Noun -> Nock -nounToNock = go - where - go = \case - A{} -> error "nounToNock: atom" - C n@C{} m -> NC (go n) (go m) - C (A op) n -> case op of - 0 | (A a) <- n -> N0 a - 1 -> N1 n - 2 | (C m o) <- n -> N2 (go m) (go o) - 3 -> N3 (go n) - 4 -> N4 (go n) - 5 | (C m o) <- n -> N5 (go m) (go o) - 6 | (C m (C o p)) <- n -> N6 (go m) (go o) (go p) - 7 | (C m o) <- n -> N7 (go m) (go o) - 8 | (C m o) <- n -> N8 (go m) (go o) - 9 | (C (A a) m) <- n -> N9 a (go m) - 10 | (C (C (A a) m) o) <- n -> N10 (a, (go m)) (go o) - 11 | (C (C (A a) m) o) <- n -> N11 (Assoc a (go m)) (go o) - | (C (A a) m) <- n -> N11 (Tag a) (go m) - 12 | (C m o) <- n -> N12 (go m) (go o) - _ -> error ("nockToNoun: invalid " <> show op <> " " <> show n) - --- | Nock interpreter -nock :: (Dashboard d) => Noun -> Nock -> d Noun -nock n = \case - NC f g -> C <$> nock n f <*> nock n g - N0 a -> pure $ axis a n - N1 n' -> pure n' - N2 sf ff -> do - s <- nock n sf - f <- nock n ff - match f >>= \case - Just jet -> pure (jet s) - Nothing -> nock s (nounToNock f) - N3 f -> nock n f <&> \case - C{} -> yes - A{} -> no - N4 f -> nock n f <&> \case - C{} -> error "nock: cannot increment cell" - A a -> A (a + 1) - N5 f g -> loob <$> ((==) <$> nock n f <*> nock n g) - N6 f g h -> nock n f >>= \case - (A 0) -> nock n g - (A 1) -> nock n h - _ -> error "nock: invalid test value" - N7 f g -> do - n' <- nock n f - nock n' g - N8 f g -> do - n' <- nock n f - nock (C n' n) g - N9 a f -> do - c <- nock n f - nock c (nounToNock (axis a c)) - N10 (a, f) g -> edit a <$> nock n f <*> nock n g - N11 _ f -> nock n f - N12{} -> error "nock: scrying is not allowed" - diff --git a/pkg/hs/proto/lib/SimpleNoun.hs b/pkg/hs/proto/lib/SimpleNoun.hs deleted file mode 100644 index 1c6294a45..000000000 --- a/pkg/hs/proto/lib/SimpleNoun.hs +++ /dev/null @@ -1,123 +0,0 @@ -module SimpleNoun where - -import ClassyPrelude -import Numeric.Natural - -import qualified Urbit.Noun as N - -type Atom = Natural - -type Noun = Tree Atom -data Tree a - = A !a - | C !(Tree a) !(Tree a) - deriving (Eq, Ord, Read, Functor, Generic) - -instance Hashable a => Hashable (Tree a) - -data Fern a - = FernA !a - | FernF [Fern a] - -toFern :: Tree a -> Fern a -toFern = \case - A a -> FernA a - C h t -> case toFern t of - a@FernA{} -> FernF [toFern h, a] - FernF fs -> FernF (toFern h : fs) - -instance Show a => Show (Fern a) where - show = \case - FernA a -> show a - FernF xs -> "[" <> intercalate " " (map show xs) <> "]" - -instance Show a => Show (Tree a) where - show = show . toFern - -yes, no :: Noun -yes = A 0 -no = A 1 - -loob :: Bool -> Noun -loob = \case - True -> yes - False -> no - -textToAtom :: Text -> Atom -textToAtom t = case N.textToUtf8Atom t of - N.A a -> a - N.C _ _ -> error "textToAtom: nani!?" - -showA :: Atom -> String -showA a = show (N.A a) - -tshowA :: Atom -> Text -tshowA = pack . showA - --- | Tree address -type Axis = Atom - -data Dir = L | R - deriving (Eq, Ord, Enum, Read, Show) -type Path = [Dir] - --- some stuff from hoon.hoon - -cap :: Axis -> Dir -cap = \case - 2 -> L - 3 -> R - a | a <= 1 -> error "cap: bad axis" - | otherwise -> cap (div a 2) - -mas :: Axis -> Axis -mas = \case - 2 -> 1 - 3 -> 1 - a | a <= 1 -> error "mas: bad axis" - | otherwise -> (mod a 2) + 2 * mas (div a 2) - -capMas :: Axis -> (Dir, Axis) -capMas = \case - 2 -> (L, 1) - 3 -> (R, 1) - a | a <= 1 -> error "capMas: bad axis" - | otherwise -> (d, (mod a 2) + 2 * r) - where - (d, r) = capMas (div a 2) - -peg :: Axis -> Axis -> Axis -peg a = \case - 1 -> a - 2 -> a * 2 - 3 -> a * 2 + 1 - b -> (mod b 2) + 2 * peg a (div b 2) - -axis :: Axis -> Tree a -> Tree a -axis 1 n = n -axis (capMas -> (d, r)) (C n m) = case d of - L -> axis r n - R -> axis r m -axis a _ = error ("bad axis: " ++ show a) - -edit :: Axis -> Tree a -> Tree a -> Tree a -edit 1 v n = v -edit (capMas -> (d, r)) v (C n m) = case d of - L -> C (edit r v n) m - R -> C n (edit r v m) -edit a _ _ = error ("bad edit: " ++ show a) - --- Write an axis as a binary number; e.g. 5 as 101. --- The rule is: after droping the 1 in the msb, you read from left to right. --- 0 becomes L and 1 becomes R. So 5 becomes [L,R] -toPath :: Axis -> Path -toPath = \case - 1 -> [] - (capMas -> (d, r)) -> d : toPath r - -toAxis :: Path -> Axis -toAxis = foldl' step 1 - where - step r = \case - L -> 2 * r - R -> 2 * r + 1 diff --git a/pkg/hs/proto/lib/Untyped/CST.hs b/pkg/hs/proto/lib/Untyped/CST.hs deleted file mode 100644 index 5ac2a37ec..000000000 --- a/pkg/hs/proto/lib/Untyped/CST.hs +++ /dev/null @@ -1,54 +0,0 @@ -module Untyped.CST where - -import ClassyPrelude -import Prelude (foldr1) - -import SimpleNoun -import qualified Untyped.Hoon as H -import Untyped.Parser -- remove after we've moved the CST type - -hone :: CST -> H.Hoon Sym -hone = go - where - go = \case - WutCol c d e -> H.WutCol (go c) (go d) (go e) - WutPat c d e -> H.WutPat (go c) (go d) (go e) - WutKet c d e -> H.WutKet (go c) (go d) (go e) - WutPam cs -> foldr H.WutPam (H.HAtom 0) $ map go cs - WutBar cs -> foldr H.WutBar (H.HAtom 1) $ map go cs - WutHep c pcs -> H.WutHep (go c) (map tr pcs) - TisFas s c d -> H.TisFas s (go c) (go d) - ColHep c d -> H.HCons (go c) (go d) - ColLus{} -> error "hone: offensive rune :+ -- use :*" - ColKet{} -> error "hone: offensive rune :^ -- use :*" - ColTar [] -> error "hone: empty :*" - ColTar cs -> foldr1 H.HCons $ map go cs - ColSig cs -> foldr H.HCons (H.HAtom 0) $ map go cs - BarTis s c -> H.BarTis s (go c) - BarHep r v i c -> H.BarHep r v (go i) (go c) - BarCen pcs -> H.BarCen (map tr pcs) - CenHep c d -> H.CenHep (go c) (go d) - CenDot c d -> H.CenDot (go c) (go d) - DotDot s c -> H.DotDot s (go c) - SigFas (go -> H.HAtom a) c -> H.SigFas a (go c) - SigFas{} -> error "hone: invalid ~/ tag" - ZapZap -> H.ZapZap - Tupl cs -> go (ColTar cs) - Var s -> H.HVar s - Atom a -> H.HAtom a - Tag tx -> H.HAtom (textToAtom tx) - Cord tx -> H.HAtom (textToAtom tx) - Tape tx -> error "hone: tapes not implemented" - Incr c -> H.DotLus (go c) - IncrIrr c -> H.DotLus (go c) - AppIrr c d -> H.CenHep (go c) (go d) - IsEq c d -> H.DotTis (go c) (go d) - IsEqIrr c d -> H.DotTis (go c) (go d) - Pam -> H.HAtom 0 - Bar -> H.HAtom 1 - Yes -> H.HAtom 0 - No -> H.HAtom 1 - Sig -> H.HAtom 0 - - tr (PatTar, c) = (H.Wild, go c) - tr (PatTag s, c) = (H.Exact (A $ textToAtom s), go c) diff --git a/pkg/hs/proto/lib/Untyped/Core.hs b/pkg/hs/proto/lib/Untyped/Core.hs deleted file mode 100644 index e70dcebb7..000000000 --- a/pkg/hs/proto/lib/Untyped/Core.hs +++ /dev/null @@ -1,227 +0,0 @@ -module Untyped.Core where - -import ClassyPrelude - -import Bound -import Control.Monad.Writer hiding (fix) -import Data.Deriving (deriveEq1, deriveOrd1, deriveRead1, deriveShow1) -import Data.Maybe (fromJust) -import qualified Data.Set as Set - -import Dashboard (pattern FastAtom) -import Nock -import SimpleNoun - -type Nat = Int - -data Exp a - = Var a - | App (Exp a) (Exp a) - | Lam (Scope () Exp a) - | Atm Atom - | Cel (Exp a) (Exp a) - | IsC (Exp a) - | Suc (Exp a) - | Eql (Exp a) (Exp a) - | Ift (Exp a) (Exp a) (Exp a) - | Let (Exp a) (Scope () Exp a) - | Jet Atom (Exp a) - | Fix (Scope () Exp a) - | Zap - deriving (Functor, Foldable, Traversable) - -deriveEq1 ''Exp -deriveOrd1 ''Exp -deriveRead1 ''Exp -deriveShow1 ''Exp -makeBound ''Exp - -deriving instance Eq a => Eq (Exp a) -deriving instance Ord a => Ord (Exp a) -deriving instance Read a => Read (Exp a) -deriving instance Show a => Show (Exp a) - -lam :: Eq a => a -> Exp a -> Exp a -lam v e = Lam (abstract1 v e) - -ledt :: Eq a => a -> Exp a -> Exp a -> Exp a -ledt v e f = Let e (abstract1 v f) - -fix :: Eq a => a -> Exp a -> Exp a -fix v e = Fix (abstract1 v e) - --- | The expression that returns the given noun as a constant. -con :: Noun -> Exp a -con = \case - A a -> Atm a - C n m -> Cel (con n) (con m) - -data CExp a - = CVar a - | CSef a - | CApp (CExp a) (CExp a) - | CLam [a] (CExp (Var () Int)) - | CAtm Atom - | CCel (CExp a) (CExp a) - | CIsC (CExp a) - | CSuc (CExp a) - | CEql (CExp a) (CExp a) - | CIft (CExp a) (CExp a) (CExp a) - | CLet (CExp a) (CExp (Var () a)) - | CJet Atom (CExp a) - | CFix [a] (CExp (Var () Int)) - | CZap - deriving (Functor, Foldable, Traversable) - -deriveEq1 ''CExp -deriveOrd1 ''CExp -deriveRead1 ''CExp -deriveShow1 ''CExp - -deriving instance Eq a => Eq (CExp a) -deriving instance Ord a => Ord (CExp a) -deriving instance Read a => Read (CExp a) -deriving instance Show a => Show (CExp a) - -data Manner a - = Direct a - | Selfish a - deriving (Functor, Foldable, Traversable) - -rude :: Manner a -> a -rude = \case - Direct x -> x - Selfish x -> x - -toCopy :: Ord a => Exp a -> CExp b -toCopy = fst . runWriter . go \v -> error "toCopy: free variable" - where - go :: Ord a => (a -> Manner c) -> Exp a -> Writer (Set a) (CExp c) - go env = \case - Var v -> do - tell (singleton v) - case env v of - Direct v' -> pure (CVar v') - Selfish v' -> pure (CSef v') - App e f -> CApp <$> go env e <*> go env f - Atm a -> pure (CAtm a) - Cel e f -> CCel <$> go env e <*> go env f - IsC e -> CIsC <$> go env e - Suc e -> CSuc <$> go env e - Eql e f -> CEql <$> go env e <*> go env f - Ift e t f -> CIft <$> go env e <*> go env t <*> go env f - Jet a e -> CJet a <$> go env e - Zap -> pure CZap - Let e s -> do - ce <- go env e - let - env' = \case - B () -> Direct (B ()) - F x -> fmap F (env x) - cf <- retcon removeBound (go env' (fromScope s)) - pure (CLet ce cf) - Fix s -> lam s env CFix Selfish - Lam s -> lam s env CLam Direct - - lam s env ctor manner = - writer - ( ctor (rude . env <$> Set.toAscList usedLexicals) ce - , usedLexicals - ) - where - (ce, usedVars) = runWriter $ go env' $ fromScope s - env' = \case - B () -> manner $ B () - F v -> env v $> F (Set.findIndex v usedLexicals) - usedLexicals = removeBound usedVars - - removeBound :: (Ord a, Ord b) => Set (Var b a) -> Set a - removeBound = mapMaybeSet \case - B _ -> Nothing - F v -> Just v - --- | Like censor, except you can change the type of the log -retcon :: (w -> uu) -> Writer w a -> Writer uu a -retcon f = mapWriter \(a, m) -> (a, f m) - --- I begin to wonder why there aren't primary abstractions around filtering. -mapMaybeSet :: (Ord a, Ord b) => (a -> Maybe b) -> Set a -> Set b -mapMaybeSet f = setFromList . mapMaybe f . toList - --- Possible improvements: --- - a "quote and unquote" framework for nock code generation (maybe) -copyToNock :: CExp a -> Nock -copyToNock = go \v -> error "copyToNock: free variable" - where - -- if you comment out this declaration, you get a type error! - go :: (a -> Path) -> CExp a -> Nock - go env = \case - CVar v -> N0 (toAxis $ env v) - CSef v -> N2 (N0 $ toAxis $ env v) (N0 $ toAxis $ env v) - CApp e f -> N2 (go env f) (go env e) - CAtm a -> N1 (A a) - CCel e f -> cell (go env e) (go env f) - CIsC e -> N3 (go env e) - CSuc e -> N4 (go env e) - CEql e f -> N5 (go env e) (go env f) - CIft e t f -> N6 (go env e) (go env t) (go env f) - CJet a e -> jet a (go env e) - CZap -> N0 0 - CLet e f -> N8 (go env e) (go env' f) - where - env' = \case - B () -> [L] - F v -> R : env v - CLam vs e -> lam (map (go env . CVar) vs) (go (lamEnv vs) e) - CFix vs e -> - N7 - (lam (map (go env . CVar) vs) (go (lamEnv vs) e)) - (N2 (N0 1) (N0 1)) - - lamEnv vs = if null vs - then \case - B () -> [] - F _ -> error "copyToNock: unexpected lexical" - else \case - B () -> [R] - F i -> L : posIn i (length vs) - - jet a ef = - NC - (N1 (A 11)) - (NC - (N1 - (C (A FastAtom) - (C (A 1) (A a)))) - ef) - lam vfs ef = case layOut vfs of - Nothing -> N1 (nockToNoun ef) - Just pr -> NC (N1 (A 8)) $ NC (NC (N1 (A 1)) pr) $ N1 (nockToNoun ef) - -cell :: Nock -> Nock -> Nock -cell (N1 n) (N1 m) = N1 (C n m) -cell ef ff = NC ef ff - -layOut :: [Nock] -> Maybe Nock -layOut = \case - [] -> Nothing - [x] -> Just x - xs -> Just $ NC (fromJust $ layOut l) (fromJust $ layOut r) - where - (l, r) = splitAt (length xs `div` 2) xs - -posIn :: Int -> Int -> Path -posIn 0 1 = [] -posIn i n - | i < 0 || n <= i = error ("posIn: " <> show i <> " out of bound " <> show n) - | i < mid = L : posIn i mid - | otherwise = R : posIn (i - mid) (n - mid) - where mid = n `div` 2 - --- | The proposed new calling convention -copy :: Ord a => Exp a -> Nock -copy = copyToNock . toCopy - --- | Decrements its argument. -decrement :: Exp String -decrement = lam "a" $ App (fix "f" $ lam "b" $ Ift (Eql (Var "a") (Suc (Var "b"))) (Var "b") (App (Var "f") (Suc (Var "b")))) (Atm 0) diff --git a/pkg/hs/proto/lib/Untyped/Hoon.hs b/pkg/hs/proto/lib/Untyped/Hoon.hs deleted file mode 100644 index 89254a461..000000000 --- a/pkg/hs/proto/lib/Untyped/Hoon.hs +++ /dev/null @@ -1,77 +0,0 @@ -module Untyped.Hoon where - -import ClassyPrelude - -import Bound -import Bound.Name - -import SimpleNoun -import Untyped.Core - -data Hoon a - = HVar a - | HAtom Atom - | HCons (Hoon a) (Hoon a) - | BarCen (Cases a) - | BarHep a a (Hoon a) (Hoon a) - | BarTis a (Hoon a) - | CenDot (Hoon a) (Hoon a) - | CenHep (Hoon a) (Hoon a) --- | CenKet (Hoon a) (Hoon a) (Hoon a) --- | CenTar [Hoon a] - | TisFas a (Hoon a) (Hoon a) - | DotDot a (Hoon a) - | DotLus (Hoon a) - | DotTis (Hoon a) (Hoon a) - | SigFas Atom (Hoon a) - | WutBar (Hoon a) (Hoon a) - | WutCol (Hoon a) (Hoon a) (Hoon a) - | WutHep (Hoon a) (Cases a) - | WutKet (Hoon a) (Hoon a) (Hoon a) - | WutPam (Hoon a) (Hoon a) - | WutPat (Hoon a) (Hoon a) (Hoon a) - | ZapZap - deriving (Functor) - -deriving instance Show a => Show (Hoon a) - -type Cases a = [(Pat, Hoon a)] - -data Pat - = Exact Noun - | Wild - deriving (Show) - -desugar :: Eq a => Hoon a -> Exp a -desugar = go - where - go = \case - HVar v -> Var v - HAtom a -> Atm a - HCons h j -> Cel (go h) (go j) - BarCen cs -> Lam $ Scope $ branch (Var . F . go) (Var (B ())) cs - BarHep r s i h -> go $ CenDot i $ DotDot r $ BarTis s $ h - BarTis v h -> lam v (go h) - CenDot h j -> App (go j) (go h) - CenHep h j -> App (go h) (go j) - TisFas v h j -> ledt v (go h) (go j) - DotDot v h -> fix v (go h) - DotLus h -> Suc (go h) - DotTis h j -> Eql (go h) (go j) - SigFas a h -> Jet a (go h) - WutBar h j -> Ift (go h) (Atm 0) (go j) - WutCol h j k -> Ift (go h) (go j) (go k) - -- or branch go (go h) cs - WutHep h cs -> Let (go h) $ Scope $ branch (Var . F . go) (Var (B ())) cs - WutKet h j k -> Ift (IsC (go h)) (go j) (go k) - WutPam h j -> Ift (go h) (go j) (Atm 1) - WutPat h j k -> go $ WutKet h k j - ZapZap -> Zap - -branch :: (Hoon b -> Exp a) -> Exp a -> Cases b -> Exp a -branch go e = foldr f Zap - where - f c acc = case c of - (Exact n, h) -> Ift (Eql e (con n)) (go h) acc - (Wild, h) -> go h - diff --git a/pkg/hs/proto/lib/Untyped/Parser.hs b/pkg/hs/proto/lib/Untyped/Parser.hs deleted file mode 100644 index d012d0a6f..000000000 --- a/pkg/hs/proto/lib/Untyped/Parser.hs +++ /dev/null @@ -1,341 +0,0 @@ -module Untyped.Parser where - -import ClassyPrelude hiding (head, many, some, try) -import Control.Lens -import GHC.Natural - -import Text.Megaparsec -import Text.Megaparsec.Char -import Control.Monad.State.Lazy - -import Data.List.NonEmpty (NonEmpty(..)) -import Data.Void (Void) -import Prelude (head) - -import qualified Prelude - - --- Types ----------------------------------------------------------------------- - -type Nat = Natural -type Sym = Text - - --- CST ------------------------------------------------------------------------- - -data Pat - = PatTar - | PatTag Sym - deriving (Eq, Ord, Show) - -data CST - = WutCol CST CST CST -- ?:(c t f) - | WutPat CST CST CST -- ?@(c t f) - | WutKet CST CST CST -- ?^(c t f) - | WutPam [CST] -- ?&(c cs ...) - | WutBar [CST] -- ?|(c cs ...) - | WutHep CST [(Pat, CST)] -- ?-(c p e ps es ...) - | TisFas Sym CST CST -- =/(x 3 x) - | ColHep CST CST -- :-(a b) - | ColLus CST CST CST -- :+(a b c) - | ColKet CST CST CST CST -- :^(a b c d) - | ColTar [CST] -- :*(a as ...) - | ColSig [CST] -- :~(a as ...) - | BarTis Sym CST -- |=(s h) - | BarHep Sym Sym CST CST -- |-(rec var init body) - | BarCen [(Pat, CST)] -- |% %a 3 == - | CenHep CST CST -- %- f x - | CenDot CST CST -- %. x f - | DotDot Sym CST -- .. $ f - | SigFas CST CST - | ZapZap -- !! - | Tupl [CST] -- [a b ...] - | Var Sym -- a - | Atom Nat -- 3 - | Tag Text -- %asdf - | Cord Text -- 'cord' - | Tape Text -- "tape" - | Incr CST -- .+(3) - | IncrIrr CST -- +(3) - | AppIrr CST CST -- (x y) - | IsEq CST CST -- .=(3 4) - | IsEqIrr CST CST -- =(3 4) - | Pam -- & - | Bar -- | - | Yes -- %.y - | No -- %.n - | Sig -- ~ - deriving (Eq, Ord, Show) - --- Parser Monad ---------------------------------------------------------------- - -data Mode = Wide | Tall - deriving (Eq, Ord, Show) - -type Parser = StateT Mode (Parsec Void Text) - -withLocalState :: Monad m => s -> StateT s m a -> StateT s m a -withLocalState val x = do { old <- get; put val; x <* put old } - -inWideMode :: Parser a -> Parser a -inWideMode = withLocalState Wide - -ace, pal, par :: Parser () -ace = void (char ' ') -pal = void (char '(') -par = void (char ')') - --- Simple Lexers --------------------------------------------------------------- - -gap :: Parser () -gap = choice [ char ' ' >> void (some spaceChar) - , newline >> void (many spaceChar) - ] - -whitespace :: Parser () -whitespace = ace <|> void gap - - --- Literals -------------------------------------------------------------------- - -alpha :: Parser Char -alpha = oneOf (['a'..'z'] ++ ['A'..'Z']) - -sym :: Parser Sym -sym = bucSym <|> pack <$> some alpha - where bucSym = char '$' *> pure "" - -atom :: Parser Nat -atom = do - init <- some digitChar - rest <- many (char '.' *> some digitChar) - guard True -- TODO Validate '.'s - pure (Prelude.read $ concat $ init:rest) - -nat :: Parser Nat -nat = Prelude.read <$> some digitChar - -tape :: Parser Text -tape = do - between (char '"') (char '"') $ - pack <$> many (label "tape char" (anySingleBut '"')) - -cord :: Parser Text -cord = do - between (char '\'') (char '\'') $ - pack <$> many (label "cord char" (anySingleBut '\'')) - -tag :: Parser Text -tag = try (char '%' >> sym) - -literal :: Parser CST -literal = choice - [ Yes <$ string "%.y" - , No <$ string "%.n" - , Var <$> sym - , Atom <$> atom - , Pam <$ char '&' - , Bar <$ char '|' - , Sig <$ char '~' - , Tag <$> tag - , Cord <$> cord - , Tape <$> tape - ] - - --- Rune Helpers ---------------------------------------------------------------- - -{- - - If the parser is in `Wide` mode, only accept the `wide` form. - - If the parser is in `Tall` mode, either - - accept the `tall` form or: - - swich to `Wide` mode and then accept the wide form. --} -parseRune :: Parser a -> Parser a -> Parser a -parseRune tall wide = get >>= \case - Wide -> wide - Tall -> tall <|> inWideMode wide - -rune0 :: a -> Parser a -rune0 = pure - -rune1 :: (a->b) -> Parser a -> Parser b -rune1 node x = parseRune tall wide - where tall = do gap; p<-x; pure (node p) - wide = do pal; p<-x; par; pure (node p) - -rune2 :: (a->b->c) -> Parser a -> Parser b -> Parser c -rune2 node x y = parseRune tall wide - where tall = do gap; p<-x; gap; q<-y; pure (node p q) - wide = do pal; p<-x; ace; q<-y; par; pure (node p q) - -rune3 :: (a->b->c->d) -> Parser a -> Parser b -> Parser c -> Parser d -rune3 node x y z = parseRune tall wide - where tall = do gap; p<-x; gap; q<-y; gap; r<-z; pure (node p q r) - wide = do pal; p<-x; ace; q<-y; ace; r<-z; par; pure (node p q r) - -rune4 :: (a->b->c->d->e) -> Parser a -> Parser b -> Parser c -> Parser d -> Parser e -rune4 node x y z g = parseRune tall wide - where tall = do gap; p<-x; gap; q<-y; gap; r<-z; gap; s<-g; pure (node p q r s) - wide = do pal; p<-x; ace; q<-y; ace; r<-z; ace; s<-g; pure (node p q r s) - -runeN :: ([a]->b) -> Parser a -> Parser b -runeN node elem = node <$> parseRune tall wide - where tall = gap >> elems - where elems = term <|> elemAnd - elemAnd = do x <- elem; gap; xs <- elems; pure (x:xs) - term = string "==" *> pure [] - wide = pal *> option [] elems <* par - where elems = (:) <$> elem <*> many (ace >> elem) - -runeNE :: (NonEmpty a -> b) -> Parser a -> Parser b -runeNE node elem = node <$> parseRune tall wide - where tall = do - let elems = term <|> elemAnd - elemAnd = do x <- elem; gap; xs <- elems; pure (x:xs) - term = string "==" *> pure [] - fst <- gap *> elem - rst <- gap *> elems - pure (fst :| rst) - wide = mzero -- No wide form for cores - --- Irregular Syntax ------------------------------------------------------------ - -inc :: Parser CST -- +(3) -inc = do - string "+(" - h <- cst - char ')' - pure h - -equals :: Parser (CST, CST) -- =(3 4) -equals = do - string "=(" - x <- cst - ace - y <- cst - char ')' - pure (x, y) - -tuple :: forall a. Parser a -> Parser [a] -tuple p = char '[' >> elems - where - xs :: Parser [a] - xs = do { x <- p; (x:) <$> tail } - - tail :: Parser [a] - tail = (pure [] <* char ']') - <|> (ace >> elems) - - elems :: Parser [a] - elems = (pure [] <* char ']') <|> xs - -appIrr :: Parser CST -appIrr = do - char '(' - x <- cst - char ' ' - y <- cst - char ')' - pure (AppIrr x y) - -irregular :: Parser CST -irregular = - inWideMode $ - choice [ Tupl <$> tuple cst - , IncrIrr <$> inc - , uncurry IsEqIrr <$> equals - , appIrr - ] - --- Runes ----------------------------------------------------------------------- - -pat :: Parser Pat -pat = choice [ PatTag <$> tag - , char '*' $> PatTar - ] - -cases :: Parser [(Pat, CST)] -cases = do - mode <- get - guard (mode == Tall) - end <|> lop - where - goo = lop <|> end - end = string "==" $> [] - lop = do { p <- pat; gap; b <- cst; gap; ((p,b):) <$> goo } - -wutHep :: Parser CST -wutHep = do - mode <- get - guard (mode == Tall) - gap - ex <- cst - gap - cs <- cases - pure (WutHep ex cs) - -barCen :: Parser CST -barCen = do - mode <- get - guard (mode == Tall) - gap - cs <- cases - pure (BarCen cs) - -rune :: Parser CST -rune = runeSwitch [ ("|=", rune2 BarTis sym cst) - , ("|-", rune4 BarHep sym sym cst cst) - , (":-", rune2 ColHep cst cst) - , (":+", rune3 ColLus cst cst cst) - , (":^", rune4 ColKet cst cst cst cst) - , (":*", runeN ColTar cst) - , (":~", runeN ColSig cst) - , ("%-", rune2 CenHep cst cst) - , ("%.", rune2 CenDot cst cst) - , ("..", rune2 DotDot sym cst) - , ("!!", rune0 ZapZap) - , ("?:", rune3 WutCol cst cst cst) - , ("?@", rune3 WutPat cst cst cst) - , ("?&", runeN WutPam cst) - , ("?|", runeN WutBar cst) - , ("?^", rune3 WutKet cst cst cst) - , ("=/", rune3 TisFas sym cst cst) - , (".+", rune1 Incr cst) - , (".=", rune2 IsEq cst cst) - , ("?-", wutHep) - , ("|%", barCen) - , ("~/", rune2 SigFas cst cst) - ] - -runeSwitch :: [(Text, Parser a)] -> Parser a -runeSwitch = choice . fmap (\(s, p) -> string s *> p) - - --- CST Parser ------------------------------------------------------------------ - -cst :: Parser CST -cst = irregular <|> rune <|> literal - - --- Entry Point ----------------------------------------------------------------- - -hoonFile :: StateT Mode (Parsec Void Text) CST -hoonFile = do - option () whitespace - h <- cst - option () whitespace - eof - pure h - -parse :: Text -> Either Text CST -parse txt = - runParser (evalStateT hoonFile Tall) "stdin" txt & \case - Left e -> Left (pack $ errorBundlePretty e) - Right x -> pure x - -parseHoonTest :: Text -> IO () -parseHoonTest = parseTest (evalStateT hoonFile Tall) - -main :: IO () -main = (head <$> getArgs) >>= parseHoonTest diff --git a/pkg/hs/proto/lib/Untyped/ShittyCorePrinter.hs b/pkg/hs/proto/lib/Untyped/ShittyCorePrinter.hs deleted file mode 100644 index 6f2ab7346..000000000 --- a/pkg/hs/proto/lib/Untyped/ShittyCorePrinter.hs +++ /dev/null @@ -1,24 +0,0 @@ -module Untyped.ShittyCorePrinter where - --- it's pretty clowny but whatever --- TODO: handle the new cases (maybe don't do) - -import Prelude - -import Bound -import Data.Foldable - -import Untyped.Core - -prettyPrec :: [String] -> Bool -> Int -> Exp String -> ShowS -prettyPrec _ d n (Var a) = showString a -prettyPrec vs d n (App x y) = showParen d $ - prettyPrec vs False n x . showChar ' ' . prettyPrec vs True n y -prettyPrec (v:vs) d n (Lam b) = showParen d $ - showString v . showString ". " . prettyPrec vs False n (instantiate1 (Var v) b) - -prettyWith :: [String] -> Exp String -> String -prettyWith vs t = prettyPrec (filter (`notElem` toList t) vs) False 0 t "" - -pretty :: Exp String -> String -pretty = prettyWith $ [ [i] | i <- ['a'..'z']] ++ [i : show j | j <- [1 :: Int ..], i <- ['a'..'z'] ] diff --git a/pkg/hs/proto/package.yaml b/pkg/hs/proto/package.yaml deleted file mode 100644 index bb8f9e882..000000000 --- a/pkg/hs/proto/package.yaml +++ /dev/null @@ -1,92 +0,0 @@ -name: proto -version: 0.1.0 -license: MIT -license-file: LICENSE - -dependencies: - - base - - bound - - classy-prelude - - containers - - deriving-compat - - lens - - megaparsec - - mtl - - multimap - - para - - pretty-show - - text - - transformers - - transformers-compat - - unordered-containers - - urbit-noun - -default-extensions: - - ApplicativeDo - - BangPatterns - - BlockArguments - - DeriveAnyClass - - DeriveDataTypeable - - DeriveFoldable - - DeriveGeneric - - DeriveTraversable - - DerivingStrategies - - EmptyDataDecls - - FlexibleContexts - - FlexibleInstances - - FunctionalDependencies - - GADTs - - GeneralizedNewtypeDeriving - - LambdaCase - - MultiParamTypeClasses - - NamedFieldPuns - - NoImplicitPrelude - - NumericUnderscores - - OverloadedStrings - - PartialTypeSignatures - - PatternSynonyms - - QuasiQuotes - - Rank2Types - - RankNTypes - - RecordWildCards - - ScopedTypeVariables - - StandaloneDeriving - - TemplateHaskell - - TupleSections - - TypeApplications - - TypeFamilies - - UnicodeSyntax - - ViewPatterns - -library: - source-dirs: lib - ghc-options: - - -fwarn-incomplete-patterns - - -fwarn-unused-binds - - -fwarn-unused-imports - - -Wwarn - - -O2 - -executables: - proto: - main: Main.hs - source-dirs: app - dependencies: - - proto - ghc-options: - - -threaded - - -rtsopts - - -O2 - - "-with-rtsopts=-N" - - -fwarn-incomplete-patterns - -tests: - proto-test: - main: Spec.hs - source-dirs: test - dependencies: - - proto - ghc-options: - - -threaded - - -rtsopts - - -with-rtsopts=-N diff --git a/pkg/hs/proto/test/Spec.hs b/pkg/hs/proto/test/Spec.hs deleted file mode 100644 index 92f77176d..000000000 --- a/pkg/hs/proto/test/Spec.hs +++ /dev/null @@ -1,6 +0,0 @@ -module Main where - -import ClassyPrelude - -main :: IO () -main = putStrLn "Test suite not yet implemented" diff --git a/pkg/hs/racquire/.gitignore b/pkg/hs/racquire/.gitignore deleted file mode 100644 index 65e7ea818..000000000 --- a/pkg/hs/racquire/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.stack-work -*.cabal -test/gold/*.writ diff --git a/pkg/hs/racquire/LICENSE b/pkg/hs/racquire/LICENSE deleted file mode 100644 index bf9294e05..000000000 --- a/pkg/hs/racquire/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 urbit - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/pkg/hs/racquire/lib/Data/RAcquire.hs b/pkg/hs/racquire/lib/Data/RAcquire.hs deleted file mode 100644 index 588db777f..000000000 --- a/pkg/hs/racquire/lib/Data/RAcquire.hs +++ /dev/null @@ -1,137 +0,0 @@ -{-| - RAcquire = ReaderT e Acquire a --} -module Data.RAcquire where -{- - ( RAcquire (..) - , Allocated (..) - , with - , mkRAcquire - , ReleaseType (..) - , mkRAcquireType - ) where --} - -import Prelude - -import qualified Control.Exception as E -import qualified Control.Monad.Catch as C () -import qualified Data.Acquire.Internal as Act - -import Control.Monad.IO.Unlift (MonadUnliftIO, withRunInIO) -import Control.Monad.Reader -import Data.Typeable (Typeable) - -import RIO (RIO, runRIO) - --------------------------------------------------------------------------------- - -data ReleaseType - = ReleaseEarly - | ReleaseNormal - | ReleaseException - deriving (Show, Read, Eq, Ord, Enum, Bounded, Typeable) - -data Allocated e a - = Allocated !a !(ReleaseType -> RIO e ()) - -newtype RAcquire e a - = RAcquire ((forall b. RIO e b -> RIO e b) -> RIO e (Allocated e a)) - deriving Typeable - --------------------------------------------------------------------------------- - -class MonadRIO m where - liftRIO :: RIO e a -> m e a - -instance MonadRIO RIO where - liftRIO = id - -class MonadAcquire m where - liftAcquire :: Act.Acquire a -> m a - --------------------------------------------------------------------------------- - -instance Functor (RAcquire e) where - fmap = liftM - -instance Applicative (RAcquire e) where - pure a = RAcquire (\_ -> return (Allocated a (const $ return ()))) - (<*>) = ap - -instance Monad (RAcquire e) where - return = pure - RAcquire f >>= g' = RAcquire $ \restore -> do - env <- ask - Allocated x free1 <- f restore - let RAcquire g = g' x - Allocated y free2 <- liftIO $ E.onException - (runRIO env $ g restore) - (runRIO env $ free1 ReleaseException) - - return $! Allocated y $ \rt -> - liftIO $ E.finally (runRIO env $ free2 rt) - (runRIO env $ free1 rt) - -instance MonadReader e (RAcquire e) where - ask = liftRIO ask - local mod (RAcquire f) = RAcquire $ \restore -> local mod (f restore) - --------------------------------------------------------------------------------- - -instance MonadRIO RAcquire where - liftRIO f = RAcquire $ \restore -> do - x <- restore f - return $! Allocated x (const $ return ()) - -instance MonadIO (RAcquire e) where - liftIO = liftRIO . liftIO - -unTransRIO :: e -> (RIO e a -> RIO e a) -> IO a -> IO a -unTransRIO env trans act = runRIO env $ trans $ liftIO act - -instance MonadAcquire (RAcquire e) where - liftAcquire (Act.Acquire f) = do - env <- liftRIO ask - RAcquire $ \restore -> do - fmap fixAllo $ liftIO $ f $ unTransRIO env restore - where - fixAllo (Act.Allocated x y) = Allocated x $ fmap liftIO (y . fixTy) - - fixTy = \case - ReleaseEarly -> Act.ReleaseEarly - ReleaseNormal -> Act.ReleaseNormal - ReleaseException -> Act.ReleaseException - --------------------------------------------------------------------------------- - -mkRAcquire :: RIO e a - -> (a -> RIO e ()) - -> RAcquire e a -mkRAcquire create free = RAcquire $ \restore -> do - x <- restore create - return $! Allocated x (const $ free x) - -mkRAcquireType - :: RIO e a -- ^ acquire the resource - -> (a -> ReleaseType -> RIO e ()) -- ^ free the resource - -> RAcquire e a -mkRAcquireType create free = RAcquire $ \restore -> do - x <- restore create - return $! Allocated x (free x) - -transRIO :: e -> (IO a -> IO a) -> RIO e a -> RIO e a -transRIO env trans act = liftIO $ trans $ runRIO env act - -rwith :: (MonadUnliftIO (m e), MonadReader e (m e)) - => RAcquire e a - -> (a -> m e b) - -> m e b -rwith (RAcquire f) g = do - env <- ask - withRunInIO $ \run -> E.mask $ \restore -> do - Allocated x free <- runRIO env $ f $ transRIO env restore - res <- E.onException (restore $ run $ g x) - (runRIO env $ free ReleaseException) - runRIO env $ free ReleaseNormal - return res diff --git a/pkg/hs/racquire/package.yaml b/pkg/hs/racquire/package.yaml deleted file mode 100644 index bbaca592c..000000000 --- a/pkg/hs/racquire/package.yaml +++ /dev/null @@ -1,67 +0,0 @@ -name: racquire -version: 0.10.4 -license: MIT -license-file: LICENSE - -library: - source-dirs: lib - ghc-options: - - -Wall - - -Werror - - -Wno-type-defaults - - -Wno-unused-matches - - -Wno-name-shadowing - - -O2 - -dependencies: - - base - - mtl - - unliftio-core - - resourcet - - exceptions - - rio - -default-extensions: - - ApplicativeDo - - BangPatterns - - BlockArguments - - ConstraintKinds - - DataKinds - - DefaultSignatures - - DeriveAnyClass - - DeriveDataTypeable - - DeriveFoldable - - DeriveGeneric - - DeriveTraversable - - DerivingStrategies - - EmptyCase - - EmptyDataDecls - - FlexibleContexts - - FlexibleInstances - - FunctionalDependencies - - GADTs - - GeneralizedNewtypeDeriving - - LambdaCase - - MagicHash - - MultiParamTypeClasses - - NamedFieldPuns - - NoImplicitPrelude - - NumericUnderscores - - OverloadedStrings - - PackageImports - - PartialTypeSignatures - - PatternSynonyms - - QuasiQuotes - - Rank2Types - - RankNTypes - - RecordWildCards - - ScopedTypeVariables - - StandaloneDeriving - - TemplateHaskell - - TupleSections - - TypeApplications - - TypeFamilies - - TypeOperators - - UnboxedTuples - - UnicodeSyntax - - ViewPatterns diff --git a/pkg/hs/stack.yaml b/pkg/hs/stack.yaml deleted file mode 100644 index f9077a35d..000000000 --- a/pkg/hs/stack.yaml +++ /dev/null @@ -1,30 +0,0 @@ -resolver: lts-16.15 - -packages: - - natpmp-static - - racquire - - terminal-progress-bar - - urbit-atom - - urbit-azimuth - - urbit-eventlog-lmdb - - urbit-king - - urbit-termsize - - urbit-noun - - urbit-noun-core - -extra-deps: - - base58-bytestring-0.1.0@sha256:a1da72ee89d5450bac1c792d9fcbe95ed7154ab7246f2172b57bd4fd9b5eab79 - - lock-file-0.7.0.0@sha256:3ad84b5e454145e1d928063b56abb96db24a99a21b493989520e58fa0ab37b00 - - para-1.1@sha256:a90eebb063ad70271e6e2a7f00a93e8e8f8b77273f100f39852fbf8301926f81 - - web3-0.9.1.0@sha256:6b7faac0b63e7d0aae46588dd9a42e11f54ce0fdf4c2744bdf4cc6c5cbf39aa2 - - vinyl-0.12.3@sha256:66553fc71cabfa86837bf5f98558e3e6d1807c47af5f5f1cd758081d3fb023ea - -# This allows building on NixOS. -nix: - packages: - - pkgconfig - - zlib - -# TODO: Why is this here? -ghc-options: - urbit-king: '-optP-Wno-nonportable-include-path' diff --git a/pkg/hs/terminal-progress-bar/LICENSE b/pkg/hs/terminal-progress-bar/LICENSE deleted file mode 120000 index ea5b60640..000000000 --- a/pkg/hs/terminal-progress-bar/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE \ No newline at end of file diff --git a/pkg/hs/terminal-progress-bar/README.markdown b/pkg/hs/terminal-progress-bar/README.markdown deleted file mode 120000 index 1691050d1..000000000 --- a/pkg/hs/terminal-progress-bar/README.markdown +++ /dev/null @@ -1 +0,0 @@ -../README.markdown \ No newline at end of file diff --git a/pkg/hs/terminal-progress-bar/Setup.hs b/pkg/hs/terminal-progress-bar/Setup.hs deleted file mode 100644 index 9a994af67..000000000 --- a/pkg/hs/terminal-progress-bar/Setup.hs +++ /dev/null @@ -1,2 +0,0 @@ -import Distribution.Simple -main = defaultMain diff --git a/pkg/hs/terminal-progress-bar/bench/bench.hs b/pkg/hs/terminal-progress-bar/bench/bench.hs deleted file mode 100644 index 9f00ac6bb..000000000 --- a/pkg/hs/terminal-progress-bar/bench/bench.hs +++ /dev/null @@ -1,51 +0,0 @@ -{-# language PackageImports #-} -module Main where - -import "base" Data.Monoid ( (<>) ) -import "criterion" Criterion.Main -import "terminal-progress-bar" System.ProgressBar -import "time" Data.Time.Clock ( UTCTime(..) ) - -main :: IO () -main = defaultMain - [ renderProgressBarBenchmark 10 0 - , renderProgressBarBenchmark 10 50 - , renderProgressBarBenchmark 10 100 - , renderProgressBarBenchmark 100 0 - , renderProgressBarBenchmark 100 50 - , renderProgressBarBenchmark 100 100 - , renderProgressBarBenchmark 200 0 - , renderProgressBarBenchmark 200 50 - , renderProgressBarBenchmark 200 100 - , labelBenchmark "percentage" percentage (Progress 0 100 ()) - , labelBenchmark "percentage" percentage (Progress 50 100 ()) - , labelBenchmark "percentage" percentage (Progress 100 100 ()) - , labelBenchmark "exact" exact (Progress 0 100 ()) - , labelBenchmark "exact" exact (Progress 50 100 ()) - , labelBenchmark "exact" exact (Progress 100 100 ()) - ] - -renderProgressBarBenchmark :: Int -> Int -> Benchmark -renderProgressBarBenchmark width done = - bench name $ nf (\(s, p, t) -> renderProgressBar s p t) - ( defStyle{styleWidth = ConstantWidth width} - , Progress done 100 () - , someTiming - ) - where - name = "progressBar/default - " - <> show width <> " wide - progress " <> show done <> " % 100" - -labelBenchmark :: String -> Label () -> Progress () -> Benchmark -labelBenchmark labelName label progress = - bench name $ nf (\(p, t) -> runLabel label p t) (progress, someTiming) - where - name = "label/" <> labelName <> " " - <> show (progressDone progress) <> " % " - <> show (progressTodo progress) - -someTime :: UTCTime -someTime = UTCTime (toEnum 0) 0 - -someTiming :: Timing -someTiming = Timing someTime someTime diff --git a/pkg/hs/terminal-progress-bar/changelog.md b/pkg/hs/terminal-progress-bar/changelog.md deleted file mode 120000 index 7b91ffb65..000000000 --- a/pkg/hs/terminal-progress-bar/changelog.md +++ /dev/null @@ -1 +0,0 @@ -../changelog.md \ No newline at end of file diff --git a/pkg/hs/terminal-progress-bar/src/System/ProgressBar.hs b/pkg/hs/terminal-progress-bar/src/System/ProgressBar.hs deleted file mode 100644 index a568443c6..000000000 --- a/pkg/hs/terminal-progress-bar/src/System/ProgressBar.hs +++ /dev/null @@ -1,716 +0,0 @@ -{-# language DeriveGeneric #-} -{-# language GeneralizedNewtypeDeriving #-} -{-# language OverloadedStrings #-} -{-# language PackageImports #-} -{-# language ScopedTypeVariables #-} - -{- | -A progress bar in the terminal. - -A progress bar conveys the progress of a task. Use a progress bar to -provide a visual cue that processing is underway. --} -module System.ProgressBar - ( -- * Getting started - -- $start - - -- * Example - -- $example - - -- * Progress bars - ProgressBar - , newProgressBar - , killProgressBar - , hNewProgressBar - , renderProgressBar - , updateProgress - , incProgress - -- * Options - , Style(..) - , EscapeCode - , OnComplete(..) - , defStyle - , ProgressBarWidth(..) - -- * Progress - , Progress(..) - -- * Labels - , Label(..) - , Timing(..) - , msg - , percentage - , exact - , elapsedTime - , remainingTime - , totalTime - , renderDuration - ) where - -import "base" Control.Monad ( when ) -import "base" Data.Int ( Int64 ) -import "base" Data.Monoid ( Monoid, mempty ) -import "base" Data.Ratio ( Ratio, (%) ) -import "base" Data.Semigroup ( Semigroup, (<>) ) -import "base" Data.String ( IsString, fromString ) -import "base" GHC.Generics ( Generic ) -import "deepseq" Control.DeepSeq ( NFData, rnf ) -import qualified "terminal-size" System.Console.Terminal.Size as TS -import qualified "text" Data.Text.Lazy as TL -import qualified "text" Data.Text.Lazy.Builder as TLB -import qualified "text" Data.Text.Lazy.Builder.Int as TLB -import "time" Data.Time.Clock ( UTCTime, NominalDiffTime, diffUTCTime, getCurrentTime ) - -import ClassyPrelude (liftIO, MVar, newMVar, modifyMVar_) - -import RIO (logSticky, logStickyDone, HasLogFunc, RIO, display) - --------------------------------------------------------------------------------- - --- | A terminal progress bar. --- --- A 'ProgressBar' value contains the state of a progress bar. --- --- Create a progress bar with 'newProgressBar' or 'hNewProgressBar'. --- Update a progress bar with 'updateProgress' or 'incProgress'. -data ProgressBar s - = ProgressBar - { pbStyle :: !(Style s) - , pbStateMv :: !(MVar (State s)) - , pbRefreshDelay :: !Double - , pbStartTime :: !UTCTime - } - -instance (NFData s) => NFData (ProgressBar s) where - rnf pb = pbStyle pb - `seq` pbStateMv pb - `seq` pbRefreshDelay pb - `seq` pbStartTime pb - `seq` () - --- | State of a progress bar. -data State s - = State - { stProgress :: !(Progress s) - -- ^ Current progress. - , stRenderTime :: !UTCTime - -- ^ Moment in time of last render. - } - --- | An amount of progress. -data Progress s - = Progress - { progressDone :: !Int - -- ^ Amount of work completed. - , progressTodo :: !Int - -- ^ Total amount of work. - , progressCustom :: !s - -- ^ A value which is used by custom labels. The builtin labels - -- do not care about this field. You can ignore it by using the - -- unit value '()'. - } - -progressFinished :: Progress s -> Bool -progressFinished p = progressDone p >= progressTodo p - --- | Creates a progress bar. --- --- The progress bar is drawn immediately. Update the progress bar with --- 'updateProgress' or 'incProgress'. Do not output anything to your --- terminal between updates. It will mess up the animation. --- --- The progress bar is written to 'stderr'. Write to another handle --- with 'hNewProgressBar'. -newProgressBar - :: HasLogFunc e - => Style s -- ^ Visual style of the progress bar. - -> Double -- ^ Maximum refresh rate in Hertz. - -> Progress s -- ^ Initial progress. - -> RIO e (ProgressBar s) -newProgressBar = hNewProgressBar - --- | Creates a progress bar which outputs to the given handle. --- --- See 'newProgressBar'. -hNewProgressBar - :: HasLogFunc e - => Style s -- ^ Visual style of the progress bar. - -> Double -- ^ Maximum refresh rate in Hertz. - -> Progress s -- ^ Initial progress. - -> RIO e (ProgressBar s) -hNewProgressBar style maxRefreshRate initProgress = do - style' <- updateWidth style - - startTime <- liftIO getCurrentTime - hPutProgressBar style' initProgress (Timing startTime startTime) - - stateMv <- newMVar - State - { stProgress = initProgress - , stRenderTime = startTime - } - pure ProgressBar - { pbStyle = style' - , pbStateMv = stateMv - , pbRefreshDelay = recip maxRefreshRate - , pbStartTime = startTime - } - --- | Update the width based on the current terminal. -updateWidth :: Style s -> RIO e (Style s) -updateWidth style = - case styleWidth style of - ConstantWidth {} -> pure style - TerminalWidth {} -> do - mbWindow <- liftIO TS.size - pure $ case mbWindow of - Nothing -> style - Just window -> style{ styleWidth = TerminalWidth (TS.width window) } - --- | Change the progress of a progress bar. --- --- This function is thread safe. Multiple threads may update a single --- progress bar at the same time. --- --- There is a maximum refresh rate. This means that some updates might not be drawn. -updateProgress - :: forall s e - . HasLogFunc e - => ProgressBar s -- ^ Progress bar to update. - -> (Progress s -> Progress s) -- ^ Function to change the progress. - -> RIO e () -updateProgress progressBar f = do - updateTime <- liftIO getCurrentTime - modifyMVar_ (pbStateMv progressBar) $ renderAndUpdate updateTime - where - renderAndUpdate :: UTCTime -> State s -> RIO e (State s) - renderAndUpdate updateTime state = do - when shouldRender $ - hPutProgressBar (pbStyle progressBar) newProgress timing - pure State - { stProgress = newProgress - , stRenderTime = if shouldRender then updateTime else stRenderTime state - } - where - timing = Timing - { timingStart = pbStartTime progressBar - , timingLastUpdate = updateTime - } - - shouldRender = not tooFast || finished - tooFast = secSinceLastRender <= pbRefreshDelay progressBar - finished = progressFinished newProgress - - newProgress = f $ stProgress state - - -- Amount of time that passed since last render, in seconds. - secSinceLastRender :: Double - secSinceLastRender = realToFrac $ diffUTCTime updateTime (stRenderTime state) - --- | Increment the progress of an existing progress bar. --- --- See 'updateProgress' for more information. -incProgress - :: HasLogFunc e - => ProgressBar s -- ^ Progress bar which needs an update. - -> Int -- ^ Amount by which to increment the progress. - -> RIO e () -incProgress pb n = updateProgress pb $ \p -> p{ progressDone = progressDone p + n } - -killProgressBar :: HasLogFunc e => ProgressBar s -> RIO e () -killProgressBar _ = pure () - -hPutProgressBar :: HasLogFunc e => Style s -> Progress s -> Timing -> RIO e () -hPutProgressBar style progress timing = do - let barStr = (display (renderProgressBar style progress timing)) - logSticky barStr - when (progressFinished progress) $ do - logStickyDone barStr - --- | Renders a progress bar. --- --- >>> let t = UTCTime (ModifiedJulianDay 0) 0 --- >>> renderProgressBar defStyle (Progress 30 100 ()) (Timing t t) --- "[============>..............................] 30%" --- --- Note that this function can not use 'TerminalWidth' because it --- doesn't use 'IO'. Use 'newProgressBar' or 'hNewProgressBar' to get --- automatic width. -renderProgressBar - :: Style s - -> Progress s -- ^ Current progress. - -> Timing -- ^ Timing information. - -> TL.Text -- ^ Textual representation of the 'Progress' in the given 'Style'. -renderProgressBar style progress timing = TL.concat - [ styleEscapePrefix style progress - , prefixLabel - , prefixPad - , styleEscapeOpen style progress - , styleOpen style - , styleEscapeDone style progress - , TL.replicate completed $ TL.singleton $ styleDone style - , styleEscapeCurrent style progress - , if remaining /= 0 && completed /= 0 - then TL.singleton $ styleCurrent style - else "" - , styleEscapeTodo style progress - , TL.replicate - (remaining - if completed /= 0 then 1 else 0) - (TL.singleton $ styleTodo style) - , styleEscapeClose style progress - , styleClose style - , styleEscapePostfix style progress - , postfixPad - , postfixLabel - ] - where - todo = fromIntegral $ progressTodo progress - done = fromIntegral $ progressDone progress - -- Amount of (visible) characters that should be used to display to progress bar. - width = fromIntegral $ getProgressBarWidth $ styleWidth style - - -- Amount of work completed. - fraction :: Ratio Int64 - fraction | todo /= 0 = done % todo - | otherwise = 0 % 1 - - -- Amount of characters available to visualize the progress. - effectiveWidth = max 0 $ width - usedSpace - -- Amount of printing characters needed to visualize everything except the bar . - usedSpace = TL.length (styleOpen style) - + TL.length (styleClose style) - + TL.length prefixLabel - + TL.length postfixLabel - + TL.length prefixPad - + TL.length postfixPad - - -- Number of characters needed to represent the amount of work - -- that is completed. Note that this can not always be represented - -- by an integer. - numCompletedChars :: Ratio Int64 - numCompletedChars = fraction * (effectiveWidth % 1) - - completed, remaining :: Int64 - completed = min effectiveWidth $ floor numCompletedChars - remaining = effectiveWidth - completed - - prefixLabel, postfixLabel :: TL.Text - prefixLabel = runLabel (stylePrefix style) progress timing - postfixLabel = runLabel (stylePostfix style) progress timing - - prefixPad, postfixPad :: TL.Text - prefixPad = pad prefixLabel - postfixPad = pad postfixLabel - -pad :: TL.Text -> TL.Text -pad s | TL.null s = TL.empty - | otherwise = TL.singleton ' ' - --- | Width of progress bar in characters. -data ProgressBarWidth - = ConstantWidth !Int - -- ^ A constant width. - | TerminalWidth !Int - -- ^ Use the entire width of the terminal. - -- - -- Identical to 'ConstantWidth' if the width of the terminal can - -- not be determined. - deriving (Generic) - -instance NFData ProgressBarWidth - -getProgressBarWidth :: ProgressBarWidth -> Int -getProgressBarWidth (ConstantWidth n) = n -getProgressBarWidth (TerminalWidth n) = n - -{- | Visual style of a progress bar. - -The style determines how a progress bar is rendered to text. - -The textual representation of a progress bar follows the following template: - -\<__prefix__>\<__open__>\<__done__>\<__current__>\<__todo__>\<__close__>\<__postfix__> - -Where \<__done__> and \<__todo__> are repeated as often as necessary. - -Consider the following progress bar - -> "Working [=======>.................] 30%" - -This bar can be specified using the following style: - -@ -'Style' -{ 'styleOpen' = \"[" -, 'styleClose' = \"]" -, 'styleDone' = \'=' -, 'styleCurrent' = \'>' -, 'styleTodo' = \'.' -, 'stylePrefix' = 'msg' \"Working" -, 'stylePostfix' = 'percentage' -, 'styleWidth' = 'ConstantWidth' 40 -, 'styleEscapeOpen' = const 'TL.empty' -, 'styleEscapeClose' = const 'TL.empty' -, 'styleEscapeDone' = const 'TL.empty' -, 'styleEscapeCurrent' = const 'TL.empty' -, 'styleEscapeTodo' = const 'TL.empty' -, 'styleEscapePrefix' = const 'TL.empty' -, 'styleEscapePostfix' = const 'TL.empty' -, 'styleOnComplete' = 'WriteNewline' -} -@ --} -data Style s - = Style - { styleOpen :: !TL.Text - -- ^ Bar opening symbol. - , styleClose :: !TL.Text - -- ^ Bar closing symbol - , styleDone :: !Char - -- ^ Completed work. - , styleCurrent :: !Char - -- ^ Symbol used to denote the current amount of work that has been done. - , styleTodo :: !Char - -- ^ Work not yet completed. - , stylePrefix :: Label s - -- ^ Prefixed label. - , stylePostfix :: Label s - -- ^ Postfixed label. - , styleWidth :: !ProgressBarWidth - -- ^ Total width of the progress bar. - , styleEscapeOpen :: EscapeCode s - -- ^ Escape code printed just before the 'styleOpen' symbol. - , styleEscapeClose :: EscapeCode s - -- ^ Escape code printed just before the 'styleClose' symbol. - , styleEscapeDone :: EscapeCode s - -- ^ Escape code printed just before the first 'styleDone' character. - , styleEscapeCurrent :: EscapeCode s - -- ^ Escape code printed just before the 'styleCurrent' character. - , styleEscapeTodo :: EscapeCode s - -- ^ Escape code printed just before the first 'styleTodo' character. - , styleEscapePrefix :: EscapeCode s - -- ^ Escape code printed just before the 'stylePrefix' label. - , styleEscapePostfix :: EscapeCode s - -- ^ Escape code printed just before the 'stylePostfix' label. - , styleOnComplete :: !OnComplete - -- ^ What happens when progress is finished. - } deriving (Generic) - -instance (NFData s) => NFData (Style s) - --- | An escape code is a sequence of bytes which the terminal looks --- for and interprets as commands, not as character codes. --- --- It is vital that the output of this function, when send to the --- terminal, does not result in characters being drawn. -type EscapeCode s - = Progress s -- ^ Current progress bar state. - -> TL.Text -- ^ Resulting escape code. Must be non-printable. - --- | What happens when a progress bar is finished. -data OnComplete - = WriteNewline - -- ^ Write a new line when the progress bar is finished. The - -- completed progress bar will remain visible. - | Clear -- ^ Clear the progress bar once it is finished. - deriving (Generic) - -instance NFData OnComplete - --- | The default style. --- --- This style shows the progress as a percentage. It does not use any --- escape sequences. --- --- Override some fields of the default instead of specifying all the --- fields of a 'Style' record. -defStyle :: Style s -defStyle = - Style - { styleOpen = "[" - , styleClose = "]" - , styleDone = '=' - , styleCurrent = '>' - , styleTodo = '.' - , stylePrefix = mempty - , stylePostfix = percentage - , styleWidth = TerminalWidth 50 - , styleEscapeOpen = const TL.empty - , styleEscapeClose = const TL.empty - , styleEscapeDone = const TL.empty - , styleEscapeCurrent = const TL.empty - , styleEscapeTodo = const TL.empty - , styleEscapePrefix = const TL.empty - , styleEscapePostfix = const TL.empty - , styleOnComplete = WriteNewline - } - --- | A label is a part of a progress bar that changes based on the progress. --- --- Labels can be at the front (prefix) or at the back (postfix) of a progress bar. --- --- Labels can use both the current amount of progress and the timing --- information to generate some text. -newtype Label s = Label{ runLabel :: Progress s -> Timing -> TL.Text } deriving (NFData) - --- | Combining labels combines their output. -instance Semigroup (Label s) where - Label f <> Label g = Label $ \p t -> f p t <> g p t - --- | The mempty label always outputs an empty text. -instance Monoid (Label s) where - mempty = msg TL.empty - mappend = (<>) - --- | Every string is a label which ignores its input and just outputs --- that string. -instance IsString (Label s) where - fromString = msg . TL.pack - --- | Timing information about a 'ProgressBar'. --- --- This information is used by 'Label's to calculate elapsed time, remaining time, total time, etc. --- --- See 'elapsedTime', 'remainingTime' and 'totalTime'. -data Timing - = Timing - { timingStart :: !UTCTime - -- ^ Moment in time when a progress bar was created. See - -- 'newProgressBar'. - , timingLastUpdate :: !UTCTime - -- ^ Moment in time of the most recent progress update. - } - --- | Static text. --- --- The output does not depend on the input. --- --- >>> msg "foo" st --- "foo" -msg :: TL.Text -> Label s -msg s = Label $ \_ _ -> s - --- | Progress as a percentage. --- --- >>> runLabel $ percentage (Progress 30 100 ()) someTiming --- " 30%" --- --- __Note__: if no work is to be done (todo == 0) the percentage will --- be shown as 100%. -percentage :: Label s -percentage = Label render - where - render progress _timing - | todo == 0 = "100%" - | otherwise = TL.justifyRight 4 ' ' $ TLB.toLazyText $ - TLB.decimal (round (done % todo * 100) :: Int) - <> TLB.singleton '%' - where - done = progressDone progress - todo = progressTodo progress - --- | Progress as a fraction of the total amount of work. --- --- >>> runLabel $ exact (Progress 30 100 ()) someTiming --- " 30/100" -exact :: Label s -exact = Label render - where - render progress _timing = - TL.justifyRight (TL.length todoStr) ' ' doneStr <> "/" <> todoStr - where - todoStr = TLB.toLazyText $ TLB.decimal todo - doneStr = TLB.toLazyText $ TLB.decimal done - - done = progressDone progress - todo = progressTodo progress - --- | Amount of time that has elapsed. --- --- Time starts when a progress bar is created. --- --- The user must supply a function which actually renders the amount --- of time that has elapsed. You can use 'renderDuration' or --- @formatTime@ from time >= 1.9. -elapsedTime - :: (NominalDiffTime -> TL.Text) - -> Label s -elapsedTime formatNDT = Label render - where - render _progress timing = formatNDT dt - where - dt :: NominalDiffTime - dt = diffUTCTime (timingLastUpdate timing) (timingStart timing) - --- | Estimated remaining time. --- --- Tells you how much longer some task is expected to take. --- --- This label uses a simple estimation algorithm. It assumes progress --- is linear. To prevent nonsense results it won't estimate remaining --- time until at least 1 second of work has been done. --- --- When it refuses to estimate the remaining time it will show an --- alternative message instead. --- --- The user must supply a function which actually renders the amount --- of time that has elapsed. Use 'renderDuration' or @formatTime@ from --- the time >= 1.9 package. -remainingTime - :: (NominalDiffTime -> TL.Text) - -> TL.Text - -- ^ Alternative message when remaining time can't be - -- calculated (yet). - -> Label s -remainingTime formatNDT altMsg = Label render - where - render progress timing - | dt > 1 = formatNDT estimatedRemainingTime - | progressDone progress <= 0 = altMsg - | otherwise = altMsg - where - estimatedRemainingTime = estimatedTotalTime - dt - estimatedTotalTime = dt * recip progressFraction - - progressFraction :: NominalDiffTime - progressFraction - | progressTodo progress <= 0 = 1 - | otherwise = fromIntegral (progressDone progress) - / fromIntegral (progressTodo progress) - - dt :: NominalDiffTime - dt = diffUTCTime (timingLastUpdate timing) (timingStart timing) - --- | Estimated total time. --- --- This label uses a simple estimation algorithm. It assumes progress --- is linear. To prevent nonsense results it won't estimate the total --- time until at least 1 second of work has been done. --- --- When it refuses to estimate the total time it will show an --- alternative message instead. --- --- The user must supply a function which actually renders the total --- amount of time that a task will take. You can use 'renderDuration' --- or @formatTime@ from the time >= 1.9 package. -totalTime - :: (NominalDiffTime -> TL.Text) - -> TL.Text - -- ^ Alternative message when total time can't be calculated - -- (yet). - -> Label s -totalTime formatNDT altMsg = Label render - where - render progress timing - | dt > 1 = formatNDT estimatedTotalTime - | progressDone progress <= 0 = altMsg - | otherwise = altMsg - where - estimatedTotalTime = dt * recip progressFraction - - progressFraction :: NominalDiffTime - progressFraction - | progressTodo progress <= 0 = 1 - | otherwise = fromIntegral (progressDone progress) - / fromIntegral (progressTodo progress) - - dt :: NominalDiffTime - dt = diffUTCTime (timingLastUpdate timing) (timingStart timing) - --- | Show amount of time. --- --- > renderDuration (fromInteger 42) --- 42 --- --- > renderDuration (fromInteger $ 5 * 60 + 42) --- 05:42 --- --- > renderDuration (fromInteger $ 8 * 60 * 60 + 5 * 60 + 42) --- 08:05:42 --- --- Use the time >= 1.9 package to get a formatTime function which --- accepts 'NominalDiffTime'. -renderDuration :: NominalDiffTime -> TL.Text -renderDuration dt = hTxt <> mTxt <> sTxt - where - hTxt | h == 0 = mempty - | otherwise = renderDecimal h <> ":" - mTxt | m == 0 = mempty - | otherwise = renderDecimal m <> ":" - sTxt = renderDecimal s - - (h, hRem) = ts `quotRem` 3600 - (m, s ) = hRem `quotRem` 60 - - -- Total amount of seconds - ts :: Int - ts = round dt - - renderDecimal n = TL.justifyRight 2 '0' $ TLB.toLazyText $ TLB.decimal n - -{- $start - -You want to perform some task which will take some time. You wish to -show the progress of this task in the terminal. - - 1. Determine the total amount of work - - 2. Create a progress bar with 'newProgressBar' - - 3. For each unit of work: - - 3a. Perform the work - - 3b. Update the progress bar with 'incProgress' - -Explore the 'Style' and the 'Label' types to see various ways in which -you can customize the progress bar. - -You do not have to close the progress bar, or even finish the task. It -is perfectly fine to stop half way (maybe your task throws an -exception). - -Just remember to avoid outputting text to the terminal while a -progress bar is active. It will mess up the output a bit. --} - -{- $example - -Write a function which represents a unit of work. This could be a file -copy operation, a network operation or some other expensive -calculation. This example simply waits 1 second. - -@ - work :: IO () - work = threadDelay 1000000 -- 1 second -@ - -And you define some work to be done. This could be a list of files to -process or some jobs that need to be processed. - -@ - toBeDone :: [()] - toBeDone = replicate 20 () -@ - -Now create the progress bar. Use the default style and choose a -maximum refresh rate of 10 Hz. The initial progress is 0 work done out -of 20. - -@ - pb <- 'newProgressBar' 'defStyle' 10 ('Progress' 0 20 ()) -@ - -Start performing the work while keeping the user informed of the progress: - -@ - for_ toBeDone $ \() -> do - work -- perform 1 unit of work - 'incProgress' pb 1 -- increment progress by 1 -@ - -That's it! You get a nice animated progress bar in your terminal. It -will look like this: - -@ -[==========>................................] 25% -@ --} diff --git a/pkg/hs/terminal-progress-bar/terminal-progress-bar.cabal b/pkg/hs/terminal-progress-bar/terminal-progress-bar.cabal deleted file mode 100644 index 25edd4d2b..000000000 --- a/pkg/hs/terminal-progress-bar/terminal-progress-bar.cabal +++ /dev/null @@ -1,72 +0,0 @@ -name: terminal-progress-bar -version: 0.4.1 -cabal-version: >=1.10 -build-type: Simple -author: Roel van Dijk -maintainer: Roel van Dijk -copyright: 2012–2019 Roel van Dijk -license: BSD3 --- ense-file: LICENSE -category: System, User Interfaces -homepage: https://github.com/roelvandijk/terminal-progress-bar -bug-reports: https://github.com/roelvandijk/terminal-progress-bar/issues -synopsis: A progress bar in the terminal -description: - A progress bar conveys the progress of a task. This package - implements a progress bar that is displayed in a terminal. - . - See the module 'System.ProgressBar' to get started or look at the - terminal-progress-bar-example package. - . - The animated progress bar depends entirely on the interpretation of - the carriage return character (\'\\r\'). If your terminal interprets - it as something else than \"move cursor to beginning of line\", the - animation won't work. - --- ra-source-files: LICENSE, README.markdown, changelog.md - -source-repository head - type: git - location: git://github.com/roelvandijk/terminal-progress-bar.git - -library - hs-source-dirs: src - build-depends: - base >= 4.5 && < 5 - , deepseq >= 1.4.3 - , terminal-size >= 0.3.2 - , text >= 1.2 - , time >= 1.8 - , rio - , classy-prelude - exposed-modules: System.ProgressBar - ghc-options: -Wall - default-language: Haskell2010 - -test-suite test-terminal-progress-bar - type: exitcode-stdio-1.0 - main-is: test.hs - hs-source-dirs: test - ghc-options: -Wall - build-depends: - base >= 4.5 && < 5 - , HUnit >= 1.2.4.2 - , terminal-progress-bar - , test-framework >= 0.3.3 - , test-framework-hunit >= 0.2.6 - , text >= 1.2 - , time >= 1.8 - default-language: Haskell2010 - -benchmark bench-terminal-progress-bar - type: exitcode-stdio-1.0 - main-is: bench.hs - hs-source-dirs: bench - - build-depends: - base >= 4.5 && < 5 - , criterion >= 1.1.4 - , terminal-progress-bar - , time >= 1.8 - ghc-options: -Wall -O2 - default-language: Haskell2010 diff --git a/pkg/hs/terminal-progress-bar/test/test.hs b/pkg/hs/terminal-progress-bar/test/test.hs deleted file mode 100644 index 1cb2c9810..000000000 --- a/pkg/hs/terminal-progress-bar/test/test.hs +++ /dev/null @@ -1,102 +0,0 @@ -{-# language OverloadedStrings #-} -{-# language PackageImports #-} - -module Main where - --------------------------------------------------------------------------------- --- Imports --------------------------------------------------------------------------------- - -import "base" System.Environment ( getArgs ) -import "base" Data.Semigroup ( (<>) ) -import "HUnit" Test.HUnit.Base ( assertEqual ) -import "test-framework" Test.Framework - ( defaultMainWithOpts, interpretArgsOrExit, Test, testGroup ) -import "test-framework-hunit" Test.Framework.Providers.HUnit ( testCase ) -import "terminal-progress-bar" System.ProgressBar -import qualified "text" Data.Text.Lazy as TL -import "time" Data.Time.Clock ( UTCTime(..), NominalDiffTime ) - --------------------------------------------------------------------------------- --- Test suite --------------------------------------------------------------------------------- - -main :: IO () -main = do opts <- interpretArgsOrExit =<< getArgs - defaultMainWithOpts tests opts - -tests :: [Test] -tests = - [ testGroup "Label padding" - [ eqTest "no labels" "[]" mempty mempty 0 $ Progress 0 0 () - , eqTest "pre" "pre []" (msg "pre") mempty 0 $ Progress 0 0 () - , eqTest "post" "[] post" mempty (msg "post") 0 $ Progress 0 0 () - , eqTest "pre & post" "pre [] post" (msg "pre") (msg "post") 0 $ Progress 0 0 () - ] - , testGroup "Bar fill" - [ eqTest "empty" "[....]" mempty mempty 6 $ Progress 0 1 () - , eqTest "almost half" "[=>..]" mempty mempty 6 $ Progress 49 100 () - , eqTest "half" "[==>.]" mempty mempty 6 $ Progress 1 2 () - , eqTest "almost full" "[===>]" mempty mempty 6 $ Progress 99 100 () - , eqTest "full" "[====]" mempty mempty 6 $ Progress 1 1 () - , eqTest "overfull" "[====]" mempty mempty 6 $ Progress 2 1 () - ] - , testGroup "Labels" - [ testGroup "Percentage" - [ eqTest " 0%" " 0% [....]" percentage mempty 11 $ Progress 0 1 () - , eqTest "100%" "100% [====]" percentage mempty 11 $ Progress 1 1 () - , eqTest " 50%" " 50% [==>.]" percentage mempty 11 $ Progress 1 2 () - , eqTest "200%" "200% [====]" percentage mempty 11 $ Progress 2 1 () - , labelTest "0 work todo" percentage (Progress 10 0 ()) "100%" - ] - , testGroup "Exact" - [ eqTest "0/0" "0/0 [....]" exact mempty 10 $ Progress 0 0 () - , eqTest "1/1" "1/1 [====]" exact mempty 10 $ Progress 1 1 () - , eqTest "1/2" "1/2 [==>.]" exact mempty 10 $ Progress 1 2 () - , eqTest "2/1" "2/1 [====]" exact mempty 10 $ Progress 2 1 () - , labelTest "0 work todo" exact (Progress 10 0 ()) "10/0" - ] - , testGroup "Label Semigroup" - [ eqTest "exact <> msg <> percentage" - "1/2 - 50% [===>...]" - (exact <> msg " - " <> percentage) - mempty 20 $ Progress 1 2 () - ] - , testGroup "rendeRuration" - [ renderDurationTest 42 "42" - , renderDurationTest (5 * 60 + 42) "05:42" - , renderDurationTest (8 * 60 * 60 + 5 * 60 + 42) "08:05:42" - , renderDurationTest (123 * 60 * 60 + 59 * 60 + 59) "123:59:59" - ] - ] - ] - -labelTest :: String -> Label () -> Progress () -> TL.Text -> Test -labelTest testName label progress expected = - testCase testName $ assertEqual expectationError expected $ runLabel label progress someTiming - -renderDurationTest :: NominalDiffTime -> TL.Text -> Test -renderDurationTest dt expected = - testCase ("renderDuration " <> show dt) $ assertEqual expectationError expected $ renderDuration dt - -eqTest :: String -> TL.Text -> Label () -> Label () -> Int -> Progress () -> Test -eqTest name expected mkPreLabel mkPostLabel width progress = - testCase name $ assertEqual expectationError expected actual - where - actual = renderProgressBar style progress someTiming - - style :: Style () - style = defStyle - { stylePrefix = mkPreLabel - , stylePostfix = mkPostLabel - , styleWidth = ConstantWidth width - } - -someTime :: UTCTime -someTime = UTCTime (toEnum 0) 0 - -someTiming :: Timing -someTiming = Timing someTime someTime - -expectationError :: String -expectationError = "Expected result doesn't match actual result" diff --git a/pkg/hs/urbit-atom/.gitignore b/pkg/hs/urbit-atom/.gitignore deleted file mode 100644 index 088be03c6..000000000 --- a/pkg/hs/urbit-atom/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -urbit-atom.cabal -dist-newstyle/ diff --git a/pkg/hs/urbit-atom/LICENSE b/pkg/hs/urbit-atom/LICENSE deleted file mode 100644 index bf9294e05..000000000 --- a/pkg/hs/urbit-atom/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 urbit - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/pkg/hs/urbit-atom/TODO.md b/pkg/hs/urbit-atom/TODO.md deleted file mode 100644 index c0d8369c9..000000000 --- a/pkg/hs/urbit-atom/TODO.md +++ /dev/null @@ -1,5 +0,0 @@ -- Support big-endian CPUs (CPP flag; use GMP import/export) -- Support `integer-simple`. (Android) -- `atomWords` and `wordsAtom` are unacceptably slow on GHCJS. - - This is only used in `jam`/`cue`, so it doesn't matter for now. -- Understand why my hand rolled import is slower than GMP import. diff --git a/pkg/hs/urbit-atom/bench/Main.hs b/pkg/hs/urbit-atom/bench/Main.hs deleted file mode 100644 index c4fbd225b..000000000 --- a/pkg/hs/urbit-atom/bench/Main.hs +++ /dev/null @@ -1,54 +0,0 @@ -{-# OPTIONS_GHC -Wno-missing-signatures #-} - -module Main (main) where - -import Prelude -import Criterion.Main - -import Data.ByteString (ByteString) -import Urbit.Atom (Atom) - -import qualified Urbit.Atom.Fast as Fast -import qualified Urbit.Atom.Slow as Slow - - --- Examples -------------------------------------------------------------------- - -a64, a32768 :: Atom -a64 = (2^64) - 1 -a32768 = (2^32768)-1 - -bDog, bBigDog :: ByteString -bDog = "The quick brown fox jumps over the lazy dog." -bBigDog = mconcat (replicate 800 bDog) - - --- Benchmarks ------------------------------------------------------------------ - -maiDump = Fast.atomBytes -maiLoad = Fast.bytesAtom -sloDump = Slow.atomBytes -sloLoad = Slow.bytesAtom -gmpDump = Fast.exportBytes -gmpLoad = Fast.importBytes - -main = defaultMain - [ bgroup "lit-dump" [ bench "slo" $ whnf sloDump a64 - , bench "gmp" $ whnf gmpDump a64 - , bench "mai" $ whnf maiDump a64 - ] - - , bgroup "big-dump" [ bench "gmp" $ whnf gmpDump a32768 - , bench "mai" $ whnf maiDump a32768 - ] - - , bgroup "lit-load" [ bench "slo" $ whnf sloLoad bDog - , bench "gmp" $ whnf gmpLoad bDog - , bench "mai" $ whnf maiLoad bDog - ] - - , bgroup "big-load" [ bench "gmp" $ whnf gmpLoad bBigDog - , bench "mai" $ whnf maiLoad bBigDog - ] - ] - diff --git a/pkg/hs/urbit-atom/lib/Urbit/Atom.hs b/pkg/hs/urbit-atom/lib/Urbit/Atom.hs deleted file mode 100644 index d640c2d7c..000000000 --- a/pkg/hs/urbit-atom/lib/Urbit/Atom.hs +++ /dev/null @@ -1,117 +0,0 @@ -{-# LANGUAGE CPP #-} - -{-| - Atom implementation with fast conversions between bytestrings - and atoms. --} - -module Urbit.Atom - ( Atom - , atomBytes - , bytesAtom - , atomWords - , wordsAtom - , utf8Atom - , atomUtf8 - , atomUtf8Exn - , atomUtf8Lenient - ) -where - -import Prelude - -import Data.ByteString (ByteString) -import Data.Vector.Primitive (Vector) -import GHC.Natural (Natural) - -import qualified Data.Text as T -import qualified Data.Text.Encoding as T -import qualified Data.Text.Encoding.Error as T - -#if defined(__GHCJS__) -import qualified Urbit.Atom.Slow as Slow -#endif - -import qualified Urbit.Atom.Fast as A - - --------------------------------------------------------------------------------- - -type Atom = Natural - - --- Choose Implementation Based on Platform ------------------------------------- - -{- | - Convert an Atom to a bytestring. O(n), copies. - - My hand-rolled implementation is faster, but doesn't work on GHCJS. So, - on GHCJS use GMP's `export` routine. - - TODO GMP's `export` routine also handles big endian machines, so use - in that case too. --} -atomBytes :: Atom -> ByteString -atomBytes = -#if defined(__GHCJS__) - A.exportBytes -#else - A.atomBytes -#endif - -{- | - Convert a bytestring to an Atom. O(n), copies. - - This always uses GMP's `export` routine, since it's portable and faster - than my hand-rolled implementation. --} -bytesAtom :: ByteString -> Atom -bytesAtom = A.importBytes - -{- | - Cast an atom to a vector. O(1), does not copy. - - My fast implementation doesn't work on GHCJS, so fallback to the naive - implementation on that platform for now. --} -atomWords :: Atom -> Vector Word -atomWords = -#if defined(__GHCJS__) - Slow.atomWords -#else - A.atomWords -#endif - -{- | - Cast a vector to an atom. O(1), does not copy unless given a slice, - then O(n). - - My fast implementation doesn't work on GHCJS, so fallback to the naive - implementation on that platform for now. --} -wordsAtom :: Vector Word -> Atom -wordsAtom = -#if defined(__GHCJS__) - Slow.wordsAtom -#else - A.wordsAtom -#endif - - --- String/Cord Conversion ------------------------------------------------------ - --- | Encode a utf8-encoded atom from text. -utf8Atom :: T.Text -> Atom -utf8Atom = bytesAtom . T.encodeUtf8 - --- | Interpret an atom as utf8 text. -atomUtf8 :: Atom -> Either T.UnicodeException T.Text -atomUtf8 = T.decodeUtf8' . atomBytes - --- | Interpret an atom as utf8 text, throwing an exception on bad unicode. -atomUtf8Exn :: Atom -> T.Text -atomUtf8Exn = T.decodeUtf8 . atomBytes - --- | Interpret an atom as utf8 text, replacing bad unicode characters. -atomUtf8Lenient :: Atom -> T.Text -atomUtf8Lenient = T.decodeUtf8With T.lenientDecode . atomBytes diff --git a/pkg/hs/urbit-atom/lib/Urbit/Atom/Fast.hs b/pkg/hs/urbit-atom/lib/Urbit/Atom/Fast.hs deleted file mode 100644 index 45ce36479..000000000 --- a/pkg/hs/urbit-atom/lib/Urbit/Atom/Fast.hs +++ /dev/null @@ -1,339 +0,0 @@ -{-# LANGUAGE CPP, UnliftedFFITypes #-} - -{-| - Atom implementation with fast conversions between bytestrings - and atoms. - - TODO Support Big Endian. --} - -module Urbit.Atom.Fast - ( wordsAtom - , bytesAtom - , atomBytes - , atomWords - , exportBytes - , importBytes - , wordBitWidth# - , wordBitWidth - , atomBitWidth# - , atomBitWidth - , takeBitsWord - , bigNatWords - , wordsBigNat - , bit - , byt - ) -where - -import Prelude - -import Control.Monad.Primitive (primitive_) -import Data.Bits (shiftL, shiftR, (.&.), (.|.)) -import Data.ByteString (ByteString) -import Data.Vector.Primitive (Vector(..)) -import Data.Word (Word8) -import GHC.Exts (Ptr(Ptr), sizeofByteArray#) -import GHC.Exts (Int(..)) -import GHC.Integer.GMP.Internals (BigNat(..)) -import GHC.Natural (Natural(..)) -import GHC.Prim (Int#, clz#, minusWord#, plusWord#) -import GHC.Prim (Word#, Addr#, int2Word#, timesWord#) -import GHC.Prim (copyByteArrayToAddr#) -import GHC.Word (Word(..)) -import System.IO.Unsafe (unsafePerformIO) - -import qualified Data.ByteString as BS -import qualified Data.ByteString.Internal as BS -import qualified Data.ByteString.Unsafe as BS -import qualified Data.Primitive.ByteArray as Prim -import qualified Data.Vector.Primitive as VP -import qualified Foreign.ForeignPtr as Ptr -import qualified Foreign.ForeignPtr.Unsafe as Ptr -import qualified GHC.Integer.GMP.Internals as G - - --- Setup BIT and BYT macros. --------------------------------------------------- - -#include - -#if WORD_SIZE_IN_BITS == 64 -#define BIT 64 -#define BYT 8 -#elif WORD_SIZE_IN_BITS == 32 -#define BIT 32 -#define BYT 4 -#else -#error WORD_SIZE_IN_BITS must be either 32 or 64 -#endif - -bit :: Word -bit = BIT - -byt :: Word -byt = BYT - - --------------------------------------------------------------------------------- - -wordBitWidth# :: Word# -> Word# -wordBitWidth# w = minusWord# BIT## (clz# w) - -wordBitWidth :: Word -> Word -wordBitWidth (W# w) = W# (wordBitWidth# w) - -bigNatBitWidth# :: BigNat -> Word# -bigNatBitWidth# nat = - lswBits `plusWord#` ((int2Word# lastIdx) `timesWord#` BIT##) - where - I# lastIdx = (I# (G.sizeofBigNat# nat)) - 1 - lswBits = wordBitWidth# (G.indexBigNat# nat lastIdx) - -atomBitWidth# :: Natural -> Word# -atomBitWidth# (NatS# gl) = wordBitWidth# gl -atomBitWidth# (NatJ# bn) = bigNatBitWidth# bn - -atomBitWidth :: Num a => Natural -> a -atomBitWidth a = fromIntegral (W# (atomBitWidth# a)) - --------------------------------------------------------------------------------- - -{-# INLINE takeBitsWord #-} -takeBitsWord :: Int -> Word -> Word -takeBitsWord wid wor = wor .&. (shiftL 1 wid - 1) - - --------------------------------------------------------------------------------- - -{- - A `Pill` is a bytestring without trailing zeros. --} -newtype Pill = Pill { unPill :: ByteString } - -instance Eq Pill where - (==) x y = pillBytes x == pillBytes y - -instance Show Pill where - show = show . pillBytes - - --------------------------------------------------------------------------------- - -strip :: ByteString -> ByteString -strip buf = BS.take (len - go 0 (len - 1)) buf - where - len = BS.length buf - go n i | i < 0 = n - | 0 == BS.unsafeIndex buf i = go (n + 1) (i - 1) - | otherwise = n - -pillBytes :: Pill -> ByteString -pillBytes = strip . unPill - -bytesPill :: ByteString -> Pill -bytesPill = Pill . strip - - --------------------------------------------------------------------------------- - -{- - Cast a BigNat to a vector without a copy. --} -bigNatWords :: BigNat -> Vector Word -bigNatWords bn | G.isZeroBigNat bn = mempty -bigNatWords bn@(BN# bArr) = - Vector 0 (I# (sizeofByteArray# bArr) `div` BYT) (Prim.ByteArray bArr) - -{-| - Cast a vector to a BigNat. This will not copy. - - TODO Don't crash if given a slice. --} -wordsBigNat :: Vector Word -> BigNat -wordsBigNat v@(Vector off (I# len) (Prim.ByteArray buf)) = case VP.length v of - 0 -> G.zeroBigNat - 1 -> case VP.unsafeIndex v 0 of - W# w -> G.wordToBigNat w - n -> if off /= 0 - then error "words2Nat: bad-vec" - else G.byteArrayToBigNat# buf len - -{-| - More careful version of `wordsBigNat`, but not yet tested. - - Cast a vector to a BigNat. This will not copy unless input is a slice. - - Note that the length of the vector is in words, and the length passed - to `byteArrayToBigNat#` is also in words. --} -_wordsBigNat :: Vector Word -> BigNat -_wordsBigNat v = case VP.length v of - 0 -> G.zeroBigNat - 1 -> G.wordToBigNat w where W# w = VP.unsafeIndex v 0 - n -> if offset v == 0 then extract v else extract (VP.force v) - where - offset (Vector off _ _) = off - - extract (Vector _ (I# len) (Prim.ByteArray buf)) = - G.byteArrayToBigNat# buf len - - --------------------------------------------------------------------------------- - --- | Cast a nat to a vector (no copy) -atomWords :: Natural -> Vector Word -atomWords = bigNatWords . natBigNat - --- | Cast a vector to a nat (no copy) -wordsAtom :: Vector Word -> Natural -wordsAtom = bigNatNat . wordsBigNat - --- | Cast a Nat to a BigNat (no copy). -natBigNat :: Natural -> BigNat -natBigNat (NatS# w ) = G.wordToBigNat w -natBigNat (NatJ# bn) = bn - --- | Cast a BigNat to a Nat (no copy). -bigNatNat :: BigNat -> Natural -bigNatNat bn = case G.sizeofBigNat# bn of - 0# -> 0 - 1# -> NatS# (G.bigNatToWord bn) - _ -> NatJ# bn - - --------------------------------------------------------------------------------- - -_wordBytes :: Word -> ByteString -_wordBytes wor = BS.reverse $ BS.pack $ go 0 [] - where - go i acc | i >= BYT = acc - go i acc | otherwise = go (i + 1) (fromIntegral (shiftR wor (i * BYT)) : acc) - -bytesFirstWord :: ByteString -> Word -bytesFirstWord buf = go 0 0 - where - top = min BYT (BS.length buf) - i idx off = shiftL (fromIntegral $ BS.index buf idx) off - go acc idx = - if idx >= top then acc else go (acc .|. i idx (BYT * idx)) (idx + 1) - - --------------------------------------------------------------------------------- - -_pillWords :: Pill -> Vector Word -_pillWords = bsToWords . pillBytes - -wordsPill :: Vector Word -> Pill -wordsPill = bytesPill . vecBytes . wordsToBytes - - --------------------------------------------------------------------------------- - -wordsToBytes :: Vector Word -> Vector Word8 -wordsToBytes (Vector off sz buf) = Vector (off * BYT) (sz * BYT) buf - -bsToWords :: ByteString -> Vector Word -bsToWords bs = VP.generate (1 + BS.length bs `div` BYT) - $ \i -> bytesFirstWord (BS.drop (i * BYT) bs) - - --------------------------------------------------------------------------------- - -vecBytes :: Vector Word8 -> ByteString -vecBytes (Vector off sz buf) = unsafePerformIO $ do - fp <- BS.mallocByteString sz - let Ptr a = Ptr.unsafeForeignPtrToPtr fp -- Safe b/c returning fp - copyByteArrayToAddr a buf 0 sz - pure (BS.PS fp off sz) - where - unI# :: Int -> Int# - unI# (I# n#) = n# - - -- Hack to get GHCJS build working, since it has an old version of the - -- `primitive` library. - copyByteArrayToAddr dst# (Prim.ByteArray src#) soff sz = - primitive_ (copyByteArrayToAddr# src# (unI# soff) dst# (unI# sz)) - -_bytesVec :: ByteString -> Vector Word8 -_bytesVec bs = VP.generate (BS.length bs) (BS.index bs) - - --------------------------------------------------------------------------------- - -natPill :: Natural -> Pill -natPill = wordsPill . atomWords - -pillAtom :: Pill -> Natural -pillAtom = wordsAtom . bsToWords . pillBytes - --- | Dump an atom to a bytestring. -atomBytes :: Natural -> ByteString -atomBytes = pillBytes . natPill - --- | Load a bytestring into an atom. -bytesAtom :: ByteString -> Natural -bytesAtom = pillAtom . bytesPill - --- Try using GMPs `input/export` feature. -------------------------------------- - --- sizeInBaseInteger i 256# --- sz = sizeInBaseNatural wor 256# --- exportBigNatToAddr :: BigNat -> Addr# -> Int# -> IO Word Source# --- exportWordToAddr :: Word -> Addr# -> Int# -> IO Word - --- Use "sizeInBaseInteger i 256#" to compute the exact number --- of bytes written in advance for i /= 0. In case of i == 0, --- exportIntegerToMutableByteArray will write and report zero bytes written, --- whereas sizeInBaseInteger report one byte. - -sizeInBaseNatural :: Natural -> Int# -> Word# -{-# INLINE sizeInBaseNatural #-} -sizeInBaseNatural (NatS# w) base = G.sizeInBaseWord# w base -sizeInBaseNatural (NatJ# n) base = G.sizeInBaseBigNat n base - -exportNaturalToAddr :: Natural -> Addr# -> Int# -> IO Word -exportNaturalToAddr (NatS# w) = G.exportWordToAddr (W# w) -exportNaturalToAddr (NatJ# n) = G.exportBigNatToAddr n - -exportNaturalToByteString :: Natural -> Int -> ByteString -exportNaturalToByteString nat (I# i#) = unsafePerformIO $ do - let sz# = sizeInBaseNatural nat 256# - let szi = fromIntegral (W# sz#) - fp <- BS.mallocByteString szi - let Ptr a = Ptr.unsafeForeignPtrToPtr fp - exportNaturalToAddr nat a i# - pure (BS.PS fp 0 szi) - -exportBytes :: Natural -> ByteString -exportBytes 0 = mempty -exportBytes n = exportNaturalToByteString n 0 - -bigNatNatural :: BigNat -> Natural -bigNatNatural big = - case G.sizeofBigNat# big of - 0# -> 0 - 1# -> NatS# (G.bigNatToWord big) - _ -> NatJ# big - -stripBytes :: ByteString -> ByteString -stripBytes buf = BS.take (len - go 0 (len - 1)) buf - where - len = BS.length buf - go n i | i < 0 = n - | 0 == BS.unsafeIndex buf i = go (n + 1) (i - 1) - | otherwise = n - - -importBytes :: ByteString -> Natural -importBytes = go . stripBytes - where - go (BS.PS fp 0 sz) = unsafePerformIO $ do - let Ptr a = Ptr.unsafeForeignPtrToPtr fp -- TODO Not safe! - let W# sz# = fromIntegral sz - res <- bigNatNatural <$> G.importBigNatFromAddr a sz# 0# - Ptr.touchForeignPtr fp - pure res - - -- TODO Avoid this extra copy when given a slice. Should be able to - -- just offset the raw pointer. - go bs = importBytes (BS.copy bs) diff --git a/pkg/hs/urbit-atom/lib/Urbit/Atom/Slow.hs b/pkg/hs/urbit-atom/lib/Urbit/Atom/Slow.hs deleted file mode 100644 index 0740c3d6c..000000000 --- a/pkg/hs/urbit-atom/lib/Urbit/Atom/Slow.hs +++ /dev/null @@ -1,85 +0,0 @@ -{-# LANGUAGE CPP #-} - -module Urbit.Atom.Slow - ( wordsAtom - , atomWords - , atomBytes - , bytesAtom - , bit - , byt - ) -where - -import Numeric.Natural -import Prelude -import Data.Bits hiding (bit) -import Data.Word - -import Data.ByteString (ByteString) -import Data.Vector.Primitive (Vector) - -import qualified Data.ByteString as BS -import qualified Data.Vector.Primitive as VP - - --- Setup BIT and BYT macros. --------------------------------------------------- - -#include - -#if WORD_SIZE_IN_BITS == 64 -#define BIT 64 -#define BYT 8 -#elif WORD_SIZE_IN_BITS == 32 -#define BIT 32 -#define BYT 4 -#else -#error WORD_SIZE_IN_BITS must be either 32 or 64 -#endif - -bit :: Word -bit = BIT - -byt :: Word -byt = BYT - - --------------------------------------------------------------------------------- - -{-| - Natural number to LSB-ByteString. --} -atomBytes :: Natural -> ByteString -atomBytes = BS.pack . go [] - where - go acc 0 = reverse acc - go acc n = go (fromIntegral n : acc) (shiftR n 8) - -{-| - LSB-first ByteString to Natural number. --} -bytesAtom :: ByteString -> Natural -bytesAtom = BS.foldr' go 0 - where - go :: Word8 -> Natural -> Natural - go byt acc = shiftL acc 8 .|. fromIntegral byt - - --------------------------------------------------------------------------------- - -{-| - LSW-first Word Vector to Natural number. --} -wordsAtom :: Vector Word -> Natural -wordsAtom = VP.foldr' go 0 - where - go :: Word -> Natural -> Natural - go wor acc = shiftL acc BIT .|. fromIntegral wor - -{-| - Natural number to LSW-first Word Vector. --} -atomWords :: Natural -> Vector Word -atomWords = VP.fromList . go [] - where - go acc 0 = reverse acc - go acc n = go (fromIntegral n : acc) (shiftR n BIT) diff --git a/pkg/hs/urbit-atom/package.yaml b/pkg/hs/urbit-atom/package.yaml deleted file mode 100644 index 088da5055..000000000 --- a/pkg/hs/urbit-atom/package.yaml +++ /dev/null @@ -1,92 +0,0 @@ -name: urbit-atom -version: 0.10.1 -license: MIT -license-file: LICENSE - -ghc-options: - - -Wall - - -Werror - - -Wno-type-defaults - - -Wno-unused-matches - - -Wno-name-shadowing - - -Wno-unbanged-strict-patterns - - -O2 - -library: - source-dirs: lib - dependencies: - - base - - bytestring - - ghc-prim - - integer-gmp - - primitive - - text - - vector - -tests: - urbit-atom-tests: - source-dirs: test - main: Main.hs - ghc-options: "-threaded -rtsopts -with-rtsopts=-N" - dependencies: - - base - - bytestring - - QuickCheck - - text - - urbit-atom - - vector - -benchmarks: - urbit-atom-bench: - source-dirs: bench - main: Main.hs - ghc-options: "-threaded -rtsopts -with-rtsopts=-N" - dependencies: - - base - - bytestring - - criterion - - urbit-atom - -default-extensions: - - ApplicativeDo - - BangPatterns - - BlockArguments - - DataKinds - - DefaultSignatures - - DeriveAnyClass - - DeriveDataTypeable - - DeriveFoldable - - DeriveGeneric - - DeriveTraversable - - DerivingStrategies - - EmptyCase - - EmptyDataDecls - - FlexibleContexts - - FlexibleInstances - - FunctionalDependencies - - GADTs - - GeneralizedNewtypeDeriving - - LambdaCase - - MagicHash - - MultiParamTypeClasses - - NamedFieldPuns - - NoImplicitPrelude - - NumericUnderscores - - OverloadedStrings - - PackageImports - - PartialTypeSignatures - - PatternSynonyms - - QuasiQuotes - - Rank2Types - - RankNTypes - - RecordWildCards - - ScopedTypeVariables - - StandaloneDeriving - - TemplateHaskell - - TupleSections - - TypeApplications - - TypeFamilies - - TypeOperators - - UnboxedTuples - - UnicodeSyntax - - ViewPatterns diff --git a/pkg/hs/urbit-atom/test/Main.hs b/pkg/hs/urbit-atom/test/Main.hs deleted file mode 100644 index 0ba9611cc..000000000 --- a/pkg/hs/urbit-atom/test/Main.hs +++ /dev/null @@ -1,183 +0,0 @@ -{-# OPTIONS_GHC -Wno-deprecations -Wno-orphans #-} - - -module Main (main) where - --------------------------------------------------------------------------------- - -import Data.IORef -import Numeric.Natural -import Prelude -import System.Exit -import System.IO.Unsafe -import Test.QuickCheck - -import Control.Monad (when) -import Data.ByteString (ByteString) -import Data.Vector.Primitive (Prim, Vector) - -import qualified Data.ByteString as BS -import qualified Data.ByteString.Unsafe as BS -import qualified Data.Vector.Primitive as VP -import qualified Urbit.Atom.Fast as F -import qualified Urbit.Atom.Slow as S - - --- Instances ------------------------------------------------------------------- - -instance Arbitrary Natural where - arbitrary = fromInteger . abs <$> arbitrary - -instance Arbitrary ByteString where - arbitrary = BS.pack <$> arbitrary - -instance (Prim a, Arbitrary a) => Arbitrary (Vector a) where - arbitrary = VP.fromList <$> arbitrary - - --- Utils ----------------------------------------------------------------------- - -stripBytes :: ByteString -> ByteString -stripBytes buf = BS.take (len - go 0 (len - 1)) buf - where - len = BS.length buf - go n i | i < 0 = n - | 0 == BS.unsafeIndex buf i = go (n + 1) (i - 1) - | otherwise = n - -stripWords :: Vector Word -> Vector Word -stripWords vec = VP.take (len - go 0 (len - 1)) vec - where - len = VP.length vec - go n i | i < 0 = n - | 0 == VP.unsafeIndex vec i = go (n + 1) (i - 1) - | otherwise = n - -dumpLoad :: Eq i => (i -> o) -> (o -> i) -> (i -> Bool) -dumpLoad dump load x = x == load (dump x) - -loadDump :: Eq o => (o -> i) -> (i -> o) -> (o -> o) -> (o -> Bool) -loadDump load dump norm x = norm x == dump (load x) - - --- Test Reference Implementation ----------------------------------------------- - -prop_atom_bytes_roundtrip :: Natural -> Bool -prop_atom_bytes_roundtrip = dumpLoad S.atomBytes S.bytesAtom - -prop_atom_words_roundtrip :: Natural -> Bool -prop_atom_words_roundtrip = dumpLoad S.atomWords S.wordsAtom - -prop_bytes_atom_roundtrip :: ByteString -> Bool -prop_bytes_atom_roundtrip = loadDump S.bytesAtom S.atomBytes stripBytes - -prop_words_atom_roundtrip :: Vector Word -> Bool -prop_words_atom_roundtrip = loadDump S.wordsAtom S.atomWords stripWords - - --- Test Fast Implementation ---------------------------------------------------- - -prop_fast_atom_bytes_roundtrip :: Natural -> Bool -prop_fast_atom_bytes_roundtrip = dumpLoad F.atomBytes F.bytesAtom - -prop_fast_atom_words_roundtrip :: Natural -> Bool -prop_fast_atom_words_roundtrip = dumpLoad F.atomWords F.wordsAtom - -prop_fast_bytes_atom_roundtrip :: ByteString -> Bool -prop_fast_bytes_atom_roundtrip = loadDump F.bytesAtom F.atomBytes stripBytes - -prop_fast_words_atom_roundtrip :: Vector Word -> Bool -prop_fast_words_atom_roundtrip = loadDump F.wordsAtom F.atomWords stripWords - - --- Fast and Reference Implementations are the Same ----------------------------- - -prop_fast_words_atom_correct :: Vector Word -> Bool -prop_fast_words_atom_correct x = F.wordsAtom x == S.wordsAtom x - -prop_fast_atom_words_correct :: Natural -> Bool -prop_fast_atom_words_correct x = F.atomWords x == S.atomWords x - -prop_fast_bytes_atom_correct :: ByteString -> Bool -prop_fast_bytes_atom_correct x = F.bytesAtom x == S.bytesAtom x - -prop_fast_atom_import_correct :: ByteString -> Bool -prop_fast_atom_import_correct x = F.importBytes x == S.bytesAtom x - -prop_fast_atom_bytes_correct :: Natural -> Bool -prop_fast_atom_bytes_correct x = F.atomBytes x == S.atomBytes x - -prop_fast_atom_export_correct :: Natural -> Bool -prop_fast_atom_export_correct x = F.exportBytes x == S.atomBytes x - - --------------------------------------------------------------------------------- - -failed :: IORef Int -failed = unsafePerformIO (newIORef 0) - -checkProp :: Testable prop => String -> prop -> IO () -checkProp nm chk = do - putStrLn nm - res <- quickCheckResult chk - putStrLn "" - - case res of - Success{} -> pure () - _ -> modifyIORef' failed succ - -main :: IO () -main = do - checkProp "Reference: Atom <-> ByteString roundtrip" - prop_atom_bytes_roundtrip - - checkProp "Reference: Atom <-> Vector Word roundtrip" - prop_atom_words_roundtrip - - checkProp "Reference: ByteString <-> Atom roundtrip" - prop_bytes_atom_roundtrip - - checkProp "Reference: Vector Word <-> Atom roundtrip" - prop_words_atom_roundtrip - - checkProp "Fast: Atom <-> ByteString roundtrip" - prop_fast_atom_bytes_roundtrip - - checkProp "Fast: Atom <-> Vector Word roundtrip" - prop_fast_atom_words_roundtrip - - checkProp "Fast: Bytestring <-> Atom roundtrip" - prop_fast_bytes_atom_roundtrip - - checkProp "Fast: Export->Import roundtrip" $ do - withMaxSuccess 100000 (dumpLoad F.exportBytes F.importBytes) - - checkProp "Fast: Import->Export roundtrip" $ do - withMaxSuccess 10000 (loadDump F.importBytes F.exportBytes stripBytes) - - checkProp "Fast: Vector Word <-> Atom roundtrip" - prop_fast_words_atom_roundtrip - - checkProp "Fast matches reference: Vector Words -> Atom" - (withMaxSuccess 10000 prop_fast_words_atom_correct) - - checkProp "Fast matches reference: Atom -> Vector Word" - (withMaxSuccess 10000 prop_fast_atom_words_correct) - - checkProp "Fast matches reference: ByteString -> Atom" - (withMaxSuccess 10000 prop_fast_bytes_atom_correct) - - checkProp "Fast matches reference: Atom -> ByteString" - (withMaxSuccess 10000 prop_fast_atom_bytes_correct) - - checkProp "Fast matches reference: Atom Import" - (withMaxSuccess 10000 prop_fast_atom_import_correct) - - checkProp "Fast matches reference: Atom Export" - (withMaxSuccess 10000 prop_fast_atom_export_correct) - - res <- readIORef failed - when (res /= 0) $ do - putStrLn $ "FAILURE: " <> show res <> " tests failed." - exitWith (ExitFailure 1) - putStrLn $ "SUCCESS: All tests passed" diff --git a/pkg/hs/urbit-azimuth/.gitignore b/pkg/hs/urbit-azimuth/.gitignore deleted file mode 100644 index 36cb56803..000000000 --- a/pkg/hs/urbit-azimuth/.gitignore +++ /dev/null @@ -1 +0,0 @@ -urbit-azimuth.cabal diff --git a/pkg/hs/urbit-azimuth/LICENSE b/pkg/hs/urbit-azimuth/LICENSE deleted file mode 100644 index bf9294e05..000000000 --- a/pkg/hs/urbit-azimuth/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 urbit - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/pkg/hs/urbit-azimuth/Urbit/Azimuth.hs b/pkg/hs/urbit-azimuth/Urbit/Azimuth.hs deleted file mode 100644 index 5cf653601..000000000 --- a/pkg/hs/urbit-azimuth/Urbit/Azimuth.hs +++ /dev/null @@ -1,5 +0,0 @@ -module Urbit.Azimuth where - -import Network.Ethereum.Contract.TH - -[abiFrom|azimuth.json|] diff --git a/pkg/hs/urbit-azimuth/azimuth.json b/pkg/hs/urbit-azimuth/azimuth.json deleted file mode 100644 index 148d1925c..000000000 --- a/pkg/hs/urbit-azimuth/azimuth.json +++ /dev/null @@ -1 +0,0 @@ -[{"constant":true,"inputs":[{"name":"","type":"uint32"},{"name":"","type":"uint32"}],"name":"escapeRequestsIndexes","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_whose","type":"address"}],"name":"getOwnedPoints","outputs":[{"name":"ownedPoints","type":"uint32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"votingFor","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint32"}],"name":"rights","outputs":[{"name":"owner","type":"address"},{"name":"managementProxy","type":"address"},{"name":"spawnProxy","type":"address"},{"name":"votingProxy","type":"address"},{"name":"transferProxy","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"transferringFor","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"},{"name":"_sponsor","type":"uint32"}],"name":"isSponsor","outputs":[{"name":"result","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"getManagementProxy","outputs":[{"name":"manager","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"getContinuityNumber","outputs":[{"name":"continuityNumber","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint32"},{"name":"","type":"uint256"}],"name":"sponsoring","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_whose","type":"address"}],"name":"getOwnedPointCount","outputs":[{"name":"count","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_point","type":"uint32"}],"name":"doEscape","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_whose","type":"address"},{"name":"_index","type":"uint256"}],"name":"getOwnedPointAtIndex","outputs":[{"name":"point","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"getTransferProxy","outputs":[{"name":"transferProxy","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"},{"name":"_proxy","type":"address"}],"name":"isSpawnProxy","outputs":[{"name":"result","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"pointsOwnedBy","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"operators","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"getSpawnCount","outputs":[{"name":"spawnCount","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_point","type":"uint32"},{"name":"_proxy","type":"address"}],"name":"setSpawnProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_point","type":"uint32"},{"name":"_proxy","type":"address"}],"name":"setTransferProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint32"},{"name":"","type":"uint32"}],"name":"sponsoringIndexes","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"},{"name":"_proxy","type":"address"}],"name":"isTransferProxy","outputs":[{"name":"result","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"getVotingProxy","outputs":[{"name":"voter","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"},{"name":"_proxy","type":"address"}],"name":"isManagementProxy","outputs":[{"name":"result","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint32"}],"name":"votingForIndexes","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"isLive","outputs":[{"name":"result","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_sponsor","type":"uint32"}],"name":"getEscapeRequests","outputs":[{"name":"requests","type":"uint32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"getSponsor","outputs":[{"name":"sponsor","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_sponsor","type":"uint32"}],"name":"getEscapeRequestsCount","outputs":[{"name":"count","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint32"}],"name":"pointOwnerIndexes","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_proxy","type":"address"}],"name":"getManagerFor","outputs":[{"name":"mfor","type":"uint32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint32"}],"name":"managerForIndexes","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"managerFor","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"isActive","outputs":[{"name":"equals","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"getOwner","outputs":[{"name":"owner","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint32"}],"name":"points","outputs":[{"name":"encryptionKey","type":"bytes32"},{"name":"authenticationKey","type":"bytes32"},{"name":"hasSponsor","type":"bool"},{"name":"active","type":"bool"},{"name":"escapeRequested","type":"bool"},{"name":"sponsor","type":"uint32"},{"name":"escapeRequestedTo","type":"uint32"},{"name":"cryptoSuiteVersion","type":"uint32"},{"name":"keyRevisionNumber","type":"uint32"},{"name":"continuityNumber","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_proxy","type":"address"}],"name":"getSpawningForCount","outputs":[{"name":"count","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"hasBeenLinked","outputs":[{"name":"result","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"},{"name":"_who","type":"address"}],"name":"canTransfer","outputs":[{"name":"result","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint32"}],"name":"spawningForIndexes","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"hasSponsor","outputs":[{"name":"has","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_point","type":"uint32"}],"name":"activatePoint","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"getSpawned","outputs":[{"name":"spawned","type":"uint32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_point","type":"uint32"},{"name":"_proxy","type":"address"}],"name":"setManagementProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"},{"name":"_who","type":"address"}],"name":"canSpawnAs","outputs":[{"name":"result","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"getKeyRevisionNumber","outputs":[{"name":"revision","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"},{"name":"_who","type":"address"}],"name":"canManage","outputs":[{"name":"result","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_proxy","type":"address"}],"name":"getTransferringFor","outputs":[{"name":"tfor","type":"uint32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"getPointSize","outputs":[{"name":"_size","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"_sponsor","type":"uint32"}],"name":"getSponsoringCount","outputs":[{"name":"count","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_proxy","type":"address"}],"name":"getSpawningFor","outputs":[{"name":"sfor","type":"uint32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"isEscaping","outputs":[{"name":"escaping","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint32"},{"name":"","type":"uint256"}],"name":"escapeRequests","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_point","type":"uint32"},{"name":"_proxy","type":"address"}],"name":"setVotingProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sponsor","type":"uint32"}],"name":"getSponsoring","outputs":[{"name":"sponsees","type":"uint32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_point","type":"uint32"},{"name":"_sponsor","type":"uint32"}],"name":"setEscapeRequest","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_operator","type":"address"}],"name":"isOperator","outputs":[{"name":"result","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"},{"name":"_who","type":"address"}],"name":"canVoteAs","outputs":[{"name":"result","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_primary","type":"string"},{"name":"_secondary","type":"string"},{"name":"_tertiary","type":"string"}],"name":"setDnsDomains","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_point","type":"uint32"}],"name":"loseSponsor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_operator","type":"address"},{"name":"_approved","type":"bool"}],"name":"setOperator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_point","type":"uint32"}],"name":"registerSpawned","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"getKeys","outputs":[{"name":"crypt","type":"bytes32"},{"name":"auth","type":"bytes32"},{"name":"suite","type":"uint32"},{"name":"revision","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_point","type":"uint32"}],"name":"cancelEscape","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"},{"name":"_address","type":"address"}],"name":"isOwner","outputs":[{"name":"result","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_proxy","type":"address"}],"name":"getManagerForCount","outputs":[{"name":"count","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint32"}],"name":"transferringForIndexes","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_proxy","type":"address"}],"name":"getVotingFor","outputs":[{"name":"vfor","type":"uint32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"spawningFor","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_point","type":"uint32"},{"name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_proxy","type":"address"}],"name":"getTransferringForCount","outputs":[{"name":"count","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"},{"name":"_proxy","type":"address"}],"name":"isVotingProxy","outputs":[{"name":"result","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"getPrefix","outputs":[{"name":"prefix","type":"uint16"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"dnsDomains","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_point","type":"uint32"}],"name":"incrementContinuityNumber","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"getSpawnProxy","outputs":[{"name":"spawnProxy","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"}],"name":"getEscapeRequest","outputs":[{"name":"escape","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_point","type":"uint32"},{"name":"_encryptionKey","type":"bytes32"},{"name":"_authenticationKey","type":"bytes32"},{"name":"_cryptoSuiteVersion","type":"uint32"}],"name":"setKeys","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_proxy","type":"address"}],"name":"getVotingForCount","outputs":[{"name":"count","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_point","type":"uint32"},{"name":"_sponsor","type":"uint32"}],"name":"isRequestingEscapeTo","outputs":[{"name":"equals","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"point","type":"uint32"},{"indexed":true,"name":"owner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"point","type":"uint32"}],"name":"Activated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"prefix","type":"uint32"},{"indexed":true,"name":"child","type":"uint32"}],"name":"Spawned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"point","type":"uint32"},{"indexed":true,"name":"sponsor","type":"uint32"}],"name":"EscapeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"point","type":"uint32"},{"indexed":true,"name":"sponsor","type":"uint32"}],"name":"EscapeCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"point","type":"uint32"},{"indexed":true,"name":"sponsor","type":"uint32"}],"name":"EscapeAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"point","type":"uint32"},{"indexed":true,"name":"sponsor","type":"uint32"}],"name":"LostSponsor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"point","type":"uint32"},{"indexed":false,"name":"encryptionKey","type":"bytes32"},{"indexed":false,"name":"authenticationKey","type":"bytes32"},{"indexed":false,"name":"cryptoSuiteVersion","type":"uint32"},{"indexed":false,"name":"keyRevisionNumber","type":"uint32"}],"name":"ChangedKeys","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"point","type":"uint32"},{"indexed":false,"name":"number","type":"uint32"}],"name":"BrokeContinuity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"point","type":"uint32"},{"indexed":true,"name":"spawnProxy","type":"address"}],"name":"ChangedSpawnProxy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"point","type":"uint32"},{"indexed":true,"name":"transferProxy","type":"address"}],"name":"ChangedTransferProxy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"point","type":"uint32"},{"indexed":true,"name":"managementProxy","type":"address"}],"name":"ChangedManagementProxy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"point","type":"uint32"},{"indexed":true,"name":"votingProxy","type":"address"}],"name":"ChangedVotingProxy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"primary","type":"string"},{"indexed":false,"name":"secondary","type":"string"},{"indexed":false,"name":"tertiary","type":"string"}],"name":"ChangedDns","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"}],"name":"OwnershipRenounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}] diff --git a/pkg/hs/urbit-azimuth/package.yaml b/pkg/hs/urbit-azimuth/package.yaml deleted file mode 100644 index 86b6e74de..000000000 --- a/pkg/hs/urbit-azimuth/package.yaml +++ /dev/null @@ -1,55 +0,0 @@ -name: urbit-azimuth -version: 0.10.1 -license: MIT -license-file: LICENSE - -library: - source-dirs: . - -dependencies: - - base - - web3 - -default-extensions: - - ApplicativeDo - - BangPatterns - - BlockArguments - - DataKinds - - DefaultSignatures - - DeriveAnyClass - - DeriveDataTypeable - - DeriveFoldable - - DeriveGeneric - - DeriveTraversable - - DerivingStrategies - - EmptyCase - - EmptyDataDecls - - FlexibleContexts - - FlexibleInstances - - FunctionalDependencies - - GADTs - - GeneralizedNewtypeDeriving - - LambdaCase - - MagicHash - - MultiParamTypeClasses - - NamedFieldPuns - - NoImplicitPrelude - - NumericUnderscores - - OverloadedStrings - - PackageImports - - PartialTypeSignatures - - PatternSynonyms - - QuasiQuotes - - Rank2Types - - RankNTypes - - RecordWildCards - - ScopedTypeVariables - - StandaloneDeriving - - TemplateHaskell - - TupleSections - - TypeApplications - - TypeFamilies - - TypeOperators - - UnboxedTuples - - UnicodeSyntax - - ViewPatterns diff --git a/pkg/hs/urbit-eventlog-lmdb/.gitignore b/pkg/hs/urbit-eventlog-lmdb/.gitignore deleted file mode 100644 index 65e7ea818..000000000 --- a/pkg/hs/urbit-eventlog-lmdb/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.stack-work -*.cabal -test/gold/*.writ diff --git a/pkg/hs/urbit-eventlog-lmdb/LICENSE b/pkg/hs/urbit-eventlog-lmdb/LICENSE deleted file mode 100644 index bf9294e05..000000000 --- a/pkg/hs/urbit-eventlog-lmdb/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 urbit - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/pkg/hs/urbit-eventlog-lmdb/lib/Urbit/EventLog/Event.hs b/pkg/hs/urbit-eventlog-lmdb/lib/Urbit/EventLog/Event.hs deleted file mode 100644 index 1e0b79e63..000000000 --- a/pkg/hs/urbit-eventlog-lmdb/lib/Urbit/EventLog/Event.hs +++ /dev/null @@ -1,21 +0,0 @@ -module Urbit.EventLog.Event - ( buildLogEvent - , parseLogEvent - ) - where - -import ClassyPrelude -import Data.Serialize -import Urbit.Noun - -buildLogEvent :: Mug -> Noun -> ByteString -buildLogEvent mug noun = (runPut $ putWord32le mug) ++ (jamBS noun) - -parseLogEvent :: MonadIO m => ByteString -> m (Mug, Noun) -parseLogEvent bs = do - let (prefix, suffix) = splitAt 4 bs - let mug = case runGet getWord32le prefix of - Left _ -> error "Impossible misread of word32 in parseLogEvent" - Right x -> x - n <- cueBSExn suffix - pure (mug, n) diff --git a/pkg/hs/urbit-eventlog-lmdb/lib/Urbit/EventLog/LMDB.hs b/pkg/hs/urbit-eventlog-lmdb/lib/Urbit/EventLog/LMDB.hs deleted file mode 100644 index 819078889..000000000 --- a/pkg/hs/urbit-eventlog-lmdb/lib/Urbit/EventLog/LMDB.hs +++ /dev/null @@ -1,466 +0,0 @@ -{-| - High-Level Event-Log Interface - - TODO Effects storage logic is messy. --} - -module Urbit.EventLog.LMDB - ( LogIdentity(..) - , EventLog - , identity - , nextEv - , lastEv - , new - , existing - , streamEvents - , appendEvents - , trimEvents - , streamEffectsRows - , writeEffectsRow - ) -where - -import ClassyPrelude - -import Data.RAcquire -import Database.LMDB.Raw - -import Data.Conduit (ConduitT, yield) -import Foreign.Marshal.Alloc (allocaBytes) -import Foreign.Ptr (Ptr, castPtr, nullPtr) -import Foreign.Storable (peek, poke, sizeOf) -import RIO (HasLogFunc, RIO, display, logDebug, runRIO) -import Urbit.Noun (DecodeErr, Noun, Ship) -import Urbit.Noun (deriveNoun, fromNounExn, toNoun, fromNoun) -import Urbit.Noun (atomBytes, bytesAtom) -import Urbit.Noun.Core (pattern Atom) - - -import qualified Data.ByteString.Unsafe as BU -import qualified Data.Vector as V - - --- Public Types ---------------------------------------------------------------- - -data LogIdentity = LogIdentity - { who :: !Ship - , isFake :: !Bool - , lifecycleLen :: !Word - } deriving (Eq, Ord, Show) - -deriveNoun ''LogIdentity - - --- Types ----------------------------------------------------------------------- - -type Env = MDB_env -type Val = MDB_val -type Txn = MDB_txn -type Dbi = MDB_dbi -type Cur = MDB_cursor - -data EventLog = EventLog - { env :: Env - , _metaTbl :: Dbi - , eventsTbl :: Dbi - , effectsTbl :: Dbi - , identity :: LogIdentity - , numEvents :: TVar Word64 - } - -nextEv :: EventLog -> STM Word64 -nextEv = fmap (+1) . lastEv - -lastEv :: EventLog -> STM Word64 -lastEv = readTVar . numEvents - -data EventLogExn - = NoLogIdentity - | MissingLogVersion - | BadLogVersion Word64 - | MissingEvent Word64 - | BadNounInLogIdentity ByteString DecodeErr ByteString - | BadKeyInEventLog - | BadWriteLogIdentity LogIdentity - | BadWriteEvent Word64 - | BadWriteEffect Word64 - deriving Show - - --- Instances ------------------------------------------------------------------- - -instance Exception EventLogExn where - - --- Utils ----------------------------------------------------------------------- - -io :: MonadIO m => IO a -> m a -io = liftIO - - --- Open/Close an Event Log ----------------------------------------------------- - -rawOpen :: MonadIO m => FilePath -> m Env -rawOpen dir = io $ do - env <- mdb_env_create - mdb_env_set_maxdbs env 3 - mdb_env_set_mapsize env (1024 * 1024 * 1024 * 1024) - mdb_env_open env dir [] - pure env - -create :: HasLogFunc e => FilePath -> LogIdentity -> RIO e EventLog -create dir id = do - logDebug $ display (pack @Text $ "Creating LMDB database: " <> dir) - logDebug $ display (pack @Text $ "Log Identity: " <> show id) - env <- rawOpen dir - (m, e, f) <- createTables env - clearEvents env e - writeIdent env m id - EventLog env m e f id <$> newTVarIO 0 - where - createTables env = - rwith (writeTxn env) $ \txn -> io $ - (,,) <$> mdb_dbi_open txn (Just "META") [MDB_CREATE] - <*> mdb_dbi_open txn (Just "EVENTS") [MDB_CREATE, MDB_INTEGERKEY] - <*> mdb_dbi_open txn (Just "EFFECTS") [MDB_CREATE, MDB_INTEGERKEY] - -open :: HasLogFunc e => FilePath -> RIO e EventLog -open dir = do - logDebug $ display (pack @Text $ "Opening LMDB database: " <> dir) - env <- rawOpen dir - (m, e, f) <- openTables env - id <- getIdent env m - logDebug $ display (pack @Text $ "Log Identity: " <> show id) - numEvs <- getNumEvents env e - EventLog env m e f id <$> newTVarIO numEvs - where - openTables env = - rwith (writeTxn env) $ \txn -> io $ - (,,) <$> mdb_dbi_open txn (Just "META") [] - <*> mdb_dbi_open txn (Just "EVENTS") [MDB_INTEGERKEY] - <*> mdb_dbi_open txn (Just "EFFECTS") [MDB_CREATE, MDB_INTEGERKEY] - -close :: HasLogFunc e => FilePath -> EventLog -> RIO e () -close dir (EventLog env meta events effects _ _) = do - logDebug $ display (pack @Text $ "Closing LMDB database: " <> dir) - io $ do mdb_dbi_close env meta - mdb_dbi_close env events - mdb_dbi_close env effects - mdb_env_sync_flush env - mdb_env_close env - - --- Create a new event log or open an existing one. ----------------------------- - -existing :: HasLogFunc e => FilePath -> RAcquire e EventLog -existing dir = mkRAcquire (open dir) (close dir) - -new :: HasLogFunc e => FilePath -> LogIdentity -> RAcquire e EventLog -new dir id = mkRAcquire (create dir id) (close dir) - - --- Read/Write Log Identity ----------------------------------------------------- - -{-| - A read-only transaction that commits at the end. - - Use this when opening database handles. --} -_openTxn :: Env -> RAcquire e Txn -_openTxn env = mkRAcquire begin commit - where - begin = io $ mdb_txn_begin env Nothing True - commit = io . mdb_txn_commit - -{-| - A read-only transaction that aborts at the end. - - Use this when reading data from already-opened databases. --} -readTxn :: Env -> RAcquire e Txn -readTxn env = mkRAcquire begin abort - where - begin = io $ mdb_txn_begin env Nothing True - abort = io . mdb_txn_abort - -{-| - A read-write transaction that commits upon sucessful completion and - aborts on exception. - - Use this when reading data from already-opened databases. --} -writeTxn :: Env -> RAcquire e Txn -writeTxn env = mkRAcquireType begin finalize - where - begin = io $ mdb_txn_begin env Nothing False - finalize txn = io . \case - ReleaseNormal -> mdb_txn_commit txn - ReleaseEarly -> mdb_txn_commit txn - ReleaseException -> mdb_txn_abort txn - -cursor :: Txn -> Dbi -> RAcquire e Cur -cursor txn dbi = mkRAcquire open close - where - open = io $ mdb_cursor_open txn dbi - close = io . mdb_cursor_close - -getIdent :: HasLogFunc e => Env -> Dbi -> RIO e LogIdentity -getIdent env dbi = do - logDebug "Reading log identity" - getTbl env >>= traverse decodeIdent >>= \case - Nothing -> throwIO NoLogIdentity - Just li -> pure li - where - decodeIdent :: (Noun, Noun, Noun, Noun) -> RIO e LogIdentity - decodeIdent (ver, who, fake, life) = do - -- Verify log version - case fromNoun ver of - Just 1 -> pure () - Just x -> throwIO $ BadLogVersion x - Nothing -> throwIO $ MissingLogVersion - - fromNounExn $ toNoun (who, fake, life) - - getTbl :: Env -> RIO e (Maybe (Noun, Noun, Noun, Noun)) - getTbl env = do - rwith (readTxn env) $ \txn -> do - version <- getMb txn dbi "version" - who <- getMb txn dbi "who" - fake <- getMb txn dbi "fake" - life <- getMb txn dbi "life" - pure $ (,,,) <$> version <*> who <*> fake <*> life - -writeIdent :: HasLogFunc e => Env -> Dbi -> LogIdentity -> RIO e () -writeIdent env metaTbl ident@LogIdentity{..} = do - logDebug "Writing log identity" - let flags = compileWriteFlags [] - rwith (writeTxn env) $ \txn -> do - w <- putAtom flags txn metaTbl "version" (toNoun (1 :: Integer)) - x <- putAtom flags txn metaTbl "who" (toNoun who) - y <- putAtom flags txn metaTbl "fake" (toNoun isFake) - z <- putAtom flags txn metaTbl "life" (toNoun lifecycleLen) - unless (w && x && y && z) $ do - throwIO (BadWriteLogIdentity ident) - - --- Latest Event Number --------------------------------------------------------- - -getNumEvents :: Env -> Dbi -> RIO e Word64 -getNumEvents env eventsTbl = - rwith (readTxn env) $ \txn -> - rwith (cursor txn eventsTbl) $ \cur -> - withKVPtrs' nullVal nullVal $ \pKey pVal -> - io $ mdb_cursor_get MDB_LAST cur pKey pVal >>= \case - False -> pure 0 - True -> peek pKey >>= mdbValToWord64 - - --- Write Events ---------------------------------------------------------------- - -clearEvents :: Env -> Dbi -> RIO e () -clearEvents env eventsTbl = - rwith (writeTxn env) $ \txn -> - rwith (cursor txn eventsTbl) $ \cur -> - withKVPtrs' nullVal nullVal $ \pKey pVal -> do - let loop = io (mdb_cursor_get MDB_LAST cur pKey pVal) >>= \case - False -> pure () - True -> do io $ mdb_cursor_del (compileWriteFlags []) cur - loop - loop - -appendEvents :: EventLog -> Vector ByteString -> RIO e () -appendEvents log !events = do - numEvs <- atomically $ readTVar (numEvents log) - next <- pure (numEvs + 1) - doAppend $ zip [next..] $ toList events - atomically $ writeTVar (numEvents log) (numEvs + word (length events)) - where - flags = compileWriteFlags [MDB_NOOVERWRITE] - doAppend = \kvs -> - rwith (writeTxn $ env log) $ \txn -> - for_ kvs $ \(k,v) -> do - putBytes flags txn (eventsTbl log) k v >>= \case - True -> pure () - False -> throwIO (BadWriteEvent k) - -writeEffectsRow :: MonadIO m => EventLog -> Word64 -> ByteString -> m () -writeEffectsRow log k v = io $ runRIO () $ do - let flags = compileWriteFlags [] - rwith (writeTxn $ env log) $ \txn -> - putBytes flags txn (effectsTbl log) k v >>= \case - True -> pure () - False -> throwIO (BadWriteEffect k) - - --- Read Events ----------------------------------------------------------------- - -trimEvents :: HasLogFunc e => EventLog -> Word64 -> RIO e () -trimEvents log start = do - last <- atomically (lastEv log) - rwith (writeTxn $ env log) $ \txn -> - for_ [start..last] $ \eId -> - withWordPtr eId $ \pKey -> do - let key = MDB_val 8 (castPtr pKey) - found <- io $ mdb_del txn (eventsTbl log) key Nothing - unless found $ - throwIO (MissingEvent eId) - atomically $ writeTVar (numEvents log) (pred start) - -streamEvents :: MonadIO m => EventLog -> Word64 -> ConduitT () ByteString m () -streamEvents log first = do - batch <- io $ runRIO () $ readBatch log first - unless (null batch) $ do - for_ batch yield - streamEvents log (first + word (length batch)) - -streamEffectsRows :: forall e. HasLogFunc e - => EventLog -> Word64 - -> ConduitT () (Word64, ByteString) (RIO e) () -streamEffectsRows log = go - where - go :: Word64 -> ConduitT () (Word64, ByteString) (RIO e) () - go next = do - batch <- lift $ readRowsBatch (env log) (effectsTbl log) next - unless (null batch) $ do - for_ batch yield - go (next + fromIntegral (length batch)) - -{-| - Read 1000 rows from the events table, starting from event `first`. - - Throws `MissingEvent` if an event was missing from the log. --} -readBatch :: EventLog -> Word64 -> RIO e (V.Vector ByteString) -readBatch log first = start - where - start = do - last <- atomically (lastEv log) - if (first > last) - then pure mempty - else readRows $ fromIntegral $ min 1000 $ ((last+1) - first) - - assertFound :: Word64 -> Bool -> RIO e () - assertFound id found = do - unless found $ throwIO $ MissingEvent id - - readRows count = - withWordPtr first $ \pIdx -> - withKVPtrs' (MDB_val 8 (castPtr pIdx)) nullVal $ \pKey pVal -> - rwith (readTxn $ env log) $ \txn -> - rwith (cursor txn $ eventsTbl log) $ \cur -> do - assertFound first =<< io (mdb_cursor_get MDB_SET_KEY cur pKey pVal) - fetchRows count cur pKey pVal - - fetchRows count cur pKey pVal = do - env <- ask - V.generateM count $ \i -> runRIO env $ do - key <- io $ peek pKey >>= mdbValToWord64 - val <- io $ peek pVal >>= mdbValToBytes - idx <- pure (first + word i) - unless (key == idx) $ throwIO $ MissingEvent idx - when (count /= succ i) $ do - assertFound idx =<< io (mdb_cursor_get MDB_NEXT cur pKey pVal) - pure val - -{-| - Read 1000 rows from the database, starting from key `first`. --} -readRowsBatch :: forall e. HasLogFunc e - => Env -> Dbi -> Word64 -> RIO e (V.Vector (Word64, ByteString)) -readRowsBatch env dbi first = readRows - where - readRows = do - logDebug $ display ("(readRowsBatch) From: " <> tshow first) - withWordPtr first $ \pIdx -> - withKVPtrs' (MDB_val 8 (castPtr pIdx)) nullVal $ \pKey pVal -> - rwith (readTxn env) $ \txn -> - rwith (cursor txn dbi) $ \cur -> - io (mdb_cursor_get MDB_SET_RANGE cur pKey pVal) >>= \case - False -> pure mempty - True -> V.unfoldrM (fetchBatch cur pKey pVal) 1000 - - fetchBatch :: Cur -> Ptr Val -> Ptr Val -> Word - -> RIO e (Maybe ((Word64, ByteString), Word)) - fetchBatch cur pKey pVal 0 = pure Nothing - fetchBatch cur pKey pVal n = do - key <- io $ peek pKey >>= mdbValToWord64 - val <- io $ peek pVal >>= mdbValToBytes - io $ mdb_cursor_get MDB_NEXT cur pKey pVal >>= \case - False -> pure $ Just ((key, val), 0) - True -> pure $ Just ((key, val), pred n) - - --- Utils ----------------------------------------------------------------------- - -withKVPtrs' :: (MonadIO m, MonadUnliftIO m) - => Val -> Val -> (Ptr Val -> Ptr Val -> m a) -> m a -withKVPtrs' k v cb = - withRunInIO $ \run -> - withKVPtrs k v $ \x y -> run (cb x y) - -nullVal :: MDB_val -nullVal = MDB_val 0 nullPtr - -word :: Int -> Word64 -word = fromIntegral - -assertExn :: Exception e => Bool -> e -> IO () -assertExn True _ = pure () -assertExn False e = throwIO e - -byteStringAsMdbVal :: ByteString -> (MDB_val -> IO a) -> IO a -byteStringAsMdbVal bs k = - BU.unsafeUseAsCStringLen bs $ \(ptr,sz) -> - k (MDB_val (fromIntegral sz) (castPtr ptr)) - -mdbValToWord64 :: MDB_val -> IO Word64 -mdbValToWord64 (MDB_val sz ptr) = do - assertExn (sz == 8) BadKeyInEventLog - peek (castPtr ptr) - -withWord64AsMDBval :: (MonadIO m, MonadUnliftIO m) - => Word64 -> (MDB_val -> m a) -> m a -withWord64AsMDBval w cb = do - withWordPtr w $ \p -> - cb (MDB_val (fromIntegral (sizeOf w)) (castPtr p)) - -withWordPtr :: (MonadIO m, MonadUnliftIO m) - => Word64 -> (Ptr Word64 -> m a) -> m a -withWordPtr w cb = - withRunInIO $ \run -> - allocaBytes (sizeOf w) (\p -> poke p w >> run (cb p)) - - --- Lower-Level Operations ------------------------------------------------------ - -getMb :: MonadIO m => Txn -> Dbi -> ByteString -> m (Maybe Noun) -getMb txn db key = - io $ - byteStringAsMdbVal key $ \mKey -> - mdb_get txn db mKey >>= traverse (mdbValToNoun key) - -mdbValToBytes :: MDB_val -> IO ByteString -mdbValToBytes (MDB_val sz ptr) = do - BU.unsafePackCStringLen (castPtr ptr, fromIntegral sz) - -mdbValToNoun :: ByteString -> MDB_val -> IO Noun -mdbValToNoun key (MDB_val sz ptr) = do - (Atom . bytesAtom) <$> BU.unsafePackCStringLen (castPtr ptr, fromIntegral sz) - -putAtom :: MonadIO m - => MDB_WriteFlags -> Txn -> Dbi -> ByteString -> Noun -> m Bool -putAtom flags txn db key val = - case val of - Atom a -> io $ - byteStringAsMdbVal key $ \mKey -> - byteStringAsMdbVal (atomBytes a) $ \mVal -> - mdb_put flags txn db mKey mVal - _ -> error "Impossible putAtom received cell" - -putBytes :: MonadIO m - => MDB_WriteFlags -> Txn -> Dbi -> Word64 -> ByteString -> m Bool -putBytes flags txn db id bs = - io $ - withWord64AsMDBval id $ \idVal -> - byteStringAsMdbVal bs $ \mVal -> - mdb_put flags txn db idVal mVal diff --git a/pkg/hs/urbit-eventlog-lmdb/package.yaml b/pkg/hs/urbit-eventlog-lmdb/package.yaml deleted file mode 100644 index 398e69a8b..000000000 --- a/pkg/hs/urbit-eventlog-lmdb/package.yaml +++ /dev/null @@ -1,72 +0,0 @@ -name: urbit-eventlog-lmdb -version: 0.10.4 -license: MIT -license-file: LICENSE - -library: - source-dirs: lib - ghc-options: - - -fwarn-incomplete-patterns - - -fwarn-unused-binds - - -fwarn-unused-imports - - -Werror - - -O2 - -dependencies: - - base - - cereal - - classy-prelude - - stm - - rio - - vector - - bytestring - - lmdb - - conduit - - racquire - - urbit-noun-core - - urbit-noun - -default-extensions: - - ApplicativeDo - - BangPatterns - - BlockArguments - - ConstraintKinds - - DataKinds - - DefaultSignatures - - DeriveAnyClass - - DeriveDataTypeable - - DeriveFoldable - - DeriveGeneric - - DeriveTraversable - - DerivingStrategies - - EmptyCase - - EmptyDataDecls - - FlexibleContexts - - FlexibleInstances - - FunctionalDependencies - - GADTs - - GeneralizedNewtypeDeriving - - LambdaCase - - MagicHash - - MultiParamTypeClasses - - NamedFieldPuns - - NoImplicitPrelude - - NumericUnderscores - - OverloadedStrings - - PackageImports - - PartialTypeSignatures - - PatternSynonyms - - QuasiQuotes - - Rank2Types - - RankNTypes - - RecordWildCards - - ScopedTypeVariables - - StandaloneDeriving - - TemplateHaskell - - TupleSections - - TypeApplications - - TypeFamilies - - TypeOperators - - UnboxedTuples - - UnicodeSyntax - - ViewPatterns diff --git a/pkg/hs/urbit-king/.gitignore b/pkg/hs/urbit-king/.gitignore deleted file mode 100644 index 65e7ea818..000000000 --- a/pkg/hs/urbit-king/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.stack-work -*.cabal -test/gold/*.writ diff --git a/pkg/hs/urbit-king/LICENSE b/pkg/hs/urbit-king/LICENSE deleted file mode 100644 index bf9294e05..000000000 --- a/pkg/hs/urbit-king/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 urbit - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/pkg/hs/urbit-king/TODO.md b/pkg/hs/urbit-king/TODO.md deleted file mode 100644 index 2e3be7108..000000000 --- a/pkg/hs/urbit-king/TODO.md +++ /dev/null @@ -1,114 +0,0 @@ -# New IPC Protocol - -Stubbed out: - -- [x] Handle replacement events (stubbed out now b/c interface can't - handle unparsed nouns) -- [x] Handle IPC errors by killing serf process. -- [x] Handle `peek` and `pack` in `swimming` flow. -- [x] Documentation for `Urbit.Vere.Serf.IPC`. -- [x] Unstub slog/stder/dead callbacks on serf config. -- [x] Remove GoodParse hack in newRunCompute. -- [x] Bring back tank printing. -- [x] Handle serf stderr message correctly. -- [x] Bring back `logEvent`. -- [x] Snapshots should block until that event is commited to disk. -- [x] Hook up error callbacks to IO Drivers. -- [x] Do something useful with error callbacks from IO Drivers. - -Bugs: - -- [x] In non-daemon mode, serf slogs/stderr output that happens *before* - the terminal connects should still go to stderr. -- [x] Serf stderr should also be send (along with slogs) to all connected - terminals. -- [x] `king new` should reject pier directories that already exist. -- [x] In non-daemon-mode, ^D doesn't bring down Urbit properly. -- [x] Spinner updated multiple times with the same event, and this causes - logging of events to contain duplicates. - -King-Haskell specific features: - -- [x] Re-implement `collectFX` flow in Serf/Pier. -- [x] Hook up `collectFX` to CLI. -- [ ] Get `collect-all-fx` flow working again. - -Performance: - -- [x] Batching during replay. -- [x] Batching during normal operation. - -Optimization: - -- [x] IO Driver Event Prioritization - -Polish: - -- [x] Cleanup batching flow. -- [x] Think through how to shutdown the serf on exception. -- [x] King should shutdown promptly on ^C. Always takes 2s in practice. -- [x] Bring back progress bars. -- [x] Make sure replay progress bars go to stderr. -- [x] Logging for new IPC flow. -- [x] Logging for boot sequence. -- [x] Take snapshots on clean shutdown. - -# Misc Bugs - -- [ ] `king run --collect-fx` flag does nothing. Remove or implement. -- [x] Handle ^C in connected terminals. It should interrupt current - event (send SIGINT to serf, which will cause the current event to - fail promptly). -- [x] The terminal driver seems to have a race condition when spinner - changed too quickly. - - -# Take Advantage of New IPC Features - -- [ ] Hook up `scry` to drivers. - - Any immediate applications of this? - -- [ ] Allow scrys to go into the %work batching flow for better latency. - -- Handle event errors in other cases: - - [ ] Ames packet failures should print (but not too often). - - [ ] Incoming Http requests should produce 500 responses. - - [ ] Terminal event errors should be printed in connected terminals. - - [ ] Http client responses should be retried. - - -# Further IO Driver Startup Flow Betterment - -Implement Pier-wide process start events - -- [x] Handle %vega and exit effects. -- [x] Handle %trim effect -- [x] Inject entropy event on pier start: ``[//arvo [%wack ENT]]` -- [ ] Verbose flag: `-v` injects `[%verb ~]` - -- CLI event injection: `-I file-path`. The `file-path` is a jammed noun - representing an event: `[wire card]`. - - [x] Just parse it as an `Ev` for now. - - [ ] Make the serf IPC code not care about the shape of events and effects. - - [ ] Support invalid events throughout the system (use `Lenient`?) - -# Polish - -- [x] Goot logging output in non-verbose mode. -- [x] Command-Line flag to re-enable verbose output. - - -# Cleanup - -- [x] ShutdownSTM action that's passed to the terminal driver should - live in `KingEnv` and should be available to all drivers. -- [ ] Break most logic from `Main.hs` out into modules. -- [ ] Simplify `Main.hs` flows. -- [ ] Cleanup Terminal Driver code. -- [x] Spin off `racquire` into it's own package. -- [x] Spin off `urbit-noun-core` and `urbit-noun` packages. -- [x] Spin off `urbit-eventlog-lmdb` into it's own package. -- [ ] Spin off `Urbit.Vere.Serf` into it's own package - - Make it care less about the shape of events and effects. -- [ ] Spin off per-pier logic into it's own package. - - Probably `urbit-pier` diff --git a/pkg/hs/urbit-king/app/Main.hs b/pkg/hs/urbit-king/app/Main.hs deleted file mode 100644 index 8a57e92a7..000000000 --- a/pkg/hs/urbit-king/app/Main.hs +++ /dev/null @@ -1,2 +0,0 @@ -module Main (module Urbit.King.Main) where -import Urbit.King.Main diff --git a/pkg/hs/urbit-king/lib/Urbit/Arvo.hs b/pkg/hs/urbit-king/lib/Urbit/Arvo.hs deleted file mode 100644 index 4b3834528..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Arvo.hs +++ /dev/null @@ -1,13 +0,0 @@ -module Urbit.Arvo - ( module Urbit.Arvo.Common - , module Urbit.Arvo.Effect - , module Urbit.Arvo.Event - , FX - ) where - -import Urbit.Arvo.Common -import Urbit.Arvo.Effect -import Urbit.Arvo.Event -import Urbit.Noun.Conversions (Lenient) - -type FX = [Lenient Ef] diff --git a/pkg/hs/urbit-king/lib/Urbit/Arvo/Common.hs b/pkg/hs/urbit-king/lib/Urbit/Arvo/Common.hs deleted file mode 100644 index 3168ba1e3..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Arvo/Common.hs +++ /dev/null @@ -1,310 +0,0 @@ -{-# LANGUAGE StrictData #-} - --- This is required due to the use of 'Void' in a constructor slot in --- combination with 'deriveNoun' which generates an unreachable pattern. -{-# OPTIONS_GHC -Wno-overlapping-patterns #-} - --- Hack. See comment above instance ToNoun H.StdMethod -{-# OPTIONS_GHC -Wno-orphans #-} - -{-| - Types used in both Events and Effects. --} -module Urbit.Arvo.Common - ( KingId(..), ServId(..) - , Vere(..), Wynn(..) - , Json, JsonNode(..) - , Desk(..), Mime(..) - , Port(..), Turf(..) - , HttpServerConf(..), PEM(..), Key, Cert - , HttpEvent(..), Method, Header(..), ResponseHeader(..) - , ReOrg(..), reorgThroughNoun - , AmesDest, Ipv4(..), Ipv6(..), Patp(..), Galaxy, AmesAddress(..) - ) where - -import Urbit.Prelude - -import Control.Monad.Fail (fail) -import Data.Serialize - -import qualified Network.HTTP.Types.Method as H -import qualified Network.Socket as N -import qualified Urbit.Ob as Ob - - --- Misc Types ------------------------------------------------------------------ - -{-| - Domain Name in TLD order: - - ["org", "urbit", "dns"] -> dns.urbit.org --} -newtype Turf = Turf { unTurf :: [Cord] } - deriving newtype (Eq, Ord, Show, ToNoun, FromNoun) - -newtype KingId = KingId { unKingId :: UV } - deriving newtype (Eq, Ord, Show, Num, Real, Enum, Integral, FromNoun, ToNoun) - -newtype ServId = ServId { unServId :: UV } - deriving newtype (Eq, Ord, Show, Num, Enum, Integral, Real, FromNoun, ToNoun) - --- Arvo Version Negotiation ---------------------------------------------------- - --- Information about the king runtime passed to Arvo. -data Vere = Vere { vereName :: Term, - vereRev :: [Cord], - vereWynn :: Wynn } - deriving (Eq, Ord, Show) - -instance ToNoun Vere where - toNoun Vere{..} = toNoun ((vereName, vereRev), vereWynn) - -instance FromNoun Vere where - parseNoun n = named "Vere" $ do - ((vereName, vereRev), vereWynn) <- parseNoun n - pure $ Vere {..} - --- A list of names and their kelvin numbers, used in version negotiations. -newtype Wynn = Wynn { unWynn :: [(Term, Word)] } - deriving newtype (Eq, Ord, Show, FromNoun, ToNoun) - --- Http Common ----------------------------------------------------------------- - -data Header = Header Cord Bytes - deriving (Eq, Ord, Show) - -data ResponseHeader = ResponseHeader - { statusCode :: Word - , headers :: [Header] - } - deriving (Eq, Ord, Show) - -data HttpEvent - = Start ResponseHeader (Maybe File) Bool - | Continue (Maybe File) Bool - | Cancel () - deriving (Eq, Ord, Show) - -deriveNoun ''ResponseHeader -deriveNoun ''Header -deriveNoun ''HttpEvent - - --- Http Requests --------------------------------------------------------------- - -type Method = H.StdMethod - --- TODO Hack! Don't write instances for library types. Write them for --- our types instead. - -instance ToNoun H.StdMethod where - toNoun = toNoun . MkBytes . H.renderStdMethod - -instance FromNoun H.StdMethod where - parseNoun n = named "StdMethod" $ do - MkBytes bs <- parseNoun n - case H.parseMethod bs of - Left md -> fail ("Unexpected method: " <> unpack (decodeUtf8 md)) - Right m -> pure m - - - --- Http Server Configuration --------------------------------------------------- - -newtype PEM = PEM { unPEM :: Wain } - deriving newtype (Eq, Ord, ToNoun, FromNoun) - -instance Show PEM where - show _ = "\"PEM (secret)\"" - -type Key = PEM -type Cert = PEM - -data HttpServerConf = HttpServerConf - { hscSecure :: Maybe (Key, Cert) - , hscProxy :: Bool - , hscLog :: Bool - , hscRedirect :: Bool - } - deriving (Eq, Ord, Show) - -deriveNoun ''HttpServerConf - - --- Desk and Mime --------------------------------------------------------------- - -newtype Desk = Desk { unDesk :: Cord } - deriving newtype (Eq, Ord, Show, ToNoun, FromNoun, IsString) - -data Mime = Mime Path File - deriving (Eq, Ord, Show) - -deriveNoun ''Mime - - --- Json ------------------------------------------------------------------------ - -type Json = Nullable JsonNode - -data JsonNode - = JNA [Json] - | JNB Bool - | JNO (HoonMap Cord Json) - | JNN Knot - | JNS Cord - deriving (Eq, Ord, Show) - -deriveNoun ''JsonNode - - --- Ames Destinations ------------------------------------------------- - -serializeToNoun :: Serialize a => a -> Noun -serializeToNoun = A . bytesAtom . encode - -serializeParseNoun :: Serialize a => String -> Int -> Noun -> Parser a -serializeParseNoun desc len = named (pack desc) . \case - A (atomBytes -> bs) - -- Atoms lose leading 0s, but since lsb, these become trailing NULs - | length bs <= len -> case decode $ bs <> replicate (len - length bs) 0 of - Right aa -> pure aa - Left msg -> fail msg - | otherwise -> fail ("putative " <> desc <> " " <> show bs <> " too long") - C{} -> fail ("unexpected cell in " <> desc) - -newtype Patp a = Patp { unPatp :: a } - deriving newtype (Eq, Ord, Enum, Real, Integral, Num, ToNoun, FromNoun) - --- Network Port -newtype Port = Port { unPort :: Word16 } - deriving newtype (Eq, Ord, Show, Enum, Real, Integral, Num, ToNoun, FromNoun) - --- @if -newtype Ipv4 = Ipv4 { unIpv4 :: N.HostAddress } - deriving newtype (Eq, Ord, Enum) - -instance Serialize Ipv4 where - get = (\a b c d -> Ipv4 $ N.tupleToHostAddress $ (d, c, b, a)) - <$> getWord8 <*> getWord8 <*> getWord8 <*> getWord8 - put (Ipv4 (N.hostAddressToTuple -> (a, b, c, d))) = for_ [d, c, b, a] putWord8 - -instance ToNoun Ipv4 where - toNoun = serializeToNoun - -instance FromNoun Ipv4 where - parseNoun = serializeParseNoun "Ipv4" 4 - -instance Show Ipv4 where - show (Ipv4 (N.hostAddressToTuple -> (a, b, c, d))) = - show a ++ "." ++ - show b ++ "." ++ - show c ++ "." ++ - show d - --- @is --- should probably use hostAddress6ToTuple here, but no one uses it right now -newtype Ipv6 = Ipv6 { unIpv6 :: Word128 } - deriving newtype (Eq, Ord, Show, Enum, Real, Integral, Num, ToNoun, FromNoun) - -type Galaxy = Patp Word8 - -instance Integral a => Show (Patp a) where - show = show . Ob.renderPatp . Ob.patp . fromIntegral . unPatp - -data AmesAddress = AAIpv4 Ipv4 Port - deriving (Eq, Ord, Show) - -instance Serialize AmesAddress where - get = AAIpv4 <$> get <*> (Port <$> getWord16le) - put (AAIpv4 ip (Port port)) = put ip >> putWord16le port - -instance FromNoun AmesAddress where - parseNoun = serializeParseNoun "AmesAddress" 6 - -instance ToNoun AmesAddress where - toNoun = serializeToNoun - -type AmesDest = Each Galaxy AmesAddress - - --- Path+Tagged Restructuring --------------------------------------------------- - -{-| - This reorganized events and effects to be easier to parse. This is - complicated and gross, and a better way should be found! - - ReOrg takes in nouns with the following shape: - - [[fst snd rest] [tag val]] - - And turns that into: - - ReOrg fst snd tag rest val - - For example, - - [//behn/5 %doze ~ 9999] - - Becomes: - - Reorg "" "behn" "doze" ["5"] 9999 - - This is convenient, since we can then use our head-tag based FromNoun - and ToNoun instances. - - NOTE: - - Also, in the wild, I ran into this event: - - [//term/1 %init] - - So, I rewrite atom-events as follows: - - [x y=@] -> [x [y ~]] - - Which rewrites the %init example to: - - [//term/1 [%init ~]] - - TODO The reverse translation is not done yet. - --} -data ReOrg = ReOrg Cord Cord Cord EvilPath Noun - -instance FromNoun ReOrg where - parseNoun = named "ReOrg" . \case - A _ -> expected "got atom" - C (A _) _ -> expected "empty route" - C h (A a) -> parseNoun (C h (C (A a) (A 0))) - C (C _ (A _)) (C _ _) -> expected "route is too short" - C (C f (C s p)) (C t v) -> do - fst :: Cord <- named "first-route" $ parseNoun f - snd :: Cord <- named "second-route" $ parseNoun s - pax :: EvilPath <- named "rest-of-route" $ parseNoun p - tag :: Cord <- named "tag" $ parseNoun t - val :: Noun <- pure v - pure (ReOrg fst snd tag pax val) - where - expected got = fail ("expected route+tagged; " <> got) - -instance ToNoun ReOrg where - toNoun (ReOrg fst snd tag pax val) = - toNoun ((fst, snd, pax), (tag, val)) - -{-| - Given something parsed from a ReOrg Noun, convert that back to - a ReOrg. - - This code may crash, but only if the FromNoun/ToNoun instances for - the effects are incorrect. --} -reorgThroughNoun :: ToNoun x => (Cord, x) -> ReOrg -reorgThroughNoun = - fromNounCrash . toNoun >>> \case - (f, s, t, p, v) -> ReOrg f s t p v - where - fromNounCrash :: FromNoun a => Noun -> a - fromNounCrash = - fromNounErr >>> \case - Left err -> error (show err) - Right vl -> vl diff --git a/pkg/hs/urbit-king/lib/Urbit/Arvo/Effect.hs b/pkg/hs/urbit-king/lib/Urbit/Arvo/Effect.hs deleted file mode 100644 index 6037e0298..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Arvo/Effect.hs +++ /dev/null @@ -1,321 +0,0 @@ -{-# LANGUAGE StrictData #-} - --- This is required due to the use of 'Void' in a constructor slot in --- combination with 'deriveNoun' which generates an unreachable pattern. -{-# OPTIONS_GHC -Wno-overlapping-patterns #-} - -{-| - Effect Types and Their Noun Conversions --} -module Urbit.Arvo.Effect where - -import Urbit.Noun.Time -import Urbit.Prelude - -import Control.Monad.Fail (fail) -import Numeric.Natural (Natural) -import Urbit.Arvo.Common (KingId(..), ServId(..)) -import Urbit.Arvo.Common (Header, HttpEvent, HttpServerConf, Method, Mime) -import Urbit.Arvo.Common (AmesDest, Turf) -import Urbit.Arvo.Common (ReOrg(..), reorgThroughNoun) -import Urbit.Arvo.Common (Desk, Wynn) - - --- Newt Effects ---------------------------------------------------------------- - -{-| - %turf -- Set which domain names we've bound. - %send -- Send a UDP packet. --} -data NewtEf - = NewtEfTurf (Atom, ()) [Turf] - | NewtEfSend (Atom, ()) AmesDest Bytes - deriving (Eq, Ord, Show) - -deriveNoun ''NewtEf - - --- HTTP Client Effects --------------------------------------------------------- - -data HttpClientReq = HttpClientReq - { method :: Method - , url :: Cord - , headerList :: [Header] - , body :: Maybe Octs - } - deriving (Eq, Ord, Show) - -{-| - %request -- TODO - %cancel-request -- TODO --} -data HttpClientEf - = HCERequest (Atom, ()) Word HttpClientReq - | HCECancelRequest Path Word - deriving (Eq, Ord, Show) - -deriveNoun ''HttpClientReq -deriveNoun ''HttpClientEf - - --- HTTP Server Effects --------------------------------------------------------- - -{-| - %set-config -- Update HTTP server configuration. - %response -- Respond to an active HTTP request. --} -data HttpServerEf - = HSESetConfig (ServId, ()) HttpServerConf - | HSEResponse (ServId, UD, UD, ()) HttpEvent - deriving (Eq, Ord, Show) - -deriveNoun ''HttpServerEf - - --- File System Effects --------------------------------------------------------- - -{-| - %hill -- TODO - %dirk -- mark mount dirty - %ergo -- TODO - %ogre -- TODO --} -data SyncEf - = SyncEfHill () [Desk] - | SyncEfDirk Path Desk - | SyncEfErgo Path Desk [(Path, Maybe Mime)] - | SyncEfOgre Path Desk - deriving (Eq, Ord, Show) - -deriveNoun ''SyncEf - - --- Timer Effects --------------------------------------------------------------- - -{-| - %doze -- Set or clear timer. - %void -- Nasty hack to make the parser not treat this as a record. --} -data BehnEf - = BehnEfDoze (KingId, ()) (Maybe Wen) - | BehnEfVoid Void - deriving (Eq, Ord, Show) - -deriveNoun ''BehnEf - - --- Terminal Effects ------------------------------------------------------------ - -{-| - %bel -- TODO - %clr -- TODO - %hop -- TODO - %lin -- TODO - %mor -- TODO - %sag -- TODO - %sav -- TODO - %url -- TODO --} -data Blit - = Bel () - | Clr () - | Hop HopTarget - | Klr Stub - | Put [Char] - | Nel () - | Sag Path Noun - | Sav Path Atom - | Url Cord - | Wyp () - --TMP backwards compatibility - | Lin [Char] - | Mor () - deriving (Eq, Ord) - ---NOTE bottom-left-0-based coordinates -data HopTarget - = Col Word64 - | Roc Word64 Word64 -- row, col - deriving (Eq, Ord, Show) - -data Deco - = DecoBl - | DecoBr - | DecoUn - | DecoNull - deriving (Eq, Ord, Show) - -data Tint - = TintR - | TintG - | TintB - | TintC - | TintM - | TintY - | TintK - | TintW - | TintNull - | TintTrue Word8 Word8 Word8 - deriving (Eq, Ord, Show) - -data Stye = Stye - { deco :: (HoonSet Deco) - , back :: Tint - , fore :: Tint - } - deriving (Eq, Ord, Show) - -newtype Stub = Stub [(Stye, [Char])] - deriving (Eq, Ord, Show) - -instance ToNoun Deco where - toNoun = \case - DecoBl -> toNoun $ Cord "bl" - DecoBr -> toNoun $ Cord "br" - DecoUn -> toNoun $ Cord "un" - DecoNull -> Atom 0 - -instance FromNoun Deco where - parseNoun = named "Deco" . \case - Atom 0 -> pure DecoNull - n -> parseNoun @Cord n <&> unCord >>= \case - "bl" -> pure DecoBl - "br" -> pure DecoBr - "un" -> pure DecoUn - t -> fail ("invalid: " <> unpack t) - -instance ToNoun Tint where - toNoun = \case - TintR -> toNoun $ Cord "r" - TintG -> toNoun $ Cord "g" - TintB -> toNoun $ Cord "b" - TintC -> toNoun $ Cord "c" - TintM -> toNoun $ Cord "m" - TintY -> toNoun $ Cord "y" - TintK -> toNoun $ Cord "k" - TintW -> toNoun $ Cord "w" - TintNull -> Atom 0 - TintTrue r g b -> Cell (atom r) $ Cell (atom g) (atom b) - where atom a = Atom (fromIntegral a :: Natural) - -instance FromNoun Tint where - parseNoun = named "Tint" . \case - Atom 0 -> pure TintNull - Cell (Atom r) (Cell (Atom g) (Atom b)) - -> pure (TintTrue (word r) (word g) (word b)) - where word w = fromIntegral w :: Word8 - n -> parseNoun @Cord n <&> unCord >>= \case - "r" -> pure TintR - "g" -> pure TintG - "b" -> pure TintB - "c" -> pure TintC - "m" -> pure TintM - "y" -> pure TintY - "k" -> pure TintK - "w" -> pure TintW - t -> fail ("invalid: " <> unpack t) - -instance FromNoun HopTarget where - parseNoun = \case - A c -> pure $ Col (fromIntegral c) - C (A r) (A c) -> pure $ Roc (fromIntegral r) (fromIntegral c) - n -> fail ("invalid hop target: " <> show n) - -instance ToNoun HopTarget where - toNoun = \case - Col c -> A (fromIntegral c) - Roc r c -> C (A (fromIntegral r)) (A (fromIntegral c)) - --- Manual instance to not save the noun/atom in Sag/Sav, because these can be --- megabytes and makes king hang. -instance Show Blit where - show (Bel ()) = "Bel ()" - show (Clr ()) = "Clr ()" - show (Hop t) = "Hop " ++ (show t) - show (Klr s) = "Klr " ++ (show s) - show (Put c) = "Put " ++ (show c) - show (Nel ()) = "Nel ()" - show (Sag path _) = "Sag " ++ (show path) - show (Sav path _) = "Sav " ++ (show path) - show (Url c) = "Url " ++ (show c) - show (Wyp ()) = "Wyp ()" - -- - show (Lin c) = "Lin " ++ (show c) - show (Mor ()) = "Mor ()" - -{-| - %blip -- TODO - %init -- TODO - %logo -- Shutdown - %mass -- Measure memory usage (unused) --} -data TermEf - = TermEfBlit (UD, ()) [Blit] - | TermEfInit (UD, ()) Ship - | TermEfLogo Path () - | TermEfMass Path Noun -- Irrelevant - deriving (Eq, Ord, Show) - -deriveNoun ''Stye -deriveNoun ''Stub -deriveNoun ''Blit -deriveNoun ''TermEf - - --- IO-Driver Routing ----------------------------------------------------------- - -data VaneEf - = VENewt NewtEf - | VEHttpClient HttpClientEf - | VEHttpServer HttpServerEf - | VEBehn BehnEf - | VETerm TermEf - | VEClay SyncEf - | VESync SyncEf - | VEBoat SyncEf - deriving (Eq, Ord, Show) - -deriveNoun ''VaneEf - - --- Top-Level Ef Type ----------------------------------------------------------- - -data Ef - = EfVane VaneEf - | EfVega Cord EvilPath -- second path component, rest of path - | EfExit Cord EvilPath -- second path component, rest of path - | EfWend Wynn - deriving (Eq, Ord, Show) - --- XX HACK -clip :: Noun -> Noun -clip (C (C _ x) y) = C x y -clip _ = error "misclip" - -tack :: Noun -> Noun -tack (C x y) = C (C (A 0) x) y -tack _ = error "mistack" - -instance ToNoun Ef where - toNoun = clip . \case - EfVane v -> toNoun $ reorgThroughNoun ("", v) - EfExit s p -> toNoun $ ReOrg "" s "exit" p (A 0) - EfVega s p -> toNoun $ ReOrg "" s "vega" p (A 0) - EfWend w -> toNoun $ reorgThroughNoun ("", w) - -instance FromNoun Ef where - parseNoun = tack >>> parseNoun >=> \case - ReOrg "" s "exit" p (A 0) -> pure (EfExit s p) - ReOrg "" s "exit" p _ -> fail "%exit effect expects nil value" - ReOrg "" s "vega" p (A 0) -> pure (EfVega s p) - ReOrg "" s "vega" p _ -> fail "%vega effect expects nil value" - ReOrg "" s "wend" p val -> EfWend <$> parseNoun val - ReOrg "" s tag p val -> EfVane <$> parseNoun (toNoun (s, tag, p, val)) - ReOrg _ _ _ _ _ -> fail "Non-empty first path-element" - -summarizeEffect :: Lenient Ef -> Text -summarizeEffect ef = - fromNoun (toNoun ef) & \case - Nothing -> "//invalid %effect" - Just (pax :: [Cord], tag :: Cord, val :: Noun) -> - "/" <> intercalate "/" (unCord <$> pax) <> " %" <> unCord tag diff --git a/pkg/hs/urbit-king/lib/Urbit/Arvo/Event.hs b/pkg/hs/urbit-king/lib/Urbit/Arvo/Event.hs deleted file mode 100644 index 50ef1ac1f..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Arvo/Event.hs +++ /dev/null @@ -1,452 +0,0 @@ -{-# LANGUAGE StrictData #-} - --- This is required due to the use of 'Void' in a constructor slot in --- combination with 'deriveNoun' which generates an unreachable pattern. -{-# OPTIONS_GHC -Wno-overlapping-patterns #-} - -{-| - Event Types and Noun Conversion --} -module Urbit.Arvo.Event where - -import Urbit.Prelude - -import Control.Monad.Fail (fail) -import Urbit.Arvo.Common (KingId(..), ServId(..), Vere(..)) -import Urbit.Arvo.Common (Desk, Mime) -import Urbit.Arvo.Common (Header(..), HttpEvent) -import Urbit.Arvo.Common (AmesDest, Ipv4, Ipv6, Port, Turf) -import Urbit.Arvo.Common (ReOrg(..), reorgThroughNoun) - -import qualified Crypto.Sign.Ed25519 as Ed -import qualified Data.ByteString as BS -import qualified Data.Char as C -import qualified Data.ByteString.Char8 as C -import qualified Network.HTTP.Types.Method as H - --- Misc Types ------------------------------------------------------------------ - -type Rift = Atom -- Continuity number -type Life = Word -- Number of Azimoth key revs. -type Bloq = Atom -- TODO -type Oath = Atom -- Signature - - --- Parsed URLs ----------------------------------------------------------------- - -type Host = Each Turf Ipv4 -type Hart = (Bool, Maybe Atom, Host) -type Pork = (Maybe Knot, [Cord]) -type Quay = [(Cord, Cord)] - -data PUrl = PUrl Hart Pork Quay - deriving (Eq, Ord, Show) - -deriveNoun ''PUrl - - --- Dawn Records ---------------------------------------------------------------- - -padByteString :: BS.ByteString -> Int -> BS.ByteString -padByteString bs length | remaining > 0 = bs <> (BS.replicate remaining 0) - | otherwise = bs - where remaining = (length - (BS.length bs)) - --- A Pass is the Atom concatenation of 'b', the public encryption key, and the --- public authentication key. (see +pass-from-eth.) -data Pass = Pass { passSign :: Ed.PublicKey, passCrypt :: Ed.PublicKey } - deriving (Eq, Ord, Show) - -passToBS :: Pass -> BS.ByteString -passToBS Pass{..} = C.singleton 'b' <> - (Ed.unPublicKey passSign) <> - (Ed.unPublicKey passCrypt) - -instance ToNoun Pass where - toNoun = Atom . bytesAtom . passToBS - -instance FromNoun Pass where - parseNoun n = named "Pass" $ do - MkBytes unpadded <- parseNoun n - let bs = padByteString unpadded 65 - when ((C.head bs) /= 'b') $ do - fail "Expecting 'b' prefix in public key structure" - let removedPrefix = C.tail bs - let passSign = Ed.PublicKey (take 32 removedPrefix) - let passCrypt = Ed.PublicKey (drop 32 removedPrefix) - unless ((length $ Ed.unPublicKey passSign) == 32) $ - error "Sign pubkey not 32 bytes" - unless ((length $ Ed.unPublicKey passCrypt) == 32) $ - error "Crypt pubkey not 32 bytes" - pure $ Pass{..} - --- A Ring isn't the secret keys: it's the ByteString input which generates both --- the public key and the secret key. A Ring is the concatenation of 'B', the --- encryption key derivation seed, and the authentication key derivation --- seed. These aren't actually private keys, but public/private keypairs which --- can be derived from these seeds. -data Ring = Ring { ringSign :: BS.ByteString, ringCrypt :: BS.ByteString } - deriving (Eq, Ord) - -instance ToNoun Ring where - toNoun Ring{..} = - Atom $ bytesAtom (C.singleton 'B' <> ringSign <> ringCrypt) - -instance FromNoun Ring where - parseNoun n = named "Ring" $ do - MkBytes unpadded <- parseNoun n - let bs = padByteString unpadded 65 - when ((C.head bs) /= 'B') $ do - fail "Expecting 'B' prefix in public key structure" - let removedPrefix = C.tail bs - let ringSign = (take 32 removedPrefix) - let ringCrypt = (drop 32 removedPrefix) - unless ((length ringSign) == 32) $ - error "Sign seed not 32 bytes" - unless ((length ringCrypt) == 32) $ - error "Crypt seed not 32 bytes" - pure $ Ring ringSign ringCrypt - -instance Show Ring where - show r = "(Ring <> <>)" - -data Seed = Seed - { sShip :: Ship - , sLife :: Life - , sRing :: Ring - , sOath :: (Maybe Oath) - } - deriving (Eq, Show) - -data Germs = Germs - { gShip :: Ship - , gFeed :: [Germ] - } - deriving (Eq, Show) - -data Germ = Germ - { gLife :: Life - , gRing :: Ring - } - deriving (Eq, Ord, Show) - -data Feed - = Feed0 Seed - | Feed1 Germs - deriving (Eq, Show) - --- NOTE reify type environment -$(pure []) - -instance ToNoun Feed where - toNoun = \case - Feed0 s -> $(deriveToNounFunc ''Seed) s - Feed1 s -> C (C (A 1) (A 0)) $ $(deriveToNounFunc ''Germs) s - -instance FromNoun Feed where - parseNoun = \case - (C (C (A 1) (A 0)) s) -> Feed1 <$> $(deriveFromNounFunc ''Germs) s - n -> Feed0 <$> $(deriveFromNounFunc ''Seed) n - -type Public = (Life, HoonMap Life Pass) - -data Dnses = Dnses { dPri::Cord, dSec::Cord, dTer::Cord } - deriving (Eq, Ord, Show) - -type EthAddr = Atom --Bytes -- 20 bytes -type ContNum = Word - -data EthPoint = EthPoint - { epOwn :: (EthAddr, EthAddr, EthAddr, EthAddr) - , epNet :: Maybe (Life, Pass, ContNum, (Bool, Ship), Maybe Ship) - , epKid :: Maybe (EthAddr, HoonSet Ship) - } - deriving (Eq, Show) - -data Dawn = MkDawn - { dSeed :: Seed - , dSponsor :: [(Ship, EthPoint)] - , dCzar :: HoonMap Ship (Rift, Life, Pass) - , dTurf :: [Turf] - , dBloq :: Bloq - , dNode :: (Maybe PUrl) - } - deriving (Eq, Show) - -deriveNoun ''Dnses -deriveNoun ''EthPoint -deriveNoun ''Seed -deriveNoun ''Germ -deriveNoun ''Dawn - - --- HTTP ------------------------------------------------------------------------ - -type ServerId = Atom - -data Address - = AIpv4 Ipv4 - | AIpv6 Ipv6 - | AAmes Ship - deriving (Eq, Ord, Show) - -data HttpRequest = HttpRequest - { reqMeth :: H.StdMethod - , reqUrl :: Cord - , reqHead :: [Header] - , reqBody :: Maybe File - } - deriving (Eq, Ord, Show) - -data HttpServerReq = HttpServerReq - { hsrSecure :: Bool - , hsrAddress :: Address - , hsrRequest :: HttpRequest - } - deriving (Eq, Ord, Show) - -data HttpClientEv - = HttpClientEvReceive (KingId, ()) ServerId HttpEvent - | HttpClientEvBorn (KingId, ()) () - | HttpClientEvCrud Path Noun - deriving (Eq, Ord, Show) - -data HttpServerEv - = HttpServerEvRequest (ServId, UD, UD, ()) HttpServerReq - | HttpServerEvCancelRequest (ServId, UD, UD, ()) () - | HttpServerEvRequestLocal (ServId, UD, UD, ()) HttpServerReq - | HttpServerEvLive (ServId, ()) Port (Maybe Port) - | HttpServerEvBorn (KingId, ()) () - | HttpServerEvCrud Path Noun - deriving (Eq, Ord, Show) - -deriveNoun ''Address -deriveNoun ''HttpClientEv -deriveNoun ''HttpRequest -deriveNoun ''HttpServerEv -deriveNoun ''HttpServerReq - - --- Ames ------------------------------------------------------------------------ - -data AmesEv - = AmesEvHear () AmesDest Bytes - | AmesEvHole () AmesDest Bytes - | AmesEvCrud Path Noun - deriving (Eq, Ord, Show) - -deriveNoun ''AmesEv - - --- Arvo Events ----------------------------------------------------------------- - -newtype Entropy = Entropy { entropyBits :: Word512 } - deriving newtype (Eq, Ord, FromNoun, ToNoun) - -instance Show Entropy where - show = const "\"ENTROPY (secret)\"" - - -data ArvoEv - = ArvoEvWhom () Ship - | ArvoEvWack () Entropy - | ArvoEvWyrd () Vere - | ArvoEvCrud Path Noun - | ArvoEvTrim UD - | ArvoEvWhat [Noun] - | ArvoEvWhey () - | ArvoEvVerb (Maybe Bool) - deriving (Eq, Ord, Show) - -deriveNoun ''ArvoEv - - --- Boat Events ----------------------------------------------------------------- - -data BoatEv - = BoatEvBoat () () - | BoatEvCrud Path Noun - deriving (Eq, Ord, Show) - -deriveNoun ''BoatEv - - --- Jael Events ----------------------------------------------------------------- - -data JaelEv - = JaelEvRekey () (Life, Ring) - | JaelEvCrud Path Noun - deriving (Eq, Show) - -deriveNoun ''JaelEv - - --- Timer Events ---------------------------------------------------------------- - -data BehnEv - = BehnEvWake () () - | BehnEvBorn (KingId, ()) () - | BehnEvCrud Path Noun - deriving (Eq, Ord, Show) - -deriveNoun ''BehnEv - - --- Newt Events ----------------------------------------------------------------- - -data NewtEv - = NewtEvBorn (KingId, ()) () - | NewtEvCrud Path Noun - deriving (Eq, Ord, Show) - -deriveNoun ''NewtEv - - --- FileSystem Events ----------------------------------------------------------- - -data SyncEv - = SyncEvInto (Nullable (KingId, ())) Desk Bool [(Path, Maybe Mime)] - | SyncEvCrud Path Noun - deriving (Eq, Ord, Show) - -deriveNoun ''SyncEv - - --- Terminal Events ------------------------------------------------------------- - -data LegacyBootEvent - = Fake Ship - | Dawn Dawn - deriving (Eq, Show) - -data Bolt - = Key Char - | Aro ArrowKey - | Bac () - | Del () - | Hit Word64 Word64 - | Ret () - deriving (Eq, Ord, Show) - -data Belt - = Bol Bolt - | Mod Modifier Bolt - | Txt Tour - deriving (Eq, Ord, Show) - -data ArrowKey = D | L | R | U - deriving (Eq, Ord, Show) - -data Modifier = Ctl | Met | Hyp - deriving (Eq, Ord, Show) - ---NOTE required to get the above declarations into reify's type environment --- see also ghc/ghc#9813 -$(pure []) - -instance FromNoun Bolt where - parseNoun = \case - A c -> pure $ Key $ C.chr $ fromIntegral c - C (A 7955819) _ -> fail "%key not valid bolt tag" - n -> $(deriveFromNounFunc ''Bolt) n - -instance FromNoun Belt where - parseNoun = \case - C (A 7106402) _ -> fail "%bol not valid belt tag" - n -> Bol <$> parseNoun n <|> $(deriveFromNounFunc ''Belt) n - -instance ToNoun Bolt where - toNoun = \case - Key c -> A $ fromIntegral $ C.ord c - n -> $(deriveToNounFunc ''Bolt) n - -instance ToNoun Belt where - toNoun = \case - Bol b -> toNoun b - n -> $(deriveToNounFunc ''Belt) n - -data TermEv - = TermEvBelt (UD, ()) Belt - | TermEvBlew (UD, ()) Word Word - | TermEvBoot (UD, ()) Bool LegacyBootEvent - | TermEvHail (UD, ()) () - | TermEvCrud Path Noun - deriving (Eq, Show) - -deriveNoun ''LegacyBootEvent -deriveNoun ''ArrowKey -deriveNoun ''Modifier -deriveNoun ''TermEv - - --- Events for Device Drivers --------------------------------------------------- - -data BlipEv - = BlipEvAmes AmesEv - | BlipEvArvo ArvoEv - | BlipEvBehn BehnEv - | BlipEvBoat BoatEv - | BlipEvHttpClient HttpClientEv - | BlipEvHttpServer HttpServerEv - | BlipEvJael JaelEv - | BlipEvNewt NewtEv - | BlipEvSync SyncEv - | BlipEvTerm TermEv - deriving (Eq, Show) - -deriveNoun ''BlipEv - - --- The Main Event Type --------------------------------------------------------- - -data Ev - = EvBlip BlipEv - deriving (Eq, Show) - -instance ToNoun Ev where - toNoun = toNoun . \case - EvBlip v@BlipEvAmes{} -> reorgThroughNoun ("ames", v) - EvBlip v@BlipEvArvo{} -> reorgThroughNoun ("", v) - EvBlip v@BlipEvBehn{} -> reorgThroughNoun ("behn", v) - EvBlip v@BlipEvBoat{} -> reorgThroughNoun ("clay", v) - EvBlip v@BlipEvHttpClient{} -> reorgThroughNoun ("iris", v) - EvBlip v@BlipEvHttpServer{} -> reorgThroughNoun ("eyre", v) - EvBlip v@BlipEvJael{} -> reorgThroughNoun ("jael", v) - EvBlip v@BlipEvNewt{} -> reorgThroughNoun ("ames", v) - EvBlip v@BlipEvSync{} -> reorgThroughNoun ("clay", v) - EvBlip v@BlipEvTerm{} -> reorgThroughNoun ("dill", v) - --- XX We really should check the first path element, but since this is used only --- in the event browser, which otherwise is broken, I don't care right now. -instance FromNoun Ev where - parseNoun = parseNoun >=> \case - ReOrg _ s t p v -> fmap EvBlip $ parseNoun $ toNoun (s,t,p,v) - - --- Short Event Names ----------------------------------------------------------- - -{- - In the case of user input, the cause is technically a terminal event, - but we don't display any name because the cause is really the user. --} -getSpinnerNameForEvent :: Ev -> Maybe Text -getSpinnerNameForEvent = \case - EvBlip b -> case b of - BlipEvAmes _ -> Just "ames" - BlipEvArvo _ -> Just "arvo" - BlipEvBehn _ -> Just "behn" - BlipEvBoat _ -> Just "boat" - BlipEvHttpClient _ -> Just "iris" - BlipEvHttpServer _ -> Just "eyre" - BlipEvJael _ -> Just "jael" - BlipEvNewt _ -> Just "newt" - BlipEvSync _ -> Just "clay" - BlipEvTerm (TermEvBelt _ _) -> Nothing - BlipEvTerm t -> Just "term" - -summarizeEvent :: Ev -> Text -summarizeEvent ev = - fromNoun (toNoun ev) & \case - Nothing -> "//invalid %event" - Just (pax :: [Cord], tag :: Cord, val :: Noun) -> - "/" <> intercalate "/" (unCord <$> pax) <> " %" <> unCord tag diff --git a/pkg/hs/urbit-king/lib/Urbit/King/API.hs b/pkg/hs/urbit-king/lib/Urbit/King/API.hs deleted file mode 100644 index 61bf31dfe..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/King/API.hs +++ /dev/null @@ -1,141 +0,0 @@ -{-| - TODO This has a bunch of stub logic that was intended for an - architecture with a single Urbit daemon running multiple - ships. Do it or strip it out. --} - -module Urbit.King.API - ( King(..) - , TermConn - , TermConnAPI - , kingAPI - , readPortsFile - ) -where - -import RIO.Directory -import Urbit.Prelude - -import Network.Socket (Socket) -import Prelude (read) -import Urbit.King.App (HasPierPath(..)) - -import qualified Network.HTTP.Types as H -import qualified Network.Wai as W -import qualified Network.Wai.Handler.Warp as W -import qualified Network.Wai.Handler.WebSockets as WS -import qualified Network.WebSockets as WS -import qualified Urbit.Vere.NounServ as NounServ -import qualified Urbit.Vere.Term.API as Term - - --- Types ----------------------------------------------------------------------- - -type TermConn = NounServ.Conn Term.ClientTake [Term.Ev] - -type TermConnAPI = TVar (Maybe (TermConn -> STM ())) - -{-| - Daemon state. --} -data King = King - { kServer :: Async () - , kTermConn :: TermConnAPI - } - - --------------------------------------------------------------------------------- - -{-| - Get the filepath of the urbit config directory and the ports file. --} -portsFilePath :: HasPierPath e => RIO e (FilePath, FilePath) -portsFilePath = do - dir <- view pierPathL - fil <- pure (dir ".king.ports") - pure (dir, fil) - -{-| - Write the ports file. --} -portsFile :: HasPierPath e => Word -> RAcquire e (FilePath, FilePath) -portsFile por = - mkRAcquire mkFile (removeFile . snd) - where - mkFile = do - (dir, fil) <- portsFilePath - createDirectoryIfMissing True dir - writeFile fil (encodeUtf8 $ tshow por) - pure (dir, fil) - -{-| - Get the HTTP port for the running Urbit daemon. --} -readPortsFile :: HasPierPath e => RIO e (Maybe Word) -readPortsFile = do - (_, fil) <- portsFilePath - bs <- readFile fil - evaluate (readMay $ unpack $ decodeUtf8 bs) - -kingServer :: HasLogFunc e => (Int, Socket) -> RAcquire e King -kingServer is = - mkRAcquire (startKing is) (cancel . kServer) - where - startKing :: HasLogFunc e => (Int, Socket) -> RIO e King - startKing (port, sock) = do - api <- newTVarIO Nothing - let opts = W.defaultSettings & W.setPort port - env <- ask - tid <- async $ io $ W.runSettingsSocket opts sock $ app env api - pure (King tid api) - -{-| - Start the HTTP server and write to the ports file. --} -kingAPI :: (HasPierPath e, HasLogFunc e) - => RAcquire e King -kingAPI = do - (port, sock) <- io $ W.openFreePort - (dir, fil) <- portsFile (fromIntegral port) - -- lockFile dir - kingServer (port, sock) - -serveTerminal :: HasLogFunc e => e -> TermConnAPI -> Word -> W.Application -serveTerminal env api word = - WS.websocketsOr WS.defaultConnectionOptions wsApp fallback - where - fallback req respond = - respond $ W.responseLBS H.status500 [] - $ "This endpoint uses websockets" - - wsApp pen = - atomically (readTVar api) >>= \case - Nothing -> WS.rejectRequest pen "Ship not running" - Just sp -> do - wsc <- io $ WS.acceptRequest pen - inp <- io $ newTBMChanIO 5 - out <- io $ newTBMChanIO 5 - atomically $ sp $ NounServ.mkConn inp out - let doit = runRIO env - $ NounServ.wsConn "NOUNSERV (wsServ) " inp out wsc - - -- If `wai` kills this thread for any reason, the TBMChans - -- need to be closed. If they are not closed, the - -- terminal will not know that they disconnected. - finally doit $ atomically $ do - closeTBMChan inp - closeTBMChan out - -data BadShip = BadShip Text - deriving (Show, Exception) - -app :: HasLogFunc e => e -> TermConnAPI -> W.Application -app env api req respond = - case W.pathInfo req of - ["terminal", session] -> do - session :: Word <- evaluate $ read $ unpack session - serveTerminal env api session req respond - ["status"] -> - respond $ W.responseLBS H.status200 [] "{}" - _ -> - respond $ W.responseLBS H.status404 [] "No implemented" diff --git a/pkg/hs/urbit-king/lib/Urbit/King/App.hs b/pkg/hs/urbit-king/lib/Urbit/King/App.hs deleted file mode 100644 index 7c2ac9f9e..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/King/App.hs +++ /dev/null @@ -1,296 +0,0 @@ -{-| - Code for setting up the RIO environment. --} -module Urbit.King.App - ( KingEnv - , runKingEnvStderr - , runKingEnvStderrRaw - , runKingEnvLogFile - , runKingEnvNoLog - , kingEnvKillSignal - , killKingActionL - , onKillKingSigL - , HostEnv - , runHostEnv - , PierEnv - , runPierEnv - , killPierActionL - , onKillPierSigL - , HasStderrLogFunc(..) - , HasKingId(..) - , HasProcId(..) - , HasKingEnv(..) - , HasMultiEyreApi(..) - , HasHostEnv(..) - , HasPierEnv(..) - , module Urbit.King.Config - ) -where - -import Urbit.King.Config -import Urbit.Prelude - -import RIO (logGeneric) -import System.Directory ( createDirectoryIfMissing - , getXdgDirectory - , XdgDirectory(XdgCache) - ) -import System.Posix.Internals (c_getpid) -import System.Posix.Types (CPid(..)) -import System.Random (randomIO) -import Urbit.King.App.Class (HasStderrLogFunc(..)) -import Urbit.Vere.Eyre.Multi (MultiEyreApi) -import Urbit.Vere.Ports (PortControlApi, HasPortControlApi(..)) - - --- KingEnv --------------------------------------------------------------------- - -class HasKingId a where - kingIdL :: Lens' a Word16 - -class HasProcId a where - procIdL :: Lens' a Int32 - -class (HasLogFunc a, HasStderrLogFunc a, HasKingId a, HasProcId a) - => HasKingEnv a - where - kingEnvL :: Lens' a KingEnv - -data KingEnv = KingEnv - { _kingEnvLogFunc :: !LogFunc - , _kingEnvStderrLogFunc :: !LogFunc - , _kingEnvKingId :: !Word16 - , _kingEnvProcId :: !Int32 - , _kingEnvKillSignal :: !(TMVar ()) - } - -makeLenses ''KingEnv - -instance HasKingEnv KingEnv where - kingEnvL = id - -instance HasLogFunc KingEnv where - logFuncL = kingEnvLogFunc - -instance HasStderrLogFunc KingEnv where - stderrLogFuncL = kingEnvStderrLogFunc - -instance HasProcId KingEnv where - procIdL = kingEnvProcId - -instance HasKingId KingEnv where - kingIdL = kingEnvKingId - --- Running KingEnvs ------------------------------------------------------------ - -runKingEnvStderr :: Bool -> LogLevel -> RIO KingEnv a -> IO a -runKingEnvStderr verb lvl inner = do - logOptions <- - logOptionsHandle stderr verb - <&> setLogUseTime True - <&> setLogUseLoc False - <&> setLogMinLevel lvl - withLogFunc logOptions $ \logFunc -> runKingEnv logFunc logFunc inner - -runKingEnvStderrRaw :: Bool -> LogLevel -> RIO KingEnv a -> IO a -runKingEnvStderrRaw verb lvl inner = do - logOptions <- - logOptionsHandle stderr verb - <&> setLogUseTime True - <&> setLogUseLoc False - <&> setLogMinLevel lvl - withLogFunc logOptions $ \logFunc -> - let lf = wrapCarriage logFunc - in runKingEnv lf lf inner - --- XX loses callstack -wrapCarriage :: LogFunc -> LogFunc -wrapCarriage lf = mkLogFunc $ \_ ls ll bldr -> - runRIO lf $ logGeneric ls ll (bldr <> "\r") - -runKingEnvLogFile :: Bool -> LogLevel -> Maybe FilePath -> RIO KingEnv a -> IO a -runKingEnvLogFile verb lvl fileM inner = do - logFile <- case fileM of - Just f -> pure f - Nothing -> defaultLogFile - withLogFileHandle logFile $ \h -> do - logOptions <- - logOptionsHandle h verb - <&> setLogUseTime True - <&> setLogUseLoc False - <&> setLogMinLevel lvl - stderrLogOptions <- - logOptionsHandle stderr verb - <&> setLogUseTime False - <&> setLogUseLoc False - <&> setLogMinLevel lvl - withLogFunc stderrLogOptions $ \stderrLogFunc -> withLogFunc logOptions - $ \logFunc -> runKingEnv logFunc stderrLogFunc inner - -withLogFileHandle :: FilePath -> (Handle -> IO a) -> IO a -withLogFileHandle f act = - withFile f AppendMode $ \handle -> do - hSetBuffering handle LineBuffering - act handle - -defaultLogFile :: IO FilePath -defaultLogFile = do - logDir <- getXdgDirectory XdgCache "urbit" - createDirectoryIfMissing True logDir - logId :: Word32 <- randomIO - pure (logDir "king-" <> show logId <> ".log") - -runKingEnvNoLog :: RIO KingEnv a -> IO a -runKingEnvNoLog act = runKingEnv mempty mempty act - -runKingEnv :: LogFunc -> LogFunc -> RIO KingEnv a -> IO a -runKingEnv logFunc stderr action = do - kid <- randomIO - CPid pid <- c_getpid - kil <- newEmptyTMVarIO - runRIO (KingEnv logFunc stderr kid pid kil) action - - --- KingEnv Utils --------------------------------------------------------------- - -onKillKingSigL :: HasKingEnv e => Getter e (STM ()) -onKillKingSigL = kingEnvL . kingEnvKillSignal . to readTMVar - -killKingActionL :: HasKingEnv e => Getter e (STM ()) -killKingActionL = - kingEnvL . kingEnvKillSignal . to (\kil -> void (tryPutTMVar kil ())) - --- HostEnv ------------------------------------------------------------------ - --- The host environment is everything in King, eyre configuration shared --- across ships, and nat punching data. - -class HasMultiEyreApi a where - multiEyreApiL :: Lens' a MultiEyreApi - -class (HasKingEnv a, HasMultiEyreApi a, HasPortControlApi a) => - HasHostEnv a where - hostEnvL :: Lens' a HostEnv - -data HostEnv = HostEnv - { _hostEnvKingEnv :: !KingEnv - , _hostEnvMultiEyreApi :: !MultiEyreApi - , _hostEnvPortControlApi :: !PortControlApi - } - -makeLenses ''HostEnv - -instance HasKingEnv HostEnv where - kingEnvL = hostEnvKingEnv - -instance HasLogFunc HostEnv where - logFuncL = kingEnvL . logFuncL - -instance HasStderrLogFunc HostEnv where - stderrLogFuncL = kingEnvL . stderrLogFuncL - -instance HasProcId HostEnv where - procIdL = kingEnvL . procIdL - -instance HasKingId HostEnv where - kingIdL = kingEnvL . kingEnvKingId - -instance HasMultiEyreApi HostEnv where - multiEyreApiL = hostEnvMultiEyreApi - -instance HasPortControlApi HostEnv where - portControlApiL = hostEnvPortControlApi - --- Running Running Envs -------------------------------------------------------- - -runHostEnv :: MultiEyreApi -> PortControlApi -> RIO HostEnv a - -> RIO KingEnv a -runHostEnv multi ports action = do - king <- ask - - let hostEnv = HostEnv { _hostEnvKingEnv = king - , _hostEnvMultiEyreApi = multi - , _hostEnvPortControlApi = ports - } - - io (runRIO hostEnv action) - --- PierEnv --------------------------------------------------------------------- - -class (HasKingEnv a, HasHostEnv a, HasPierConfig a, HasNetworkConfig a) => - HasPierEnv a where - pierEnvL :: Lens' a PierEnv - -data PierEnv = PierEnv - { _pierEnvHostEnv :: !HostEnv - , _pierEnvPierConfig :: !PierConfig - , _pierEnvNetworkConfig :: !NetworkConfig - , _pierEnvKillSignal :: !(TMVar ()) - } - -makeLenses ''PierEnv - -instance HasKingEnv PierEnv where - kingEnvL = pierEnvHostEnv . kingEnvL - -instance HasHostEnv PierEnv where - hostEnvL = pierEnvHostEnv - -instance HasMultiEyreApi PierEnv where - multiEyreApiL = pierEnvHostEnv . multiEyreApiL - -instance HasPortControlApi PierEnv where - portControlApiL = pierEnvHostEnv . portControlApiL - -instance HasPierEnv PierEnv where - pierEnvL = id - -instance HasKingId PierEnv where - kingIdL = kingEnvL . kingEnvKingId - -instance HasStderrLogFunc PierEnv where - stderrLogFuncL = kingEnvL . stderrLogFuncL - -instance HasLogFunc PierEnv where - logFuncL = kingEnvL . logFuncL - -instance HasPierPath PierEnv where - pierPathL = pierEnvPierConfig . pierPathL - -instance HasDryRun PierEnv where - dryRunL = pierEnvPierConfig . dryRunL - -instance HasPierConfig PierEnv where - pierConfigL = pierEnvPierConfig - -instance HasNetworkConfig PierEnv where - networkConfigL = pierEnvNetworkConfig - -instance HasProcId PierEnv where - procIdL = kingEnvL . kingEnvProcId - - --- PierEnv Utils --------------------------------------------------------------- - -onKillPierSigL :: HasPierEnv e => Getter e (STM ()) -onKillPierSigL = pierEnvL . pierEnvKillSignal . to readTMVar - -killPierActionL :: HasPierEnv e => Getter e (STM ()) -killPierActionL = - pierEnvL . pierEnvKillSignal . to (\kil -> void (tryPutTMVar kil ())) - - --- Running Pier Envs ----------------------------------------------------------- - -runPierEnv - :: PierConfig -> NetworkConfig -> TMVar () -> RIO PierEnv a -> RIO HostEnv a -runPierEnv pierConfig networkConfig vKill action = do - host <- ask - - let pierEnv = PierEnv { _pierEnvHostEnv = host - , _pierEnvPierConfig = pierConfig - , _pierEnvNetworkConfig = networkConfig - , _pierEnvKillSignal = vKill - } - - io (runRIO pierEnv action) diff --git a/pkg/hs/urbit-king/lib/Urbit/King/App/Class.hs b/pkg/hs/urbit-king/lib/Urbit/King/App/Class.hs deleted file mode 100644 index c4a4ec08b..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/King/App/Class.hs +++ /dev/null @@ -1,15 +0,0 @@ -{-| - Code for setting up the RIO environment. --} -module Urbit.King.App.Class - ( HasStderrLogFunc(..) - ) -where - -import Urbit.Prelude - - --- KingEnv --------------------------------------------------------------------- - -class HasStderrLogFunc a where - stderrLogFuncL :: Lens' a LogFunc diff --git a/pkg/hs/urbit-king/lib/Urbit/King/CLI.hs b/pkg/hs/urbit-king/lib/Urbit/King/CLI.hs deleted file mode 100644 index 5c1d16fb9..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/King/CLI.hs +++ /dev/null @@ -1,594 +0,0 @@ -{-# OPTIONS_GHC -Werror -Wall #-} -{-# LANGUAGE CPP #-} - -{-| - Command line parsing. --} -module Urbit.King.CLI where - -import Urbit.Prelude hiding (log, Parser) -import Options.Applicative -import Options.Applicative.Help.Pretty - -import System.Environment (getProgName) - --------------------------------------------------------------------------------- - -data Host = Host - { hSharedHttpPort :: Maybe Word16 - , hSharedHttpsPort :: Maybe Word16 - , hUseNatPmp :: Nat - , hSerfExe :: Maybe Text - } - deriving (Show) - --- | Options for each running pier. -data Opts = Opts - { oQuiet :: Bool - , oHashless :: Bool - , oExit :: Bool - , oDryRun :: Bool - , oDryFrom :: Maybe Word64 - , oVerbose :: Bool - , oAmesPort :: Maybe Word16 - , oNoAmes :: Bool - , oNoHttp :: Bool - , oNoHttps :: Bool - , oTrace :: Bool - , oCollectFx :: Bool - , oLocalhost :: Bool - , oOffline :: Bool - , oFullReplay :: Bool - , oHttpPort :: Maybe Word16 - , oHttpsPort :: Maybe Word16 - , oLoopbackPort :: Maybe Word16 - , oInjectEvents :: [Injection] - } - deriving (Show) - --- | Options for the logging subsystem. -data Log = Log - { lTarget :: Maybe (LogTarget FilePath) - , lLevel :: LogLevel - } - deriving (Show) - -data LogTarget a - = LogOff - | LogStderr - | LogFile a - deriving (Show) - -data BootType - = BootComet - | BootFake Text - | BootFromKeyfile FilePath - deriving (Show) - -data PillSource - = PillSourceFile FilePath - | PillSourceURL String - deriving (Show) - -data Nat - = NatAlways - | NatWhenPrivateNetwork - | NatNever - deriving (Show) - -data Injection - = InjectOneEvent FilePath - | InjectManyEvents FilePath - deriving (Show) - -data New = New - { nPillSource :: PillSource - , nPierPath :: Maybe FilePath -- Derived from ship name if not specified. - , nArvoDir :: Maybe FilePath - , nBootType :: BootType - , nLite :: Bool - , nEthNode :: String - , nSerfExe :: Maybe Text - } - deriving (Show) - -data Run = Run - { rPierPath :: FilePath - } - deriving (Show) - -data Bug - = ValidatePill - { bPillPath :: FilePath - , bPrintPil :: Bool - , bPrintSeq :: Bool - } - | CollectAllFX - { bPierPath :: FilePath - } - | EventBrowser - { bPierPath :: FilePath - } - | ValidateEvents - { bPierPath :: FilePath - , bFirstEvt :: Word64 - , bFinalEvt :: Word64 - } - | ValidateFX - { bPierPath :: FilePath - , bFirstEvt :: Word64 - , bFinalEvt :: Word64 - } - | ReplayEvents - { bPierPath :: FilePath - , bFinalEvt :: Word64 - } - | CheckDawn - { bEthNode :: String - , bKeyfilePath :: FilePath - } - | CheckComet - deriving (Show) - -data Cmd - = CmdNew New Opts - | CmdRun Host [(Run, Opts, Bool)] - | CmdBug Bug - | CmdCon FilePath - deriving (Show) - --------------------------------------------------------------------------------- - -headNote :: String -> Doc -headNote _version = string $ intercalate "\n" - [ "Urbit: a personal server operating function" - , "https://urbit.org" - , "Version " <> VERSION_urbit_king - ] - --- | TODO This needs to be updated. -footNote :: String -> Doc -footNote exe = string $ intercalate "\n" - [ "Development Usage:" - , " To create a development ship, use a fakezod:" - , " $ " <>exe<> " new zod /path/to/pill -F zod -A arvo/folder" - , "" - , "Simple Usage: " - , " $ " <>exe<> " new pier to create a comet (anonymous urbit)" - , " $ " <>exe<> " new pier -k if you own a planet" - , " $ " <>exe<> " run to restart an existing urbit" - , "" - , "For more information about developing on urbit, see:" - , " https://github.com/urbit/urbit/blob/master/CONTRIBUTING.md" - ] - --------------------------------------------------------------------------------- - -parseArgs :: IO (Cmd, Log) -parseArgs = do - nm <- getProgName - - let p = prefs $ showHelpOnError - <> showHelpOnEmpty - <> columns 80 - - let o = info (cmd <**> helper) - $ progDesc "Start an existing Urbit or boot a new one." - <> headerDoc (Just $ headNote "0.9001.0") - <> footerDoc (Just $ footNote nm) - <> fullDesc - - customExecParser p o - --------------------------------------------------------------------------------- - -defaultPillURL :: String -defaultPillURL = "https://bootstrap.urbit.org/urbit-v" <> ver <> ".pill" - where - ver = VERSION_urbit_king - --------------------------------------------------------------------------------- - -newComet :: Parser BootType -newComet = flag' BootComet - ( long "comet" - <> help "Boot a new comet" - ) - -newFakeship :: Parser BootType -newFakeship = BootFake <$> strOption - (short 'F' - <> long "fake" - <> metavar "SHIP" - <> help "Boot a fakeship") - -newFromKeyfile :: Parser BootType -newFromKeyfile = BootFromKeyfile <$> strOption - (short 'k' - <> long "keyfile" - <> metavar "KEYFILE" - <> help "Boot from a keyfile") - -pillFromPath :: Parser PillSource -pillFromPath = PillSourceFile <$> strOption - ( short 'B' - <> long "pill" - <> metavar "PILL" - <> help "Path to pill file") - -pillFromURL :: Parser PillSource -pillFromURL = PillSourceURL <$> strOption - ( short 'u' - <> long "pill-url" - <> metavar "URL" - <> value defaultPillURL - <> help "URL to pill file") - -pierPath :: Parser FilePath -pierPath = strArgument (metavar "PIER" <> help "Path to pier") - -injectEvents :: Parser [Injection] -injectEvents = many $ InjectOneEvent <$> strOption - ( short 'I' - <> long "inject-event" - <> metavar "JAM" - <> help "Path to a jammed event" - <> hidden) - <|> InjectManyEvents <$> strOption - ( long "inject-event-list" - <> metavar "JAM_LIST" - <> help "Path to a jammed list of events" - <> hidden) - -serfExe :: Parser (Maybe Text) -serfExe = optional - $ strOption - $ metavar "PATH" - <> long "serf" - <> help "Path to serf binary to run ships in" - <> hidden - -ethNode :: Parser String -ethNode = strOption - $ short 'e' - <> long "l2-endpoint" - <> value "https://l2.urbit.org/v1/azimuth" --TODO - <> help "Azimuth Layer 2 RPC API endpoint URL" - <> hidden - -new :: Parser New -new = do - nPierPath <- optional pierPath - - nBootType <- newComet <|> newFakeship <|> newFromKeyfile - - nPillSource <- pillFromPath <|> pillFromURL - - nLite <- switch - $ short 'l' - <> long "lite" - <> help "Boots ship in lite mode" - - nArvoDir <- option auto - $ metavar "PATH" - <> short 'A' - <> long "arvo" - <> value Nothing - <> help "Replace initial clay filesys with contents of PATH" - - nEthNode <- ethNode - - nSerfExe <- serfExe - - pure New{..} - -opts :: Parser Opts -opts = do - oAmesPort <- - optional - $ option auto - $ metavar "PORT" - <> short 'p' - <> long "ames" - <> help "Ames port" - <> hidden - - oNoAmes <- - switch - $ long "no-ames" - <> help "Run with Ames disabled." - <> hidden - - oNoHttp <- - switch - $ long "no-http" - <> help "Run with HTTP disabled." - <> hidden - - oNoHttps <- - switch - $ long "no-https" - <> help "Run with HTTPS disabled." - <> hidden - - oHttpPort <- - optional - $ option auto - $ metavar "PORT" - <> long "http-port" - <> help "HTTP port" - <> hidden - - oHttpsPort <- - optional - $ option auto - $ metavar "PORT" - <> long "https-port" - <> help "HTTPS port" - <> hidden - - oLoopbackPort <- - optional - $ option auto - $ metavar "PORT" - <> long "loopback-port" - <> help "Localhost-only HTTP port" - <> hidden - - oInjectEvents <- injectEvents - - oHashless <- switch $ short 'S' - <> long "hashless" - <> help "Disable battery hashing (Ignored for now)" - <> hidden - - oQuiet <- switch $ short 'q' - <> long "quiet" - <> help "Quiet" - <> hidden - - oVerbose <- switch $ short 'v' - <> long "verbose" - <> help "Puts the serf and king into verbose mode" - <> hidden - - oExit <- switch $ short 'x' - <> long "exit" - <> help "Exit immediately" - <> hidden - - oDryRun <- switch $ long "dry-run" - <> help "Persist no events and turn off Ames networking" - <> hidden - - oDryFrom <- optional $ option auto $ metavar "EVENT" - <> long "dry-from" - <> help "Dry run from event number" - <> hidden - - oTrace <- switch $ short 't' - <> long "trace" - <> help "Enable tracing" - <> hidden - - oLocalhost <- switch $ short 'L' - <> long "local" - <> help "Localhost-only networking" - <> hidden - - oCollectFx <- switch $ short 'f' - <> long "collect-fx" - <> help "Write effects to disk for debugging" - <> hidden - - oOffline <- switch $ short 'O' - <> long "offline" - <> help "Run without any networking" - <> hidden - - oFullReplay <- switch - $ long "full-log-replay" - <> help "Ignores snapshot and recomputes state from event log" - <> hidden - - pure (Opts{..}) - -log :: Parser Log -log = do - lTarget <- - optional - $ ( flag' LogStderr - $ long "log-to-stderr" - <> long "stderr" - <> help "Display logs on stderr" - <> hidden - ) - <|> ( fmap LogFile . strOption - $ long "log-to" - <> metavar "LOG_FILE" - <> help "Append logs to the given file" - <> hidden - ) - <|> ( flag' LogOff - $ long "no-logging" - <> help "Disable logging entirely" - <> hidden - ) - - lLevel <- - ( flag' LevelDebug - $ long "log-debug" - <> help "Log errors, warnings, info, and debug messages" - <> hidden - ) - <|> ( flag' LevelInfo - $ long "log-info" - <> help "Log errors, warnings, and info" - <> hidden - ) - <|> ( flag' LevelWarn - $ long "log-warn" - <> help "Log errors and warnings (default)" - <> hidden - ) - <|> ( flag' LevelError - $ long "log-error" - <> help "Log errors only" - <> hidden - ) - <|> pure LevelWarn - - pure (Log{..}) - -newShip :: Parser (Cmd, Log) -newShip = (,) <$> (CmdNew <$> new <*> opts) <*> log - -runOneShip :: Parser (Run, Opts, Bool) -runOneShip = (,,) <$> fmap Run pierPath <*> opts <*> df - where - df = switch (short 'd' <> long "daemon" <> help "Daemon mode" <> hidden) - -host :: Parser Host -host = do - hSharedHttpPort <- - optional - $ option auto - $ metavar "PORT" - <> long "shared-http-port" - <> help "HTTP port" - <> hidden - - hSharedHttpsPort <- - optional - $ option auto - $ metavar "PORT" - <> long "shared-https-port" - <> help "HTTPS port" - <> hidden - - hUseNatPmp <- - ( flag' NatAlways - $ long "port-forwarding" - <> help "Always try to search for a router to forward ames ports" - <> hidden - ) <|> - ( flag' NatNever - $ long "no-port-forwarding" - <> help "Disable trying to ask the router to forward ames ports" - <> hidden - ) <|> - ( flag' NatWhenPrivateNetwork - $ long "port-forwarding-when-internal" - <> help ("Try asking the router to forward when ip is 192.168.0.0/16, " <> - "172.16.0.0/12 or 10.0.0.0/8 (default).") - <> hidden - ) <|> - (pure $ NatWhenPrivateNetwork) - - hSerfExe <- serfExe - - pure (Host{..}) - -runShip :: Parser (Cmd, Log) -runShip = (,) <$> (CmdRun <$> host <*> some runOneShip) <*> log - -valPill :: Parser Bug -valPill = do - bPillPath <- strArgument (metavar "PILL" <> help "Path to pill") - - bPrintPil <- switch $ long "print-pill" - <> help "Print pill" - - bPrintSeq <- switch $ long "print-boot" - <> help "Print boot sequence" - - pure ValidatePill{..} - -keyfilePath :: Parser FilePath -keyfilePath = strArgument (metavar "KEYFILE" <> help "Path to key file") - -firstEv :: Parser Word64 -firstEv = option auto $ long "first" - <> metavar "FST" - <> help "starting from event FST" - <> value 1 - -lastEv :: Parser Word64 -lastEv = option auto $ long "last" - <> metavar "LAS" - <> help "ending with event LAS" - <> value maxBound - -checkEvs :: Parser Bug -checkEvs = ValidateEvents <$> pierPath <*> firstEv <*> lastEv - -checkFx :: Parser Bug -checkFx = ValidateFX <$> pierPath <*> firstEv <*> lastEv - -replayEvs :: Parser Bug -replayEvs = ReplayEvents <$> pierPath <*> lastEv - -browseEvs :: Parser Bug -browseEvs = EventBrowser <$> pierPath - -checkDawn :: Parser Bug -checkDawn = CheckDawn <$> ethNode <*> keyfilePath - -bugCmd :: Parser (Cmd, Log) -bugCmd = (flip (,) <$> log <*>) $ fmap CmdBug - $ subparser - $ command "validate-pill" - ( info (valPill <**> helper) - $ progDesc "Validate a pill file." - ) - <> command "collect-all-fx" - ( info (allFx <**> helper) - $ progDesc "Replay entire event log, collecting all effects" - ) - <> command "validate-events" - ( info (checkEvs <**> helper) - $ progDesc "Parse all data in event log" - ) - <> command "event-browser" - ( info (browseEvs <**> helper) - $ progDesc "Interactively view (and prune) event log" - ) - <> command "validate-effects" - ( info (checkFx <**> helper) - $ progDesc "Parse all data in event log" - ) - <> command "partial-replay" - ( info (replayEvs <**> helper) - $ progDesc "Replay up to N events" - ) - <> command "dawn" - ( info (checkDawn <**> helper) - $ progDesc "Test run dawn" - ) - <> command "comet" - ( info (pure CheckComet) - $ progDesc "Shows the list of stars accepting comets" - ) - -conCmd :: Parser (Cmd, Log) -conCmd = (,) <$> (CmdCon <$> pierPath) <*> log - -allFx :: Parser Bug -allFx = do - bPierPath <- strArgument (metavar "PIER" <> help "Path to pier") - pure CollectAllFX{..} - -cmd :: Parser (Cmd, Log) -cmd = subparser - $ command "new" ( info (newShip <**> helper) - $ progDesc "Boot a new ship." - ) - <> command "run" ( info (runShip <**> helper) - $ progDesc "Run an existing ship." - ) - <> command "bug" ( info (bugCmd <**> helper) - $ progDesc "Run a debugging sub-command." - ) - <> command "con" ( info (conCmd <**> helper) - $ progDesc "Connect a terminal to a running urbit." - ) diff --git a/pkg/hs/urbit-king/lib/Urbit/King/Config.hs b/pkg/hs/urbit-king/lib/Urbit/King/Config.hs deleted file mode 100644 index 4ccece736..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/King/Config.hs +++ /dev/null @@ -1,61 +0,0 @@ -{-| - Pier Configuration --} -module Urbit.King.Config where - -import Urbit.Prelude - -import qualified Urbit.Vere.Serf as Serf - -{-| - All the configuration data revolving around a ship and the current - execution options. --} -data PierConfig = PierConfig - { _pcPierPath :: FilePath - , _pcDryRun :: Bool - , _pcSerfExe :: Maybe Text - , _pcSerfFlags :: [Serf.Flag] - } deriving (Show) - -makeLenses ''PierConfig - -class HasPierPath a where - pierPathL :: Lens' a FilePath - -class HasDryRun a where - dryRunL :: Lens' a Bool - -class (HasPierPath a, HasDryRun a) => HasPierConfig a where - pierConfigL :: Lens' a PierConfig - -instance HasPierPath PierConfig where - pierPathL = pcPierPath - -instance HasDryRun PierConfig where - dryRunL = pcDryRun - - -------------------------------------------------------------------------------- - -data NetMode - = NMNone - | NMLocalhost - | NMNormal - deriving (Eq, Ord, Show) - -data NetworkConfig = NetworkConfig - { _ncNetMode :: NetMode - , _ncAmesPort :: Maybe Word16 - , _ncNoAmes :: Bool - , _ncNoHttp :: Bool - , _ncNoHttps :: Bool - , _ncHttpPort :: Maybe Word16 - , _ncHttpsPort :: Maybe Word16 - , _ncLocalPort :: Maybe Word16 - } deriving (Show) - -makeLenses ''NetworkConfig - -class HasNetworkConfig env where - networkConfigL :: Lens' env NetworkConfig diff --git a/pkg/hs/urbit-king/lib/Urbit/King/EventBrowser.hs b/pkg/hs/urbit-king/lib/Urbit/King/EventBrowser.hs deleted file mode 100644 index da8fe9515..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/King/EventBrowser.hs +++ /dev/null @@ -1,194 +0,0 @@ -{-| - Interactive Event-Log Browser - - TODO Handle CTRL-D --} - -module Urbit.King.EventBrowser (run) where - -import Urbit.Prelude - -import Data.Conduit -import Urbit.Arvo -import Urbit.Noun.Time -import Urbit.Vere.Pier.Types - -import Control.Monad.Trans.Maybe (MaybeT(..)) -import Urbit.EventLog.LMDB (EventLog) -import Urbit.EventLog.Event (parseLogEvent) - -import qualified Data.Conduit.Combinators as C -import qualified Urbit.EventLog.LMDB as Log - - --------------------------------------------------------------------------------- - -data Event = Event - { num :: Word64 - , mug :: Mug - , wen :: Wen - , ova :: Ev - } - deriving Show - -data Input = Next | Prev | Quit | Trim | Effs | Init | Last - --------------------------------------------------------------------------------- - -run :: HasLogFunc e => EventLog -> RIO e () -run log = do - hSetBuffering stdin NoBuffering - hSetEcho stdin False - logInfo $ displayShow (Log.identity log) - let cycle = fromIntegral $ lifecycleLen $ Log.identity log - las <- atomically (Log.lastEv log) - loop cycle las las - where - failRead cur = - putStrLn ("ERROR: Failed to read event: " <> tshow cur) - - input cyc las cur mFx = do - getInput las cur >>= \case - Next -> loop cyc las (succ cur) - Prev -> loop cyc las (pred cur) - Init -> loop cyc las 1 - Last -> loop cyc las las - Quit -> pure () - Trim -> trim cyc las cur mFx - Effs -> showEffects mFx >> input cyc las cur mFx - - trim cyc las cur mFx = do - deleteFrom log las cur >>= \case - True -> loop cyc (pred cur) (pred cur) - False -> input cyc las cur mFx - - loop cyc las 0 = loop cyc las 1 - loop cyc las cur | cur > las = loop cyc las las - loop cyc las cur | cyc >= cur = do - putStrLn "" - putStrLn " [EVENT]" - putStrLn "" - putStrLn " Lifecycle Nock" - putStrLn "" - input cyc las cur (Just []) - - loop cyc las cur = do - mEv <- peekEvent log cur - mFx <- peekEffect log cur - - case mEv of - Nothing -> failRead cur - Just ev -> showEvent ev >> showEffectsTeaser mFx - - input cyc las cur mFx - -deleteFrom :: HasLogFunc e => EventLog -> Word64 -> Word64 -> RIO e Bool -deleteFrom log las cur = do - sure <- areYouSure - if sure then doDelete else abortDelete - pure sure - where - abortDelete = do - putStrLn "\n\n [ABORTED]\n" - putStrLn " Aborted delete, no events pruned.\n" - - doDelete = do - Log.trimEvents log cur - putStrLn "\n\n [DELETED]\n" - putStrLn " It's gone forever!\n" - - question = - if las == cur - then mconcat [ " This will permanently delete the last event (#" - , tshow las - , ")\n" ] - else mconcat [ " This will permanently delete all events in (#" - , tshow cur - , " - #" - , tshow las - , ")\n" ] - - areYouSure = do - putStrLn "\n\n ARE YOU SURE????" - putStrLn "" - putStrLn question - putStr "(y|n) " - hFlush stdout - getChar <&> \case - 'y' -> True - _ -> False - -getInput :: Word64 -> Word64 -> RIO e Input -getInput las cur = do - putStr ("(" <> tshow cur <> "/" <> tshow las <> ") ") - hFlush stdout - getChar >>= \case - 'j' -> pure Next - 'k' -> pure Prev - 'q' -> pure Quit - 'f' -> pure Effs - 'x' -> pure Trim - '0' -> pure Init - 'G' -> pure Last - _ -> do putStrLn "\n" - putStrLn help - getInput las cur - where - help = unlines - [ " [HELP]" - , "" - , " k View the previous event" - , " j View the next event" - , " 0 View the first event" - , " G View the last event" - , " q Quit" - , " x Delete (only the last event)" - , " ? Show this help" - ] - -showEffectsTeaser :: Maybe FX -> RIO e () -showEffectsTeaser Nothing = putStrLn " [No collected effects]\n" -showEffectsTeaser (Just []) = putStrLn " [No effects for this event]\n" -showEffectsTeaser (Just fx) = putStrLn $ mconcat - [ " [" - , tshow (length fx) - , " collected effects. Press 'f' to view]\n" - ] - -showEffects :: Maybe FX -> RIO e () -showEffects Nothing = putStrLn " [No collected effects]\n" -showEffects (Just []) = putStrLn " [No effects for this event]\n" -showEffects (Just fx) = do - putStrLn "\n" - putStrLn " [EFFECTS]" - for_ fx $ \ef -> do - putStrLn "" - showEffect ef - putStrLn "" - -showEffect :: Lenient Ef -> RIO e () -showEffect (GoodParse ef) = - putStrLn $ unlines $ fmap (" " <>) $ lines $ pack $ ppShow ef -showEffect (FailParse n) = - putStrLn $ unlines $ fmap (" " <>) $ lines $ pack $ ppShow n - -showEvent :: Event -> RIO e () -showEvent ev = do - putStrLn "\n" - putStrLn " [EVENT]" - putStrLn "" - putStrLn $ unlines $ fmap (" " <>) $ lines $ pack $ ppShow (ova ev) - -peekEffect :: HasLogFunc e => EventLog -> Word64 -> RIO e (Maybe FX) -peekEffect log eId = runMaybeT $ do - (id, bs) <- MaybeT $ runConduit (Log.streamEffectsRows log eId .| C.head) - guard (id == eId) - io $ cueBSExn bs >>= fromNounExn - -peekEvent :: HasLogFunc e => EventLog -> Word64 -> RIO e (Maybe Event) -peekEvent log eId = runMaybeT $ do - octs <- MaybeT $ runConduit (Log.streamEvents log eId .| C.head) - (m,n) <- io $ parseLogEvent octs - (w,e) <- io $ fromNounExn n - ovum <- fromNounExn e - pure (Event eId m w ovum) diff --git a/pkg/hs/urbit-king/lib/Urbit/King/Main.hs b/pkg/hs/urbit-king/lib/Urbit/King/Main.hs deleted file mode 100644 index d7ae6d392..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/King/Main.hs +++ /dev/null @@ -1,965 +0,0 @@ -{- | - # Signal Handling (SIGTERM, SIGINT) - - We handle SIGTERM by causing the main thread to raise a `UserInterrupt` - exception. This is the same behavior as SIGINT (the signal sent upon - `CTRL-C`). - - The main thread is therefore responsible for handling this exception - and causing everything to shut down properly. - - # Crashing and Shutting Down - - Rule number one: The King never crashes. - - This rule is asperational at the moment, but it needs to become as - close to truth as possible. Shut down ships in extreme cases, but - never let the king go down. --} - -{- - TODO These some old scribbled notes. They don't belong here - anymore. Do something about it. - - # Event Pruning - - - `king discard-events NUM_EVENTS`: Delete the last `n` events from - the event log. - - - `king discard-events-interactive`: Iterate through the events in - the event log, from last to first, pretty-print each event, and - ask if it should be pruned. - - # Implement subcommands to test event and effect parsing. - - - `king * --collect-fx`: All effects that come from the serf get - written into the `effects` LMDB database. - - - `king clear-fx PIER`: Deletes all collected effects. - - - `king full-replay PIER`: Replays the whole event log events, print - any failures. On success, replace the snapshot. - - - # Full Replay -- An Integration Test - - - Copy the event log: - - - Create a new event log at the destination. - - Stream events from the first event log. - - Parse each event. - - Re-Serialize each event. - - Verify that the round-trip was successful. - - Write the event into the new database. - - - Replay the event log at the destination. - - If `--collect-fx` is set, then record effects as well. - - - Snapshot. - - - Verify that the final mug is the same as it was before. - - # Implement Remaining Serf Flags - - - `DebugRam`: Memory debugging. - - `DebugCpu`: Profiling - - `CheckCorrupt`: Heap Corruption Tests - - `CheckFatal`: TODO What is this? - - `Verbose`: TODO Just the `-v` flag? - - `DryRun`: TODO Just the `-N` flag? - - `Quiet`: TODO Just the `-q` flag? - - `Hashless`: Don't use hashboard for jets. --} - -module Urbit.King.Main (main) where - -import Urbit.Prelude - -import Data.Conduit -import Network.HTTP.Client.TLS -import RIO.Directory -import Urbit.Arvo -import Urbit.King.Config -import Urbit.Vere.Dawn -import Urbit.Vere.Pier -import Urbit.Vere.Ports -import Urbit.Vere.Eyre.Multi (multiEyre, MultiEyreConf(..)) -import Urbit.Vere.Pier.Types -import Urbit.Vere.Serf -import Urbit.King.App - -import Control.Concurrent (myThreadId) -import Control.Exception (AsyncException(UserInterrupt)) -import System.Process (system) -import System.IO (hPutStrLn) -import Urbit.Noun.Time (Wen) -import Urbit.Vere.LockFile (lockFile) - -import qualified Data.Set as Set -import qualified Data.Text as T -import qualified Network.HTTP.Client as C -import qualified System.Posix.Signals as Sys -import qualified System.Posix.Resource as Sys -import qualified System.ProgressBar as PB -import qualified System.Random as Sys -import qualified Urbit.EventLog.LMDB as Log -import qualified Urbit.King.CLI as CLI -import qualified Urbit.King.EventBrowser as EventBrowser -import qualified Urbit.Ob as Ob -import qualified Urbit.Vere.Pier as Pier -import qualified Urbit.Vere.Serf as Serf -import qualified Urbit.Vere.Term as Term - - --------------------------------------------------------------------------------- - -removeFileIfExists :: HasLogFunc env => FilePath -> RIO env () -removeFileIfExists pax = do - exists <- doesFileExist pax - when exists $ do - removeFile pax - - --- Compile CLI Flags to Pier Configuration ------------------------------------- - -{- - TODO: This is not all of the flags. - Urbit is basically useless with hashboard, so we ignore that flag. --} -toSerfFlags :: CLI.Opts -> [Serf.Flag] -toSerfFlags CLI.Opts{..} = catMaybes m - where - m = [ setFrom oQuiet Serf.Quiet - , setFrom oTrace Serf.Trace - , setFrom (oHashless || True) Serf.Hashless - , setFrom oQuiet Serf.Quiet - , setFrom oVerbose Serf.Verbose - , setFrom (oDryRun || isJust oDryFrom) Serf.DryRun - ] - setFrom True flag = Just flag - setFrom False _ = Nothing - -toPierConfig :: FilePath -> Maybe Text -> CLI.Opts -> PierConfig -toPierConfig pierPath serfExe o@(CLI.Opts{..}) = PierConfig { .. } - where - _pcPierPath = pierPath - _pcDryRun = oDryRun || isJust oDryFrom - _pcSerfExe = serfExe - _pcSerfFlags = toSerfFlags o - -toNetworkConfig :: CLI.Opts -> NetworkConfig -toNetworkConfig CLI.Opts {..} = NetworkConfig { .. } - where - dryRun = oDryRun || isJust oDryFrom - offline = dryRun || oOffline - - mode = case (dryRun, offline, oLocalhost) of - (True, _ , _ ) -> NMNone - (_ , True, _ ) -> NMNone - (_ , _ , True) -> NMLocalhost - (_ , _ , _ ) -> NMNormal - - _ncNetMode = mode - _ncAmesPort = oAmesPort - _ncHttpPort = oHttpPort - _ncHttpsPort = oHttpsPort - _ncLocalPort = oLoopbackPort - _ncNoAmes = oNoAmes - _ncNoHttp = oNoHttp - _ncNoHttps = oNoHttps - -logStderr :: HasStderrLogFunc e => RIO LogFunc a -> RIO e a -logStderr action = do - logFunc <- view stderrLogFuncL - runRIO logFunc action - -logSlogs :: HasStderrLogFunc e => RIO e (TVar ((Atom, Tank) -> IO ())) -logSlogs = logStderr $ do - env <- ask - newTVarIO (runRIO env . logOther "serf" . display . T.strip . tankToText . snd) - -tryBootFromPill - :: Bool - -> Pill - -> Bool - -> Ship - -> LegacyBootEvent - -> Feed - -> RIO PierEnv () -tryBootFromPill oExit pill lite ship boot feed = do - mStart <- newEmptyMVar - vSlog <- logSlogs - runOrExitImmediately vSlog (bootedPier vSlog) oExit mStart [] - where - bootedPier vSlog = do - view pierPathL >>= lockFile - rio $ logInfo "Starting boot" - sls <- Pier.booted vSlog pill lite ship boot feed - rio $ logInfo "Completed boot" - pure sls - -runOrExitImmediately - :: TVar ((Atom, Tank) -> IO ()) - -> RAcquire PierEnv (Serf, Log.EventLog) - -> Bool - -> MVar () - -> [Ev] - -> RIO PierEnv () -runOrExitImmediately vSlog getPier oExit mStart injected = do - rwith getPier (if oExit then shutdownImmediately else runPier) - where - shutdownImmediately :: (Serf, Log.EventLog) -> RIO PierEnv () - shutdownImmediately (serf, log) = do - logInfo "Sending shutdown signal" - Serf.stop serf - logInfo "Shutdown!" - - runPier :: (Serf, Log.EventLog) -> RIO PierEnv () - runPier serfLog = do - runRAcquire (Pier.pier serfLog vSlog mStart injected) - -tryPlayShip - :: Bool - -> Bool - -> Maybe Word64 - -> MVar () - -> [Ev] - -> RIO PierEnv () -tryPlayShip exitImmediately fullReplay playFrom mStart injected = do - when fullReplay wipeSnapshot - vSlog <- logSlogs - runOrExitImmediately vSlog (resumeShip vSlog) exitImmediately mStart injected - where - wipeSnapshot = do - shipPath <- view pierPathL - logInfo "wipeSnapshot" - logInfo $ display $ pack @Text ("Wiping " <> north shipPath) - logInfo $ display $ pack @Text ("Wiping " <> south shipPath) - removeFileIfExists (north shipPath) - removeFileIfExists (south shipPath) - - north shipPath = shipPath <> "/.urb/chk/north.bin" - south shipPath = shipPath <> "/.urb/chk/south.bin" - - resumeShip :: TVar ((Atom, Tank) -> IO ()) - -> RAcquire PierEnv (Serf, Log.EventLog) - resumeShip vSlog = do - view pierPathL >>= lockFile - rio $ logInfo "RESUMING SHIP" - sls <- Pier.resumed vSlog playFrom - rio $ logInfo "SHIP RESUMED" - pure sls - -runRAcquire :: (MonadUnliftIO (m e), MonadIO (m e), MonadReader e (m e)) - => RAcquire e a -> m e a -runRAcquire act = rwith act pure - - --------------------------------------------------------------------------------- - -checkEvs :: FilePath -> Word64 -> Word64 -> RIO KingEnv () -checkEvs pierPath first last = do - rwith (Log.existing logPath) $ \log -> do - let ident = Log.identity log - let pbSty = PB.defStyle { PB.stylePostfix = PB.exact } - logInfo (displayShow ident) - - last <- atomically $ Log.lastEv log <&> \lastReal -> min last lastReal - - let evCount = fromIntegral (last - first) - - pb <- PB.newProgressBar pbSty 10 (PB.Progress 1 evCount ()) - - runConduit $ Log.streamEvents log first .| showEvents - pb - first - (fromIntegral $ lifecycleLen ident) - where - logPath :: FilePath - logPath = pierPath <> "/.urb/log" - - showEvents - :: PB.ProgressBar () - -> EventId - -> EventId - -> ConduitT ByteString Void (RIO KingEnv) () - showEvents pb eId _ | eId > last = pure () - showEvents pb eId cycle = await >>= \case - Nothing -> do - lift $ PB.killProgressBar pb - lift $ logInfo "Everything checks out." - Just bs -> do - lift $ PB.incProgress pb 1 - lift $ do - n <- io $ cueBSExn bs - when (eId > cycle) $ do - (mug, wen, evNoun) <- unpackJob n - fromNounErr evNoun & \case - Left err -> logError (displayShow (eId, err)) - Right (_ :: Ev) -> pure () - showEvents pb (succ eId) cycle - - unpackJob :: Noun -> RIO KingEnv (Mug, Wen, Noun) - unpackJob = io . fromNounExn - - --------------------------------------------------------------------------------- - -collectAllFx :: FilePath -> RIO KingEnv () -collectAllFx = error "TODO" - -{- -{-| - This runs the serf at `$top/.tmpdir`, but we disable snapshots, - so this should never actually be created. We just do this to avoid - letting the serf use an existing snapshot. --} -collectAllFx :: FilePath -> RIO KingEnv () -collectAllFx top = do - logInfo $ display $ pack @Text top - vSlog <- logSlogs - rwith (collectedFX vSlog) $ \() -> - logInfo "Done collecting effects!" - where - tmpDir :: FilePath - tmpDir = top ".tmpdir" - - collectedFX :: TVar (Text -> IO ()) -> RAcquire KingEnv () - collectedFX vSlog = do - lockFile top - log <- Log.existing (top <> "/.urb/log") - serf <- Pier.runSerf vSlog tmpDir serfFlags - rio $ Serf.collectFX serf log - - serfFlags :: [Serf.Flag] - serfFlags = [Serf.Hashless, Serf.DryRun] --} - - --------------------------------------------------------------------------------- - -replayPartEvs :: FilePath -> Word64 -> RIO KingEnv () -replayPartEvs top last = do - logInfo $ display $ pack @Text top - fetchSnapshot - rwith replayedEvs $ \() -> - logInfo "Done replaying events!" - where - fetchSnapshot :: RIO KingEnv () - fetchSnapshot = do - snap <- Pier.getSnapshot top last - case snap of - Nothing -> pure () - Just sn -> do - liftIO $ system $ "cp -r \"" <> sn <> "\" \"" <> tmpDir <> "\"" - pure () - - tmpDir :: FilePath - tmpDir = top ".partial-replay" show last - - replayedEvs :: RAcquire KingEnv () - replayedEvs = do - lockFile top - log <- Log.existing (top <> "/.urb/log") - let onSlog = print - let onStdr = print - let onDead = error "DIED" - let config = Serf.Config "urbit-worker" tmpDir serfFlags onSlog onStdr onDead - (serf, info) <- io (Serf.start config) - rio $ do - eSs <- Serf.execReplay serf log (Just last) - case eSs of - Left bail -> error (show bail) - Right 0 -> io (Serf.snapshot serf) - Right num -> pure () - io $ threadDelay 500000 -- Copied from runOrExitImmediately - pure () - - serfFlags :: [Serf.Flag] - serfFlags = [Serf.Hashless] - - --------------------------------------------------------------------------------- - -{-| - Interesting --} -testPill :: HasKingEnv e => FilePath -> Bool -> Bool -> RIO e () -testPill pax showPil showSeq = do - logInfo "Reading pill file." - pillBytes <- readFile pax - - logInfo "Cueing pill file." - pillNoun <- io $ cueBS pillBytes & either throwIO pure - - logInfo "Parsing pill file." - pill <- fromNounErr pillNoun & either (throwIO . uncurry ParseErr) pure - - logInfo "Using pill to generate boot sequence." - bootSeq <- genBootSeq - (Ship 0) - pill - False - (Fake (Ship 0)) - (Feed1 $ Germs (Ship 0) []) - - logInfo "Validate jam/cue and toNoun/fromNoun on pill value" - reJam <- validateNounVal pill - - logInfo "Checking if round-trip matches input file:" - unless (reJam == pillBytes) $ do - logInfo " Our jam does not match the file...\n" - logInfo " This is surprising, but it is probably okay." - - when showPil $ do - logInfo "\n\n== Pill ==\n" - io $ pPrint pill - - when showSeq $ do - logInfo "\n\n== Boot Sequence ==\n" - io $ pPrint bootSeq - -validateNounVal :: (HasLogFunc e, Eq a, ToNoun a, FromNoun a) - => a -> RIO e ByteString -validateNounVal inpVal = do - logInfo " jam" - inpByt <- evaluate $ jamBS $ toNoun inpVal - - logInfo " cue" - outNon <- cueBS inpByt & either throwIO pure - - logInfo " fromNoun" - outVal <- fromNounErr outNon & either (throwIO . uncurry ParseErr) pure - - logInfo " toNoun" - outNon <- evaluate (toNoun outVal) - - logInfo " jam" - outByt <- evaluate $ jamBS outNon - - logInfo "Checking if: x == cue (jam x)" - unless (inpVal == outVal) $ - error "Value fails test: x == cue (jam x)" - - logInfo "Checking if: jam x == jam (cue (jam x))" - unless (inpByt == outByt) $ - error "Value fails test: jam x == jam (cue (jam x))" - - pure outByt - - --------------------------------------------------------------------------------- - -pillFrom :: CLI.PillSource -> RIO HostEnv Pill -pillFrom = \case - CLI.PillSourceFile pillPath -> do - logInfo $ display $ "boot: reading pill from " ++ (pack pillPath :: Text) - io (loadFile pillPath >>= either throwIO pure) - - CLI.PillSourceURL url -> do - logInfo $ display $ "boot: retrieving pill from " ++ (pack url :: Text) - -- Get the jamfile with the list of stars accepting comets right now. - manager <- io $ C.newManager tlsManagerSettings - request <- io $ C.parseRequest url - response <- io $ C.httpLbs (C.setRequestCheckStatus request) manager - let body = toStrict $ C.responseBody response - - noun <- cueBS body & either throwIO pure - fromNounErr noun & either (throwIO . uncurry ParseErr) pure - -multiOnFatal :: HasKingEnv e => e -> IO () -multiOnFatal env = runRIO env $ do - (view stderrLogFuncL >>=) $ flip runRIO $ logError - ("Urbit is shutting down because of a problem with the HTTP server.\n" - <> "Please restart it at your leisure.") - view killKingActionL >>= atomically - -newShip :: CLI.New -> CLI.Opts -> RIO KingEnv () -newShip CLI.New{..} opts = do - {- - TODO XXX HACK - - Because the "new ship" flow *may* automatically start the ship, - we need to create this, but it's not actually correct. - - The right solution is to separate out the "new ship" flow from the - "run ship" flow, and possibly sequence them from the outside if - that's really needed. - -} - env <- ask - multi <- multiEyre (multiOnFatal env) (MultiEyreConf Nothing Nothing True) - - -- TODO: We hit the same problem as above: we need a host env to boot a ship - -- because it may autostart the ship, so build an inactive port configuration. - let ports = buildInactivePorts - - -- here we are with a king env, and we now need a multi env. - runHostEnv multi ports $ case nBootType of - CLI.BootComet -> do - pill <- pillFrom nPillSource - putStrLn "boot: retrieving list of stars currently accepting comets" - starList <- dawnCometList - putStrLn ("boot: " ++ (tshow $ length starList) ++ - " star(s) currently accepting comets") - putStrLn "boot: mining a comet" - eny <- io $ Sys.randomIO - let seed = mineComet (Set.fromList starList) eny - putStrLn ("boot: found comet " ++ renderShip (sShip seed)) - putStrLn ("code: " ++ (tshow $ deriveCode $ sRing seed)) - bootFromFeed pill $ Feed0 seed - - CLI.BootFake name -> do - pill <- pillFrom nPillSource - ship <- shipFrom name - runTryBootFromPill pill name ship (Fake ship) (Feed1 $ Germs ship []) - - CLI.BootFromKeyfile keyFile -> do - text <- readFileUtf8 keyFile - asAtom <- case cordToUW (Cord $ T.strip text) of - Nothing -> error "Couldn't parse keyfile. Hint: keyfiles start with 0w?" - Just (UW a) -> pure a - - asNoun <- cueExn asAtom - feed :: Feed <- case fromNoun asNoun of - Nothing -> error "Keyfile does not seem to contain a seed." - Just s -> pure s - - pill <- pillFrom nPillSource - - bootFromFeed pill feed - - where - shipFrom :: Text -> RIO HostEnv Ship - shipFrom name = case Ob.parsePatp name of - Left x -> error "Invalid ship name" - Right p -> pure $ Ship $ fromIntegral $ Ob.fromPatp p - - pierPath :: Text -> FilePath - pierPath name = case nPierPath of - Just x -> x - Nothing -> "./" <> unpack name - - nameFromShip :: HasKingEnv e => Ship -> RIO e Text - nameFromShip s = name - where - nameWithSig = Ob.renderPatp $ Ob.patp $ fromIntegral s - name = case stripPrefix "~" nameWithSig of - Nothing -> error "Urbit.ob didn't produce string with ~" - Just x -> pure x - - bootFromFeed :: Pill -> Feed -> RIO HostEnv () - bootFromFeed pill feed = do - ethReturn <- dawnVent nEthNode feed - - case ethReturn of - Left x -> error $ unpack x - Right dawn -> do - let ship = sShip $ dSeed dawn - name <- nameFromShip ship - runTryBootFromPill pill name ship (Dawn dawn) feed - - -- Now that we have all the information for running an application with a - -- PierConfig, do so. - runTryBootFromPill :: Pill - -> Text - -> Ship - -> LegacyBootEvent - -> Feed - -> RIO HostEnv () - runTryBootFromPill pill name ship bootEvent feed = do - vKill <- view (kingEnvL . kingEnvKillSignal) - let pierConfig = toPierConfig (pierPath name) nSerfExe opts - let networkConfig = toNetworkConfig opts - runPierEnv pierConfig networkConfig vKill $ - tryBootFromPill True pill nLite ship bootEvent feed - -runShipEnv :: Maybe Text -> CLI.Run -> CLI.Opts -> TMVar () -> RIO PierEnv a - -> RIO HostEnv a -runShipEnv serfExe (CLI.Run pierPath) opts vKill act = do - runPierEnv pierConfig netConfig vKill act - where - pierConfig = toPierConfig pierPath serfExe opts - netConfig = toNetworkConfig opts - -runShip - :: CLI.Run -> CLI.Opts -> Bool -> RIO PierEnv () -runShip (CLI.Run pierPath) opts daemon = do - mStart <- newEmptyMVar - if daemon - then runPier mStart - else do - -- Wait until the pier has started up, then connect a terminal. If - -- the terminal ever shuts down, ask the ship to go down. - connectionThread <- async $ do - readMVar mStart - finally (connTerm pierPath) $ do - view killPierActionL >>= atomically - - -- Run the pier until it finishes, and then kill the terminal. - finally (runPier mStart) $ do - cancel connectionThread - where - runPier :: MVar () -> RIO PierEnv () - runPier mStart = do - injections <- loadInjections (CLI.oInjectEvents opts) - tryPlayShip - (CLI.oExit opts) - (CLI.oFullReplay opts) - (CLI.oDryFrom opts) - mStart - injections - - loadInjections :: [CLI.Injection] -> RIO PierEnv [Ev] - loadInjections injections = do - perInjection :: [[Ev]] <- for injections $ \case - CLI.InjectOneEvent filePath -> do - logInfo $ display $ "boot: reading injected event from " ++ - (pack filePath :: Text) - io (loadFile filePath >>= either throwIO (pure . singleton)) - - CLI.InjectManyEvents filePath -> do - logInfo $ display $ "boot: reading injected event list from " ++ - (pack filePath :: Text) - io (loadFile filePath >>= either throwIO pure) - pure $ concat perInjection - - - -buildPortHandler :: HasLogFunc e => CLI.Nat -> RIO e PortControlApi -buildPortHandler CLI.NatNever = pure buildInactivePorts --- TODO: Figure out what to do about logging here. The "port: " messages are --- the sort of thing that should be put on the muxed terminal log, but we don't --- have that at this layer. -buildPortHandler CLI.NatAlways = buildNatPorts (io . hPutStrLn stderr . unpack) -buildPortHandler CLI.NatWhenPrivateNetwork = - buildNatPortsWhenPrivate (io . hPutStrLn stderr . unpack) - -startBrowser :: HasLogFunc e => FilePath -> RIO e () -startBrowser pierPath = runRAcquire $ do - -- lockFile pierPath - log <- Log.existing (pierPath <> "/.urb/log") - rio $ EventBrowser.run log - -checkDawn :: HasLogFunc e => String -> FilePath -> RIO e () -checkDawn provider keyfilePath = do - -- The keyfile is a jammed Seed then rendered in UW format - text <- readFileUtf8 keyfilePath - asAtom <- case cordToUW (Cord $ T.strip text) of - Nothing -> error "Couldn't parse keyfile. Hint: keyfiles start with 0w?" - Just (UW a) -> pure a - - asNoun <- cueExn asAtom - feed :: Feed <- case fromNoun asNoun of - Nothing -> error "Keyfile does not seem to contain a seed." - Just s -> pure s - - print $ show feed - - e <- dawnVent provider feed - print $ show e - - -checkComet :: HasLogFunc e => RIO e () -checkComet = do - starList <- dawnCometList - putStrLn "Stars currently accepting comets:" - let starNames = map (Ob.renderPatp . Ob.patp . fromIntegral) starList - print starNames - putStrLn "Trying to mine a comet..." - eny <- io $ Sys.randomIO - let s = mineComet (Set.fromList starList) eny - print s - -main :: IO () -main = do - (args, log) <- CLI.parseArgs - - hSetBuffering stdout NoBuffering - setupSignalHandlers - setRLimits - - runKingEnv args log $ case args of - CLI.CmdRun ko ships -> runShips ko ships - CLI.CmdNew n o -> newShip n o - CLI.CmdBug (CLI.CollectAllFX pax ) -> collectAllFx pax - CLI.CmdBug (CLI.EventBrowser pax ) -> startBrowser pax - CLI.CmdBug (CLI.ValidatePill pax pil s) -> testPill pax pil s - CLI.CmdBug (CLI.ValidateEvents pax f l) -> checkEvs pax f l - CLI.CmdBug (CLI.ValidateFX pax f l) -> checkFx pax f l - CLI.CmdBug (CLI.ReplayEvents pax l ) -> replayPartEvs pax l - CLI.CmdBug (CLI.CheckDawn provider pax ) -> checkDawn provider pax - CLI.CmdBug CLI.CheckComet -> checkComet - CLI.CmdCon pier -> connTerm pier - - where - runKingEnv args log = - let - verb = verboseLogging args - runStderr = case args of - CLI.CmdRun {} -> runKingEnvStderrRaw - _ -> runKingEnvStderr - CLI.Log {..} = log - in case logTarget lTarget args of - CLI.LogFile f -> runKingEnvLogFile verb lLevel f - CLI.LogStderr -> runStderr verb lLevel - CLI.LogOff -> runKingEnvNoLog - - setupSignalHandlers = do - mainTid <- myThreadId - let onKillSig = throwTo mainTid UserInterrupt - for_ [Sys.sigTERM, Sys.sigINT] $ \sig -> do - Sys.installHandler sig (Sys.Catch onKillSig) Nothing - - setRLimits = do - openFiles <- Sys.getResourceLimit Sys.ResourceOpenFiles - let soft = case Sys.hardLimit openFiles of - Sys.ResourceLimit lim -> Sys.ResourceLimit lim - Sys.ResourceLimitInfinity -> Sys.ResourceLimit 10240 -- macOS - Sys.ResourceLimitUnknown -> Sys.ResourceLimit 10240 - Sys.setResourceLimit Sys.ResourceOpenFiles - openFiles { Sys.softLimit = soft } - - verboseLogging :: CLI.Cmd -> Bool - verboseLogging = \case - CLI.CmdRun ko ships -> any CLI.oVerbose (ships <&> \(_, o, _) -> o) - _ -> False - - -- If the user hasn't specified where to log, what we do depends on what - -- command she has issued. Notably, the LogFile Nothing outcome means that - -- runKingEnvLogFile should run an IO action to get the official app data - -- directory and open a canonically named log file there. - logTarget :: Maybe (CLI.LogTarget FilePath) - -> CLI.Cmd - -> CLI.LogTarget (Maybe FilePath) - logTarget = \case - Just (CLI.LogFile f) -> const $ CLI.LogFile (Just f) - Just CLI.LogStderr -> const $ CLI.LogStderr - Just CLI.LogOff -> const $ CLI.LogOff - Nothing -> \case - CLI.CmdCon _ -> CLI.LogFile Nothing - CLI.CmdRun ko [(_,_,daemon)] | daemon -> CLI.LogStderr - | otherwise -> CLI.LogFile Nothing - CLI.CmdRun ko _ -> CLI.LogStderr - _ -> CLI.LogStderr - -{- - Runs a ship but restarts it if it crashes or shuts down on it's own. - - Once `waitForKillRequ` returns, the ship will be terminated and this - routine will exit. --} -runShipRestarting - :: Maybe Text -> CLI.Run -> CLI.Opts -> RIO HostEnv () -runShipRestarting serfExe r o = do - let pier = pack (CLI.rPierPath r) - loop = runShipRestarting serfExe r o - - onKill <- view onKillKingSigL - vKillPier <- newEmptyTMVarIO - - tid <- asyncBound $ runShipEnv serfExe r o vKillPier $ runShip r o True - - let onShipExit = Left <$> waitCatchSTM tid - onKillRequ = Right <$> onKill - - atomically (onShipExit <|> onKillRequ) >>= \case - Left exit -> do - case exit of - Left err -> logError $ display (tshow err <> ": " <> pier) - Right () -> - logError $ display ("Ship exited on it's own. Why? " <> pier) - threadDelay 250_000 - loop - Right () -> do - logTrace $ display (pier <> " shutdown requested") - atomically $ putTMVar vKillPier () - race_ (wait tid) $ do - threadDelay 5_000_000 - logInfo $ display (pier <> " not down after 5s, killing with fire.") - cancel tid - logTrace $ display ("Ship terminated: " <> pier) - -{- - TODO This is messy and shared a lot of logic with `runShipRestarting`. --} -runShipNoRestart - :: Maybe Text -> CLI.Run -> CLI.Opts -> Bool -> RIO HostEnv () -runShipNoRestart serfExe r o d = do - -- killing ship same as killing king - vKill <- view (kingEnvL . kingEnvKillSignal) - tid <- asyncBound (runShipEnv serfExe r o vKill $ runShip r o d) - onKill <- view onKillKingSigL - - let pier = pack (CLI.rPierPath r) - - let onShipExit = Left <$> waitCatchSTM tid - onKillRequ = Right <$> onKill - - atomically (onShipExit <|> onKillRequ) >>= \case - Left (Left err) -> do - logError $ display (tshow err <> ": " <> pier) - Left (Right ()) -> do - logError $ display (pier <> " exited on it's own. Why?") - Right () -> do - logTrace $ display (pier <> " shutdown requested") - race_ (wait tid) $ do - threadDelay 5_000_000 - logTrace $ display (pier <> " not down after 5s, killing with fire.") - cancel tid - logTrace $ display (pier <> " terminated.") - -runShips :: CLI.Host -> [(CLI.Run, CLI.Opts, Bool)] -> RIO KingEnv () -runShips CLI.Host {..} ships = do - let meConf = MultiEyreConf - { mecHttpPort = fromIntegral <$> hSharedHttpPort - , mecHttpsPort = fromIntegral <$> hSharedHttpsPort - , mecLocalhostOnly = False -- TODO Localhost-only needs to be - -- a king-wide option. - } - - env <- ask - multi <- multiEyre (multiOnFatal env) meConf - - ports <- buildPortHandler hUseNatPmp - - runHostEnv multi ports (go ships) - where - go :: [(CLI.Run, CLI.Opts, Bool)] -> RIO HostEnv () - go = \case - [] -> pure () - [rod] -> runSingleShip hSerfExe rod - ships -> runMultipleShips hSerfExe (ships <&> \(r, o, _) -> (r, o)) - - --- TODO Duplicated logic. -runSingleShip :: Maybe Text -> (CLI.Run, CLI.Opts, Bool) -> RIO HostEnv () -runSingleShip serfExe (r, o, d) = do - shipThread <- async (runShipNoRestart serfExe r o d) - - {- - Wait for the ship to go down. - - Since `waitCatch` will never throw an exception, the `onException` - block will only happen if this thread is killed with an async - exception. The one we expect is `UserInterrupt` which will be raised - on this thread upon SIGKILL or SIGTERM. - - If this thread is killed, we first ask the ship to go down, wait - for the ship to actually go down, and then go down ourselves. - -} - onException (void $ waitCatch shipThread) $ do - logTrace "KING IS GOING DOWN" - atomically =<< view killKingActionL - waitCatch shipThread - pure () - - -runMultipleShips :: Maybe Text -> [(CLI.Run, CLI.Opts)] -> RIO HostEnv () -runMultipleShips serfExe ships = do - shipThreads <- for ships $ \(r, o) -> do - async (runShipRestarting serfExe r o) - - {- - Since `spin` never returns, this will run until the main - thread is killed with an async exception. The one we expect is - `UserInterrupt` which will be raised on this thread upon SIGKILL - or SIGTERM. - - Once that happens, we send a shutdown signal which will cause all - ships to be shut down, and then we `wait` for them to finish before - returning. - - This is different than the single-ship flow, because ships never - go down on their own in this flow. If they go down, they just bring - themselves back up. - -} - let spin = forever (threadDelay maxBound) - finally spin $ do - logTrace "KING IS GOING DOWN" - view killKingActionL >>= atomically - for_ shipThreads waitCatch - - --------------------------------------------------------------------------------- - -connTerm :: forall e. HasLogFunc e => FilePath -> RIO e () -connTerm = Term.runTerminalClient - - --------------------------------------------------------------------------------- - -checkFx :: HasLogFunc e - => FilePath -> Word64 -> Word64 -> RIO e () -checkFx pierPath first last = - rwith (Log.existing logPath) $ \log -> - runConduit $ streamFX log first last - .| tryParseFXStream - where - logPath = pierPath <> "/.urb/log" - -streamFX :: HasLogFunc e - => Log.EventLog -> Word64 -> Word64 - -> ConduitT () ByteString (RIO e) () -streamFX log first last = do - Log.streamEffectsRows log first .| loop - where - loop = await >>= \case Nothing -> pure () - Just (eId, bs) | eId > last -> pure () - Just (eId, bs) -> yield bs >> loop - -tryParseFXStream :: HasLogFunc e => ConduitT ByteString Void (RIO e) () -tryParseFXStream = loop - where - loop = await >>= \case - Nothing -> pure () - Just bs -> do - n <- liftIO (cueBSExn bs) - fromNounErr n & either (logError . displayShow) pure - loop - - -{- -tryCopyLog :: IO () -tryCopyLog = do - let logPath = "/Users/erg/src/urbit/zod/.urb/falselog/" - falselogPath = "/Users/erg/src/urbit/zod/.urb/falselog2/" - - persistQ <- newTQueueIO - releaseQ <- newTQueueIO - (ident, nextEv, events) <- - with (do { log <- Log.existing logPath - ; Pier.runPersist log persistQ (writeTQueue releaseQ) - ; pure log - }) - \log -> do - ident <- pure $ Log.identity log - events <- runConduit (Log.streamEvents log 1 .| consume) - nextEv <- Log.nextEv log - pure (ident, nextEv, events) - - print ident - print nextEv - print (length events) - - persistQ2 <- newTQueueIO - releaseQ2 <- newTQueueIO - with (do { log <- Log.new falselogPath ident - ; Pier.runPersist log persistQ2 (writeTQueue releaseQ2) - ; pure log - }) - $ \log2 -> do - let writs = zip [1..] events <&> \(id, a) -> - (Writ id Nothing a, []) - - print "About to write" - - for_ writs $ \w -> - atomically (writeTQueue persistQ2 w) - - print "About to wait" - - replicateM_ 100 $ do - atomically $ readTQueue releaseQ2 - - print "Done" --} diff --git a/pkg/hs/urbit-king/lib/Urbit/King/Scry.hs b/pkg/hs/urbit-king/lib/Urbit/King/Scry.hs deleted file mode 100644 index 869237477..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/King/Scry.hs +++ /dev/null @@ -1,33 +0,0 @@ -{-| - Scry helpers --} - -module Urbit.King.Scry - ( scryNow - , module Urbit.Vere.Pier.Types - ) -where - -import Urbit.Prelude -import Urbit.Vere.Serf.Types - -import Urbit.Arvo.Common (Desk) -import Urbit.Vere.Pier.Types (ScryFunc) - -scryNow :: forall e n - . (HasLogFunc e, FromNoun n) - => ScryFunc - -> Term -- ^ vane + care as two-letter string - -> Desk -- ^ desk in scry path - -> [Text] -- ^ resource path to scry for - -> RIO e (Maybe n) -scryNow scry vare desk path = - io (scry Nothing (EachNo $ DemiOnce vare desk (Path $ MkKnot <$> path))) - >>= \case - Just ("omen", fromNoun @(Path, Term, n) -> Just (_,_,v)) -> pure $ Just v - Just (_, fromNoun @n -> Just v) -> pure $ Just v - Just (_, n) -> do - logError $ displayShow ("uncanny scry result", vare, path, n) - pure Nothing - Nothing -> pure Nothing - diff --git a/pkg/hs/urbit-king/lib/Urbit/King/TryJamPill.hs b/pkg/hs/urbit-king/lib/Urbit/King/TryJamPill.hs deleted file mode 100644 index 539638679..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/King/TryJamPill.hs +++ /dev/null @@ -1,51 +0,0 @@ -{-| - Test jam/cue on pills. --} -module Urbit.King.TryJamPill where - -import Control.Lens -import Urbit.Prelude - --------------------------------------------------------------------------------- - -main :: IO () -main = do - print "cue brass" -- void getLine - tryCueJamPill Brass - - print "cue ivory" -- void getLine - tryCueJamPill Ivory - - print "cue solid" -- void getLine - tryCueJamPill Solid - -loadNoun :: FilePath -> IO (Maybe Noun) -loadNoun = fmap (preview _Cue) . readFile - -dumpJam :: FilePath -> Noun -> IO () -dumpJam fp = writeFile fp . view (re _Cue) - -tryCuePill :: PillFile -> IO () -tryCuePill pill = - loadNoun (show pill) >>= \case Nothing -> print "nil" - Just (Atom _) -> print "atom" - Just (Cell _ _) -> print "cell" - -tryCueJamPill :: PillFile -> IO () -tryCueJamPill pill = do - n <- loadNoun (show pill) >>= \case - Nothing -> print "failure" >> pure (Atom 0) - Just n@(Atom _) -> print "atom" >> pure n - Just n@(Cell _ _) -> print "cell" >> pure n - - bs <- evaluate (force (jamBS n)) - - print ("jam size: " <> show (length bs)) - -data PillFile = Brass | Ivory | Solid - -instance Show PillFile where - show = \case - Brass -> "./bin/brass.pill" - Solid -> "./bin/solid.pill" - Ivory -> "./bin/ivory.pill" diff --git a/pkg/hs/urbit-king/lib/Urbit/Prelude.hs b/pkg/hs/urbit-king/lib/Urbit/Prelude.hs deleted file mode 100644 index 8d29b6de6..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Prelude.hs +++ /dev/null @@ -1,72 +0,0 @@ -{-| - Convenient Re-Exports --} - -module Urbit.Prelude - ( module ClassyPrelude - , module Control.Arrow - , module Control.Lens - , module Data.Acquire - , module Data.RAcquire - , module Data.Void - , module Urbit.Noun - , module Text.Show.Pretty - , module Text.Printf - , module RIO - , io, rio - , logTrace - , acquireWorker, acquireWorkerBound - , hark - ) where - -import ClassyPrelude -import Urbit.Noun - -import Control.Arrow ((<<<), (>>>)) -import Control.Lens hiding (Each, Index, cons, index, snoc, uncons, unsnoc, - (<.>), (<|)) -import Data.Acquire (Acquire, mkAcquire, with) -import Data.RAcquire (RAcquire, mkRAcquire, rwith) -import Data.RAcquire (MonadAcquire(..), MonadRIO(..)) -import Data.Void (Void, absurd) -import Text.Printf (printf) -import Text.Show.Pretty (pPrint, ppShow) - -import RIO (RIO, runRIO) -import RIO (Utf8Builder, display, displayShow) -import RIO (threadDelay) -import RIO (HasLogFunc, LogFunc, LogLevel(..), logDebug, logError, logFuncL, - logInfo, logOptionsHandle, logOther, logWarn, mkLogFunc, - setLogMinLevel, setLogUseLoc, setLogUseTime, withLogFunc) - -import qualified RIO - -io :: MonadIO m => IO a -> m a -io = liftIO - -rio :: MonadRIO m => RIO e a -> m e a -rio = liftRIO - -logTrace :: HasLogFunc e => Utf8Builder -> RIO e () -logTrace = logOther "trace" - --- | Composes a log message out of textual components. -hark :: [Text] -> Utf8Builder -hark = RIO.displayBytesUtf8 . foldMap encodeUtf8 - --- Utils for Spawning Worker Threads ------------------------------------------- - -acquireWorker :: HasLogFunc e => Text -> RIO e () -> RAcquire e (Async ()) -acquireWorker nam act = mkRAcquire (async act) kill - where - kill tid = do - logInfo ("Killing worker thread: " <> display nam) - cancel tid - -acquireWorkerBound :: HasLogFunc e => Text -> RIO e () -> RAcquire e (Async ()) -acquireWorkerBound nam act = mkRAcquire (asyncBound act) kill - where - kill tid = do - logInfo ("Killing worker thread: " <> display nam) - cancel tid - diff --git a/pkg/hs/urbit-king/lib/Urbit/Timer.hs b/pkg/hs/urbit-king/lib/Urbit/Timer.hs deleted file mode 100644 index 8664e8e88..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Timer.hs +++ /dev/null @@ -1,45 +0,0 @@ -module Urbit.Timer ( Timer(..), init, stop, start - , Sys.getSystemTime, sysTimeGapMicroSecs - ) where - -import Data.IORef -import Prelude hiding (init) - -import qualified Data.Time.Clock.System as Sys -import qualified GHC.Event as Ev - - --- Timer Stuff ----------------------------------------------------------------- - -data Timer = Timer - { bState :: IORef (Maybe Ev.TimeoutKey) - , bManager :: Ev.TimerManager - } - -init :: IO Timer -init = do - st <- newIORef Nothing - man <- Ev.getSystemTimerManager - pure (Timer st man) - -sysTimeGapMicroSecs :: Sys.SystemTime -> Sys.SystemTime -> Int -sysTimeGapMicroSecs (Sys.MkSystemTime xSec xNs) (Sys.MkSystemTime ySec yNs) = - (+) (1_000_000 * fromIntegral (ySec - xSec)) - ((fromIntegral yNs - fromIntegral xNs) `quot` 1000) - -start :: Timer -> Sys.SystemTime -> IO () -> IO () -start timer@(Timer vSt man) time cb = do - let fire = cb >> stop timer - stop timer - now <- Sys.getSystemTime - let sleep = sysTimeGapMicroSecs now time - -- print (now, time, "->", sleep) - if (sleep <= 0) then fire else do - key <- Ev.registerTimeout man sleep fire - atomicWriteIORef vSt $! Just key - -stop :: Timer -> IO () -stop (Timer vSt man) = - atomicModifyIORef' vSt (Nothing,) >>= \case - Just key -> Ev.unregisterTimeout man key - Nothing -> pure () diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Ames.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Ames.hs deleted file mode 100644 index af5b9de76..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Ames.hs +++ /dev/null @@ -1,368 +0,0 @@ --- This is required due to the use of 'Void' in a constructor slot in --- combination with 'deriveNoun' which generates an unreachable pattern. -{-# OPTIONS_GHC -Wno-overlapping-patterns #-} - -{-| - Ames IO Driver --} - -module Urbit.Vere.Ames (ames, ames', PacketOutcome(..)) where - -import Urbit.Prelude - -import Network.Socket -import Urbit.Arvo hiding (Fake) -import Urbit.King.Config -import Urbit.King.Scry -import Urbit.Vere.Ames.LaneCache -import Urbit.Vere.Ames.Packet -import Urbit.Vere.Pier.Types -import Urbit.Vere.Ports - -import Data.Serialize (decode, encode) -import Urbit.King.App (HasKingId(..), HasPierEnv(..)) -import Urbit.Vere.Ames.DNS (NetworkMode(..), ResolvServ(..)) -import Urbit.Vere.Ames.DNS (galaxyPort, resolvServ) -import Urbit.Vere.Ames.UDP (UdpServ(..), fakeUdpServ, realUdpServ) -import Urbit.Vere.Stat (AmesStat(..), bump, bump') - - --- Constants ------------------------------------------------------------------- - --- | How many unprocessed ames packets to allow in the queue before we start --- dropping incoming packets. -queueBound :: Word -queueBound = 1000 - --- | How often, measured in number of packets dropped, we should announce packet --- loss. -packetsDroppedPerComplaint :: Word -packetsDroppedPerComplaint = 1000 - - --- Types ----------------------------------------------------------------------- - -type Version = Word8 - -data AmesDrv = AmesDrv - { aTurfs :: TVar (Maybe [Turf]) - , aVersion :: TVar (Maybe Version) - , aUdpServ :: UdpServ - , aResolvr :: ResolvServ - , aVersTid :: Async () - , aRecvTid :: Async () - } - -data PacketOutcome - = Intake - | Ouster - - --- Utils ----------------------------------------------------------------------- - -listenPort :: NetworkMode -> Ship -> PortNumber -listenPort m s | s < 256 = galaxyPort m (fromIntegral s) -listenPort m _ = 0 -- I don't care, just give me any port. - -localhost :: HostAddress -localhost = tupleToHostAddress (127, 0, 0, 1) - -inaddrAny :: HostAddress -inaddrAny = tupleToHostAddress (0, 0, 0, 0) - - -modeAddress :: NetworkMode -> Maybe HostAddress -modeAddress = \case - Fake -> Just localhost - Localhost -> Just localhost - Real -> Just inaddrAny - NoNetwork -> Nothing - -okFakeAddr :: AmesDest -> Bool -okFakeAddr = \case - EachYes _ -> True - EachNo (AAIpv4 (Ipv4 a) _) -> a == localhost - -localAddr :: NetworkMode -> AmesDest -> SockAddr -localAddr mode = \case - EachYes g -> SockAddrInet (galaxyPort mode g) localhost - EachNo (AAIpv4 _ p) -> SockAddrInet (fromIntegral p) localhost - -bornEv :: KingId -> Ev -bornEv inst = EvBlip $ BlipEvNewt $ NewtEvBorn (fromIntegral inst, ()) () - -hearEv :: PortNumber -> HostAddress -> ByteString -> Ev -hearEv p a bs = - EvBlip $ BlipEvAmes $ AmesEvHear () (ipDest p a) (MkBytes bs) - -ipDest :: PortNumber -> HostAddress -> AmesDest -ipDest p a = EachNo $ AAIpv4 (Ipv4 a) (fromIntegral p) - - --------------------------------------------------------------------------------- - -netMode :: HasNetworkConfig e => Bool -> RIO e NetworkMode -netMode isFake = do - netMode <- view (networkConfigL . ncNetMode) - noAmes <- view (networkConfigL . ncNoAmes) - pure $ case (noAmes, isFake, netMode) of - (True, _ , _ ) -> NoNetwork - (_ , _ , NMNone ) -> NoNetwork - (_ , True, _ ) -> Fake - (_ , _ , NMNormal ) -> Real - (_ , _ , NMLocalhost) -> Localhost - -udpPort :: HasNetworkConfig e => Bool -> Ship -> RIO e PortNumber -udpPort isFake who = do - mode <- netMode isFake - mPort <- view (networkConfigL . ncAmesPort) - pure $ maybe (listenPort mode who) fromIntegral mPort - -udpServ :: (HasLogFunc e, HasNetworkConfig e, HasPortControlApi e) - => Bool - -> Ship - -> AmesStat - -> RIO e UdpServ -udpServ isFake who stat = do - mode <- netMode isFake - port <- udpPort isFake who - case modeAddress mode of - Nothing -> fakeUdpServ - Just host -> realUdpServ port host stat - -_bornFailed :: e -> WorkError -> IO () -_bornFailed env _ = runRIO env $ do - pure () -- TODO What can we do? - -ames' - :: HasPierEnv e - => Ship - -> Bool - -> AmesStat - -> ScryFunc - -> (Text -> RIO e ()) - -> RIO e ([Ev], RAcquire e (DriverApi NewtEf)) -ames' who isFake stat scry stderr = do - -- Unfortunately, we cannot use TBQueue because the only behavior - -- provided for when full is to block the writer. The implementation - -- below uses materially the same data structures as TBQueue, however. - ventQ :: TQueue EvErr <- newTQueueIO - avail :: TVar Word <- newTVarIO queueBound - let - enqueuePacket p = do - vail <- readTVar avail - if vail > 0 - then do - modifyTVar' avail (subtract 1) - writeTQueue ventQ p - pure Intake - else do - _ <- readTQueue ventQ - writeTQueue ventQ p - pure Ouster - dequeuePacket = do - pM <- tryReadTQueue ventQ - when (isJust pM) $ modifyTVar' avail (+ 1) - pure pM - - env <- ask - let (bornEvs, startDriver) = ames env who isFake stat scry enqueuePacket stderr - - let runDriver = do - diOnEffect <- startDriver - let diEventSource = fmap RRWork <$> dequeuePacket - pure (DriverApi {..}) - - pure (bornEvs, runDriver) - - -{-| - inst -- Process instance number. - who -- Which ship are we? - enqueueEv -- Queue-event action. - mPort -- Explicit port override from command line arguments. - - 4096 is a reasonable number for recvFrom. Packets of that size are - not possible on the internet. - - TODO verify that the KingIds match on effects. --} -ames - :: forall e - . (HasLogFunc e, HasNetworkConfig e, HasPortControlApi e, HasKingId e) - => e - -> Ship - -> Bool - -> AmesStat - -> ScryFunc - -> (EvErr -> STM PacketOutcome) - -> (Text -> RIO e ()) - -> ([Ev], RAcquire e (NewtEf -> IO ())) -ames env who isFake stat scry enqueueEv stderr = (initialEvents, runAmes) - where - king = fromIntegral (env ^. kingIdL) - - initialEvents :: [Ev] - initialEvents = [bornEv king] - - runAmes :: RAcquire e (NewtEf -> IO ()) - runAmes = do - mode <- rio (netMode isFake) - drv <- mkRAcquire start stop - pure (handleEffect drv mode) - - start :: RIO e AmesDrv - start = do - mode <- rio (netMode isFake) - cachedScryLane <- cache scryLane - - aTurfs <- newTVarIO Nothing - aVersion <- newTVarIO Nothing - aVersTid <- trackVersionThread aVersion - aUdpServ <- udpServ isFake who stat - aResolvr <- resolvServ aTurfs (usSend aUdpServ) stderr - aRecvTid <- queuePacketsThread - aVersion - cachedScryLane - (send aUdpServ aResolvr mode) - aUdpServ - stat - - pure (AmesDrv { .. }) - - hearFailed AmesStat {..} = runRIO env . \case - RunSwap{} -> bump asSwp - RunBail gs -> do - for gs \(t, es) -> - for es \e -> - logWarn $ hark - ["ames: goof: ", unTerm t, ": ", tankToText e] - bump asBal - RunOkay{} -> bump asOky - - trackVersionThread :: HasLogFunc e => TVar (Maybe Version) -> RIO e (Async ()) - trackVersionThread versSlot = async $ forever do - scryVersion >>= \case - Just v -> do - v0 <- readTVarIO versSlot - atomically $ writeTVar versSlot (Just v) - if (v0 == Just v) - then logInfo $ displayShow ("ames: proto version unchanged at", v) - else stderr ("ames: protocol version now " <> tshow v) - - Nothing -> logError "ames: could not scry for version" - - threadDelay (10 * 60 * 1_000_000) -- 10m - - queuePacketsThread :: HasLogFunc e - => TVar (Maybe Version) - -> (Ship -> RIO e (Maybe [AmesDest])) - -> (AmesDest -> ByteString -> RIO e ()) - -> UdpServ - -> AmesStat - -> RIO e (Async ()) - queuePacketsThread vers lan forward UdpServ{..} s@(AmesStat{..}) = async $ forever $ do - -- port number, host address, bytestring - (p, a, b) <- atomically (bump' asRcv >> usRecv) - ver <- readTVarIO vers - case decode b of - Right (pkt@Packet {..}) | ver == Nothing || ver == Just pktVersion -> do - logDebug $ displayShow ("ames: bon packet", pkt, showUD $ bytesAtom b) - - if pktRcvr == who - then do - bump asSup - serfsUp p a b - else lan pktRcvr >>= \case - Just ls - | dest:_ <- filter notSelf ls - -> do - bump asFwd - forward dest $ encode pkt - { pktOrigin = pktOrigin - <|> Just (AAIpv4 (Ipv4 a) (fromIntegral p)) } - where - notSelf (EachYes g) = who /= Ship (fromIntegral g) - notSelf (EachNo _) = True - - _ -> do - bump asDrt - logInfo $ displayShow ("ames: dropping unroutable", pkt) - - Right pkt -> do - bump asDvr - logInfo $ displayShow ("ames: dropping ill-versed", pkt, ver) - - -- XX better handle misversioned or illegible packets. - -- Remarks from 67f06ce5, pkg/urbit/vere/io/ames.c, L1010: - -- - -- [There are] two protocol-change scenarios [which we must think about]: - -- - -- - packets using old protocol versions from our sponsees - -- these must be let through, and this is a transitive condition; - -- they must also be forwarded where appropriate - -- they can be validated, as we know their semantics - -- - -- - packets using newer protocol versions - -- these should probably be let through, or at least - -- trigger printfs suggesting upgrade. - -- they cannot be filtered, as we do not know their semantics - -- - Left e -> do - bump asDml - logInfo $ displayShow ("ames: dropping malformed", e) - - where - serfsUp p a b = - atomically (enqueueEv (EvErr (hearEv p a b) (hearFailed s))) >>= \case - Intake -> bump asSrf - Ouster -> do - d <- atomically $ do - bump' asQuf - readTVar asQuf - when (d `rem` packetsDroppedPerComplaint == 1) $ - logWarn "ames: queue full; dropping inbound packets" - - stop :: forall e. AmesDrv -> RIO e () - stop AmesDrv {..} = io $ do - usKill aUdpServ - rsKill aResolvr - cancel aVersTid - cancel aRecvTid - - handleEffect :: AmesDrv -> NetworkMode -> NewtEf -> IO () - handleEffect drv@AmesDrv {..} mode = runRIO env . \case - NewtEfTurf (_id, ()) turfs -> do - atomically $ writeTVar aTurfs (Just turfs) - - NewtEfSend (_id, ()) dest (MkBytes bs) -> do - atomically (readTVar aTurfs) >>= \case - Nothing -> stderr "ames: send before turfs" >> pure () - Just turfs -> send aUdpServ aResolvr mode dest bs - - send :: UdpServ - -> ResolvServ - -> NetworkMode - -> AmesDest - -> ByteString - -> RIO e () - send udpServ resolvr mode dest byt = do - let to adr = io (usSend udpServ adr byt) - - case (mode, dest) of - (NoNetwork, _ ) -> pure () - (Fake , _ ) -> when (okFakeAddr dest) $ to (localAddr Fake dest) - (Localhost, _ ) -> to (localAddr Localhost dest) - (Real , ra) -> ra & \case - EachYes gala -> io (rsSend resolvr gala byt) - EachNo addr -> to (ipv4Addr addr) - - scryVersion :: HasLogFunc e => RIO e (Maybe Version) - scryVersion = scryNow scry "ax" "" ["protocol", "version"] - - scryLane :: HasLogFunc e - => Ship - -> RIO e (Maybe [AmesDest]) - scryLane ship = scryNow scry "ax" "" ["peers", tshow ship, "forward-lane"] - - ipv4Addr (AAIpv4 a p) = SockAddrInet (fromIntegral p) (unIpv4 a) diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Ames/DNS.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Ames/DNS.hs deleted file mode 100644 index 442e23fac..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Ames/DNS.hs +++ /dev/null @@ -1,217 +0,0 @@ -{-| - Handles sending packets to galaxies. We need to get their IP addresses - from DNS, which is more complicated. - --- Asynchronous thread per galaxy which handles domain resolution, and can --- block its own queue of ByteStrings to send. --- --- Maybe perform the resolution asynchronously, injecting into the resolver --- queue as a message. --- --- TODO: Figure out how the real haskell time library works. - --- We've failed to lookup the IP. Drop the outbound packet --- because we have no IP for our galaxy, including possible --- previous IPs. - -{- -- Sending Packets to Galaxies. - - Each galaxy has it's own DNS resolution thread. - - Initially, no threads are started. - - To send a message to a galaxy, - - Check to see if it already has a resolution thread. - - If it does, pass the packet to that thread. - - If it doesn't, start a new thread and give it the packet. -- Galaxy resolution threads work as follows: - - First, they are given: - - They know which galaxy they are responsible for. - - They have access to the turfs TVar (shared state with Ames driver). - - They can be given packets (to be send to their galaxy). - - They must be given a way to send UDP packets. - - Next, we loop forever - - In the loop we track: - - the last-known IP address. - - the time when we last looked up the IP address. - - We wait to be given a packet. - - We get the IP address. - - If we looked up the IP address in the last 5 minute, use the - cached IP address. - - Just use the one from last time. - - Otherwise, - - Do a DNS lookup. - - Go through the turf list one item at a time. - - Try each one. - - If it resolves to one-or-more IP addresses, - - Use the first one. - - If it resolves to zero IP addresses, move on to the next turf. - - If none of the turfs can be used to resolve the IP address, - then we don't know where the galaxy is. - - Drop the packet. --} --} - -module Urbit.Vere.Ames.DNS - ( NetworkMode(..) - , ResolvServ(..) - , resolvServ - , galaxyPort - , renderGalaxy - ) -where - -import Urbit.Prelude - -import Network.Socket -import Urbit.Arvo hiding (Fake) - -import qualified Data.Map.Strict as M -import qualified Urbit.Noun.Time as Time -import qualified Urbit.Ob as Ob - - --- Types ----------------------------------------------------------------------- - -data NetworkMode = Fake | Localhost | Real | NoNetwork - deriving (Eq, Ord, Show) - -data ResolvServ = ResolvServ - { rsSend :: Galaxy -> ByteString -> IO () - , rsKill :: IO () - } - - --- Utils ----------------------------------------------------------------------- - -galaxyPort :: NetworkMode -> Galaxy -> PortNumber -galaxyPort Fake (Patp g) = fromIntegral g + 31337 -galaxyPort Localhost (Patp g) = fromIntegral g + 13337 -galaxyPort Real (Patp g) = fromIntegral g + 13337 -galaxyPort NoNetwork _ = fromIntegral 0 - -turfText :: Turf -> Text -turfText = intercalate "." . reverse . fmap unCord . unTurf - -renderGalaxy :: Galaxy -> Text -renderGalaxy = Ob.renderPatp . Ob.patp . fromIntegral . unPatp - -galaxyHostname :: Galaxy -> Turf -> Text -galaxyHostname g t = galaName g ++ "." ++ turfText t - where - stripSig :: Text -> Text - stripSig inp = fromMaybe inp (stripPrefix "~" inp) - - galaName :: Galaxy -> Text - galaName = stripSig . renderGalaxy - -resolv :: Galaxy -> [Turf] -> IO (Maybe (Turf, Text, PortNumber, SockAddr)) -resolv gal = go - where - go = \case - [] -> pure Nothing - turf : turfs -> do - let host = galaxyHostname gal turf - port = galaxyPort Real gal - getAddrInfo Nothing (Just (unpack host)) (Just (show port)) >>= \case - [] -> go turfs - ip : _ -> pure $ Just (turf, host, port, addrAddress ip) - -doResolv - :: HasLogFunc e - => Galaxy - -> (Time.Wen, Maybe SockAddr) - -> [Turf] - -> (Text -> RIO e ()) - -> RIO e (Maybe SockAddr, Time.Wen) -doResolv gal (prevWen, prevIP) turfs stderr = do - current <- io $ Time.now - if (Time.gap current prevWen ^. Time.secs) < 300 - then pure (prevIP, prevWen) - else do - tim <- io (Time.now) - io (resolv gal turfs) >>= \case - Nothing -> do - stderr $ "ames: czar at " ++ galStr ++ ": not found" - logInfo $ displayShow ("(ames) Failed to lookup IP for ", gal) - pure (prevIP, tim) - Just (turf, host, port, addr) -> do - when (Just addr /= prevIP) (printCzar addr) - logInfo $ displayShow ("(ames) Looked up ", host, port, turf, addr) - pure (Just addr, tim) - where - galStr = renderGalaxy gal - printCzar addr = stderr $ "ames: czar " ++ galStr ++ ": ip " ++ tshow addr - - -resolvWorker - :: forall e - . HasLogFunc e - => Galaxy - -> TVar (Maybe [Turf]) - -> TVar (Time.Wen, Maybe SockAddr) - -> STM ByteString - -> (SockAddr -> ByteString -> IO ()) - -> (Text -> RIO e ()) - -> RIO e (Async ()) -resolvWorker gal vTurfs vLast waitMsg send stderr = async (forever go) - where - logDrop = - logInfo $ displayShow ("(ames) Dropping packet; no ip for galaxy ", gal) - - go :: RIO e () - go = do - (packt, turfs, (lastTime, lastAddr)) <- atomically - ((,,) <$> waitMsg <*> readTVar vTurfs <*> readTVar vLast) - - (newAddr, newTime) <- doResolv gal - (lastTime, lastAddr) - (fromMaybe [] turfs) - stderr - - maybe logDrop (\ip -> io (send ip packt)) newAddr - - atomically $ writeTVar vLast (newTime, newAddr) - - -resolvServ - :: HasLogFunc e - => TVar (Maybe [Turf]) - -> (SockAddr -> ByteString -> IO ()) - -> (Text -> RIO e ()) - -> RIO e ResolvServ -resolvServ vTurfs send stderr = do - vGala <- newTVarIO (mempty :: Map Galaxy (Async (), TQueue ByteString)) - vDead <- newTVarIO False - envir <- ask - - let spawnWorker :: Galaxy -> IO (Async (), TQueue ByteString) - spawnWorker gal = runRIO envir $ do - que <- newTQueueIO - las <- newTVarIO (Time.unixEpoch, Nothing) - tid <- resolvWorker gal vTurfs las (readTQueue que) send stderr - pure (tid, que) - - let getWorker :: Galaxy -> IO (Async (), TQueue ByteString) - getWorker gal = do - (fmap (lookup gal) $ atomically $ readTVar vGala) >>= \case - Just (tid, que) -> do - pure (tid, que) - Nothing -> do - (tid, que) <- spawnWorker gal - atomically $ modifyTVar' vGala (M.insert gal (tid, que)) - pure (tid, que) - - let doSend :: Galaxy -> ByteString -> IO () - doSend gal byt = do - dead <- atomically (readTVar vDead) - unless dead $ do - (_, que) <- getWorker gal - atomically (writeTQueue que byt) - - let doKill :: IO () - doKill = do - galas <- atomically $ do - writeTVar vDead True - readTVar vGala - for_ galas (cancel . fst) - - pure (ResolvServ doSend doKill) diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Ames/LaneCache.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Ames/LaneCache.hs deleted file mode 100644 index b7eb896ed..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Ames/LaneCache.hs +++ /dev/null @@ -1,64 +0,0 @@ -module Urbit.Vere.Ames.LaneCache (cache) where - -import Urbit.Prelude - -import qualified Data.HashPSQ as P - -import Urbit.Noun.Time - -expiry :: Gap -expiry = (2 * 60) ^. from secs - -bound :: Int -bound = 1_000 - --- | An "upside down" time for use as a priority. -newtype New = New Wen - deriving newtype (Eq, Ord) - -new :: Wen -> New -new = New . negate - -wen :: New -> Wen -wen (New w) = negate w - --- | Given a new, find an older new corresponding to `expiry` ago. -lag :: New -> New -lag n = new (addGap (wen n) expiry) - -trim :: (Hashable a, Ord a, Ord b) => P.HashPSQ a b c -> P.HashPSQ a b c -trim p = if P.size p > bound then P.deleteMin p else p - -cache :: forall a b m n - . (Ord a, Hashable a, MonadIO m, MonadIO n) - => (a -> m b) - -> n (a -> m b) -cache act = do - cas <- newTVarIO (P.empty :: P.HashPSQ a New b) - - let fun x = P.lookup x <$> readTVarIO cas >>= \case - Nothing -> thru - Just (n, v) -> do - let t = wen n - t' <- io now - if gap t' t > expiry - then thru - else pure v - where - -- Insert a key into the map, simultaneously removing *all* stale - -- entries. Since insertion is linear in the size of the map, - -- presumably it's not horrible to do it this way. The alternative - -- would be to have a thread doing a purge every 10s or something, and - -- then we'd have to be in RAcquire. - up :: a -> New -> b -> P.HashPSQ a New b -> P.HashPSQ a New b - up k n v ps = trim - $ P.insert k n v - $ snd $ P.atMostView (lag n) ps - thru :: m b - thru = do - n <- new <$> io now - v <- act x - atomically $ modifyTVar' cas $ up x n v - pure v - - pure fun diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Ames/Packet.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Ames/Packet.hs deleted file mode 100644 index ea878d533..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Ames/Packet.hs +++ /dev/null @@ -1,165 +0,0 @@ -{-| - Parsing of Ames packets --} - -module Urbit.Vere.Ames.Packet where - -import Urbit.Prelude - -import Control.Monad.Fail -import Data.Bits -import Data.LargeWord -import Data.List (genericIndex) -import Data.Serialize - -import Urbit.Arvo (AmesAddress(..), Ipv4(..), Port(..)) - -data Packet = Packet - { pktVersion :: Word3 - , pktSndr :: Ship - , pktRcvr :: Ship - , pktSndrTick :: Word4 - , pktRcvrTick :: Word4 - , pktOrigin :: Maybe AmesAddress - , pktContent :: ByteString - } - deriving Eq - -instance Show Packet where - show Packet {..} - = "Packet {pktVersion = " - <> show pktVersion - <> ", pktSndr = " - <> show pktSndr - <> ", pktRcvr = " - <> show pktRcvr - <> ", pktSndrTick = " - <> show pktSndrTick - <> ", pktRcvrTick = " - <> show pktRcvrTick - <> ", pktOrigin = " - <> show pktOrigin - <> ", pktContent = " - <> showUD (bytesAtom pktContent) - <> "}" - -{- --- Wire format -data PacketHeader = PacketHeader - { pktIsAmes :: Bool -- sim_o - , pktVersion :: Word3 -- ver_y - , pktSndrClass :: ShipClass -- sac_y - , pktRcvrClass :: ShipClass -- rac_y - , pktChecksum :: Word20 -- mug_l - , pktIsRelayed :: Bool -- rel_o - } - deriving Eq - -data PacketBody = PacketBody - { pktSndr :: Ship -- sen_d - , pktRcvr :: Ship -- rec_d - , pktSndrTick :: Word4 -- sic_y - , pktRcvrTick :: Word4 -- ric_y - , pktContent :: ByteString -- (con_s, con_y) - , pktOrigin :: Maybe AmesAddress -- rog_d - } - deriving Eq --} - -type Word3 = Word8 -type Word4 = Word8 -type Word20 = Word32 - -data ShipClass - = Lord - | Planet - | Moon - | Comet - deriving (Eq, Show) - -muk :: ByteString -> Word20 -muk bs = mugBS bs .&. (2 ^ 20 - 1) - -putAmesAddress :: Putter AmesAddress -putAmesAddress = \case - AAIpv4 (Ipv4 ip) (Port port) -> putWord32le ip >> putWord16le port - -instance Serialize Packet where - get = do - -- header - head <- getWord32le - -- skip first three bits - let isAmes = testBit head 3 & not - let pktVersion = shiftR head 4 .&. 0b111 & fromIntegral - let sndrRank = shiftR head 7 .&. 0b11 - let rcvrRank = shiftR head 9 .&. 0b11 - let checksum = shiftR head 11 .&. (2 ^ 20 - 1) - let isRelayed = testBit head 31 & not -- loobean - let sndrClass = genericIndex [Lord, Planet, Moon, Comet] sndrRank - let rcvrClass = genericIndex [Lord, Planet, Moon, Comet] rcvrRank - guard isAmes - - pktOrigin <- if isRelayed - then Just <$> get - else pure Nothing - - -- body - lookAhead $ do - len <- remaining - body <- getBytes len - let chk = muk body - when (checksum /= chk) $ - fail ("checksum mismatch: expected " <> show checksum - <> "; got " <> show chk) - - tick <- getWord8 - let pktSndrTick = tick .&. 0b1111 - let pktRcvrTick = shiftR tick 4 - - pktSndr <- getShip sndrClass - pktRcvr <- getShip rcvrClass - - len <- remaining - pktContent <- getBytes len - - pure Packet{..} - where - getShip = fmap Ship . \case - Lord -> fromIntegral <$> getWord16le - Planet -> fromIntegral <$> getWord32le - Moon -> fromIntegral <$> getWord64le - Comet -> LargeKey <$> getWord64le <*> getWord64le - - put Packet{..} = do - let (sndR, putSndr) = putShipGetRank pktSndr - let (rcvR, putRcvr) = putShipGetRank pktRcvr - - let body = runPut $ do - putWord8 $ (pktSndrTick .&. 0b1111) - .|. shiftL (pktRcvrTick .&. 0b1111) 4 - putSndr - putRcvr - putByteString pktContent - - let vers = fromIntegral pktVersion .&. 0b111 - let chek = muk body - - -- skip first 3 bytes, set 4th to yes (0) for "is ames" - let head = shiftL vers 4 - .|. shiftL sndR 7 - .|. shiftL rcvR 9 - .|. shiftL chek 11 - .|. if isJust pktOrigin then 0 else bit 31 - - putWord32le head - case pktOrigin of - Just o -> put o - Nothing -> pure () - putByteString body - - where - putShipGetRank (Ship (LargeKey p q)) = case q of - 0 | p < 2 ^ 16 -> (0, putWord16le $ fromIntegral p) -- lord - | p < 2 ^ 32 -> (1, putWord32le $ fromIntegral p) -- planet - | otherwise -> (2, putWord64le $ fromIntegral p) -- moon - _ -> (3, putWord64le p >> putWord64le q) -- comet diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Ames/UDP.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Ames/UDP.hs deleted file mode 100644 index 018930632..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Ames/UDP.hs +++ /dev/null @@ -1,274 +0,0 @@ -{- | - Raw UDP Server used by Ames driver. - - 1. Opens a UDP socket and makes sure that it stays open. - - - If can't open the port, wait and try again repeatedly. - - If there is an error reading to or writing from the open socket, - close it and open another, making sure, however, to reuse the - same port - NOTE: It's not clear what, if anything, closing and reopening - the socket does. We're keeping this behavior out of conservatism - until we understand it better. - - 2. Receives packets from the socket. - - - When packets come in from the socket, they go into a bounded queue. - - If the queue is full, the packet is dropped. - - If the socket is closed, wait and try again repeatedly. - - `usRecv` gets the first packet from the queue. - - 3. Sends packets to the socket. - - - Packets sent to `usSend` enter a bounded queue. - - If that queue is full, the packet is dropped. - - Packets are taken off the queue one at a time. - - If the socket is closed (or broken), the packet is dropped. - - 4. Runs until `usKill` is run, then all threads are killed and the - socket is closed. --} - -module Urbit.Vere.Ames.UDP - ( UdpServ(..) - , fakeUdpServ - , realUdpServ - ) -where - -import Urbit.Prelude -import Urbit.Vere.Ports - -import Network.Socket - -import Control.Monad.STM (retry) -import Network.Socket.ByteString (recvFrom, sendTo) -import Urbit.Vere.Stat (AmesStat(..), bump) - --- Types ----------------------------------------------------------------------- - -data UdpServ = UdpServ - { usSend :: SockAddr -> ByteString -> IO () - , usRecv :: STM (PortNumber, HostAddress, ByteString) - , usKill :: IO () - } - - --- Utils ----------------------------------------------------------------------- - -{- | - Writes to queue and returns `True` unless the queue is full, then do - nothing and return `False`. --} -tryWriteTBQueue :: TBQueue x -> x -> STM Bool -tryWriteTBQueue q x = do - isFullTBQueue q >>= \case - True -> pure False - False -> writeTBQueue q x $> True - -{- | - Open a UDP socket and bind it to a port --} -doBind :: PortNumber -> HostAddress -> IO (Either IOError Socket) -doBind por hos = tryIOError $ do - sok <- io $ socket AF_INET Datagram defaultProtocol - () <- io $ bind sok (SockAddrInet por hos) - pure sok - -{- | - Open a UDP socket and bind it to a port. - - If this fails, wait 250ms and repeat forever. --} -forceBind :: HasLogFunc e => PortNumber -> HostAddress -> RIO e Socket -forceBind por hos = go - where - go = do - logInfo (display ("AMES: UDP: Opening socket on port " <> tshow por)) - io (doBind por hos) >>= \case - Right sk -> do - logInfo (display ("AMES: UDP: Opened socket on port " <> tshow por)) - pure sk - Left err -> do - logInfo (display ("AMES: UDP: " <> tshow err)) - logInfo ("AMES: UDP: Failed to open UDP socket. Waiting") - threadDelay 250_000 - go - -{- | - Attempt to send a packet to a socket. - - If it fails, return `False`. Otherwise, return `True`. --} -sendPacket :: HasLogFunc e => ByteString -> SockAddr -> Socket -> RIO e Bool -sendPacket fullBytes adr sok = do - logDebug $ displayShow ("AMES", "UDP", "Sending packet.") - res <- io $ tryIOError $ go fullBytes - case res of - Left err -> do - logError $ displayShow ("AMES", "UDP", "Failed to send packet", err) - pure False - Right () -> do - logDebug $ displayShow ("AMES", "UDP", "Packet sent.") - pure True - where - go byt = do - sent <- sendTo sok byt adr - when (sent /= length byt) $ do - go (drop sent byt) - -{- | - Attempt to receive a packet from a socket. - - - If an exception is throw, return `Left exn`. - - If it wasn't an IPv4 packet, return `Right Nothing`. - - Otherwise, return `Right (Just packet)`. --} -recvPacket - :: HasLogFunc e - => Socket - -> RIO e (Either IOError (Maybe (ByteString, PortNumber, HostAddress))) -recvPacket sok = do - io (tryIOError $ recvFrom sok 4096) <&> \case - Left exn -> Left exn - Right (b, SockAddrInet p a) -> Right (Just (b, p, a)) - Right (_, _ ) -> Right Nothing - - --- Fake Server for No-Networking Mode ------------------------------------------ - -{- | - Fake UDP API for no-networking configurations. --} -fakeUdpServ :: HasLogFunc e => RIO e UdpServ -fakeUdpServ = do - logInfo $ displayShow ("AMES", "UDP", "\"Starting\" fake UDP server.") - pure UdpServ { .. } - where - usSend = \_ _ -> pure () - usRecv = retry - usKill = pure () - - --- Real Server ----------------------------------------------------------------- - -{- | - Real UDP server. See module-level docs. --} -realUdpServ - :: forall e - . (HasLogFunc e, HasPortControlApi e) - => PortNumber - -> HostAddress - -> AmesStat - -> RIO e UdpServ -realUdpServ startPort hos sat = do - logInfo $ displayShow ("AMES", "UDP", "Starting real UDP server.") - - env <- ask - - vSock <- newTVarIO Nothing - vFail <- newEmptyTMVarIO - qSend <- newTBQueueIO 100 -- TODO Tuning - qRecv <- newTBQueueIO 100 -- TODO Tuning - - {- - If reading or writing to a socket fails, unbind it and tell the - socket-open thread to close it and open another. - - This is careful about edge-cases. In any of these cases, do nothing. - - - If vSock isn't set to the socket we used, do nothing. - - If vFail is already set (another thread signaled failure already). - -} - let signalBrokenSocket :: Socket -> RIO e () - signalBrokenSocket sock = do - logInfo $ displayShow ("AMES", "UDP" - , "Socket broken. Requesting new socket" - ) - atomically $ do - mSock <- readTVar vSock - mFail <- tryReadTMVar vFail - when (mSock == Just sock && mFail == Nothing) $ do - putTMVar vFail sock - writeTVar vSock Nothing - - enqueueRecvPacket :: PortNumber -> HostAddress -> ByteString -> RIO e () - enqueueRecvPacket p a b = do - did <- atomically (tryWriteTBQueue qRecv (p, a, b)) - when (did == False) $ do - bump (asUqf sat) - logWarn $ displayShow $ ("AMES", "UDP",) - "Dropping inbound packet because queue is full." - - enqueueSendPacket :: SockAddr -> ByteString -> RIO e () - enqueueSendPacket a b = do - did <- atomically (tryWriteTBQueue qSend (a, b)) - when (did == False) $ do - logWarn "AMES: UDP: Dropping outbound packet because queue is full." - let opener por = do - logInfo $ displayShow $ ("AMES", "UDP", "Trying to open socket, port",) - por - sk <- forceBind por hos - sn <- io $ getSocketName sk - sp <- io $ socketPort sk - logInfo $ displayShow $ ("AMES", "UDP", "Got socket", sn, sp) - - let waitForRelease = do - atomically (writeTVar vSock (Just sk)) - broken <- atomically (takeTMVar vFail) - logWarn "AMES: UDP: Closing broken socket." - io (close broken) - - case sn of - (SockAddrInet boundPort _) -> - -- When we're on IPv4, maybe port forward at the NAT. - rwith (requestPortAccess $ fromIntegral boundPort) $ - \() -> waitForRelease - _ -> waitForRelease - - opener sp - - tOpen <- async $ opener startPort - - tSend <- async $ forever $ join $ atomically $ do - (adr, byt) <- readTBQueue qSend - readTVar vSock <&> \case - Nothing -> pure () - Just sk -> do - okay <- sendPacket byt adr sk - unless okay (signalBrokenSocket sk) - - tRecv <- async $ forever $ do - atomically (readTVar vSock) >>= \case - Nothing -> threadDelay 100_000 - Just sk -> do - recvPacket sk >>= \case - Left exn -> do - bump (asUdf sat) - logError "AMES: UDP: Failed to receive packet" - signalBrokenSocket sk - Right Nothing -> do - bump (asUi6 sat) - logError "AMES: UDP: Dropping non-ipv4 packet" - pure () - Right (Just (b, p, a)) -> do - logDebug "AMES: UDP: Received packet." - bump (asUdp sat) - enqueueRecvPacket p a b - - let shutdown = do - logInfo "AMES: UDP: Shutting down. (killing threads)" - cancel tOpen - cancel tSend - cancel tRecv - logInfo "AMES: UDP: Shutting down. (closing socket)" - io $ join $ atomically $ do - res <- readTVar vSock <&> maybe (pure ()) close - writeTVar vSock Nothing - pure res - - pure $ UdpServ { usSend = \a b -> runRIO env (enqueueSendPacket a b) - , usRecv = readTBQueue qRecv - , usKill = runRIO env shutdown - } diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Behn.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Behn.hs deleted file mode 100644 index 0957a8eda..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Behn.hs +++ /dev/null @@ -1,73 +0,0 @@ --- This is required due to the use of 'Void' in a constructor slot in --- combination with 'deriveNoun', which will generate an unreachable pattern. -{-# OPTIONS_GHC -Wno-overlapping-patterns #-} - -{-| - Behn: Timer Driver --} - -module Urbit.Vere.Behn (behn, DriverApi(..), behn') where - -import Data.Time.Clock.System (SystemTime) - -import Urbit.Arvo -import Urbit.Prelude -import Urbit.Vere.Pier.Types - -import Urbit.King.App (HasKingId(..), HasPierEnv(..)) -import Urbit.Noun.Time (Wen) -import Urbit.Timer (Timer) - -import qualified Urbit.Noun.Time as Time -import qualified Urbit.Timer as Timer - - --- Behn Stuff ------------------------------------------------------------------ - -behn' :: HasPierEnv e => RIO e ([Ev], RAcquire e (DriverApi BehnEf)) -behn' = do - env <- ask - pure ([bornEv (fromIntegral (env ^. kingIdL))], runDriver env) - where - runDriver env = do - ventQ :: TQueue EvErr <- newTQueueIO - diOnEffect <- liftAcquire (behn env (writeTQueue ventQ)) - let diEventSource = fmap RRWork <$> tryReadTQueue ventQ - pure (DriverApi {..}) - -bornEv :: KingId -> Ev -bornEv king = EvBlip $ BlipEvBehn $ BehnEvBorn (king, ()) () - -wakeEv :: Ev -wakeEv = EvBlip $ BlipEvBehn $ BehnEvWake () () - -sysTime :: Wen -> SystemTime -sysTime = view Time.systemTime - -wakeErr :: WorkError -> IO () -wakeErr _ = pure () - -behn - :: HasKingId e - => e - -> (EvErr -> STM ()) - -> Acquire (BehnEf -> IO ()) -behn env enqueueEv = runBehn - where - king = fromIntegral (env ^. kingIdL) - - runBehn :: Acquire (BehnEf -> IO ()) - runBehn = do - tim <- mkAcquire Timer.init Timer.stop - pure (runRIO env . handleEf tim) - - handleEf :: Timer -> BehnEf -> RIO e () - handleEf b = io . \case - BehnEfVoid v -> absurd v - BehnEfDoze (i, ()) mWen -> do - when (i == king) (doze b mWen) - - doze :: Timer -> Maybe Wen -> IO () - doze tim = \case - Nothing -> Timer.stop tim - Just t -> Timer.start tim (sysTime t) $ atomically (enqueueEv (EvErr wakeEv wakeErr)) diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Clay.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Clay.hs deleted file mode 100644 index e76fdba2c..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Clay.hs +++ /dev/null @@ -1,275 +0,0 @@ -{-| - UNIX Filesystem Driver --} - -module Urbit.Vere.Clay - ( clay - , clay' - ) -where - -import Urbit.Arvo -import Urbit.King.App -import Urbit.Prelude -import Urbit.Vere.Pier.Types - -import Conduit -import RIO.Directory -import RIO.FilePath - -import qualified Data.Conduit.Combinators as CC -import qualified Data.Map.Strict as M -import qualified Data.Set as S - - --------------------------------------------------------------------------------- - -data ClayDrv = ClayDrv - { cdMountPoints :: TVar (Map Desk (Map FilePath Int)) - } - -deskToPath :: Desk -> FilePath -deskToPath (Desk (Cord t)) = unpack t - --- | The hard coded mime type of every file. -textPlain :: Path -textPlain = Path [(MkKnot "text"), (MkKnot "plain")] - --- | Filter for dotfiles, tempfiles and backup files. -validClaySyncPath :: FilePath -> Bool -validClaySyncPath fp = hasPeriod && notTildeFile && notDotFile && notDoubleHash - where - fileName = takeFileName fp - hasPeriod = elem '.' fileName - notTildeFile = not $ "~" `isSuffixOf` fileName - notDotFile = not $ "." `isPrefixOf` fileName - notDoubleHash = - not $ ("#" `isPrefixOf` fileName) && ("#" `isSuffixOf` fileName) - -{-| - Returns a list of the result of running a function on each valid - file in the directory fp. Runnable in IO. --} -foreachFileIn :: (MonadUnliftIO m) - => FilePath -> (FilePath -> (ResourceT m) a) -> m [a] -foreachFileIn fp fun = - runConduitRes $ (sourceDirectoryDeep False fp) - .| filterC validClaySyncPath - .| CC.mapM fun - .| sinkList - -{-| - Note: Vere just reuses +mug, but since the actual hash function is - an implementation detail which doesn't leave the io driver, we just - use the standard hash. --} -getHashOfFile :: (MonadIO m) => FilePath -> m (FilePath, Int) -getHashOfFile fp = do - bs <- readFile fp - let !h = hash bs - pure (fp, h) - -{-| - Takes an initial snapshot of the filesystem, recording what files exist and - what their hashes are. --} -takeFilesystemSnapshot :: FilePath -> RIO e (Map FilePath Int) -takeFilesystemSnapshot fp = do - exists <- doesDirectoryExist fp - if not exists then - pure M.empty - else - M.fromList <$> foreachFileIn fp getHashOfFile - -{-| - Check an existing filepath against a snapshot of files that existed on disk - the last time we checked. Returns Either (unchanged) (new file data). --} -checkFileForUpdates :: (MonadIO m) - => Map FilePath Int -> FilePath - -> m (Either FilePath (FilePath, Mime, Int)) -checkFileForUpdates snapshot fp = do - bs <- readFile fp - let !newHash = hash bs - pure $ case lookup fp snapshot of - -- text/plain is the hardcoded mime type of every file sent to clay. - Nothing -> Right (fp, (Mime textPlain (File (Octs bs))), newHash) - Just i -> if i == newHash then Left fp - else Right (fp, (Mime textPlain (File (Octs bs))), newHash) - -{-| - Given a previous snapshot of the filesystem, produces a list of changes --} -buildActionListFromDifferences :: FilePath -> Map FilePath Int - -> RIO e [(FilePath, Maybe (Mime, Int))] -buildActionListFromDifferences fp snapshot = do - checks <- foreachFileIn fp (checkFileForUpdates snapshot) - - let changedItems = rights checks <&> \(fp, m, i) -> (fp, Just (m, i)) - - let existsSet = S.fromList $ flip map checks $ \case - Left fp -> fp - Right (fp, _, _) -> fp - let deletedSet = S.difference (M.keysSet snapshot) existsSet - let deletedItems = (toList deletedSet) <&> \x -> (x, Nothing) - - pure $ sort (deletedItems ++ changedItems) - --------------------------------------------------------------------------------- - -_boatFailed :: e -> WorkError -> IO () -_boatFailed env _ = runRIO env $ do - pure () -- TODO What can we do? - -clay' - :: HasPierEnv e - => RIO e ([Ev], RAcquire e (DriverApi SyncEf)) -clay' = do - ventQ :: TQueue EvErr <- newTQueueIO - env <- ask - - let (bornEvs, startDriver) = clay env (writeTQueue ventQ) - - let runDriver = do - diOnEffect <- startDriver - let diEventSource = fmap RRWork <$> tryReadTQueue ventQ - pure (DriverApi {..}) - - pure (bornEvs, runDriver) - -clay - :: forall e - . (HasPierConfig e, HasLogFunc e, HasKingId e) - => e - -> (EvErr -> STM ()) - -> ([Ev], RAcquire e (SyncEf -> IO ())) -clay env plan = - (initialEvents, runSync) - where - king = fromIntegral (env ^. kingIdL) - - boatEv = EvBlip $ BlipEvBoat $ BoatEvBoat () () - - -- TODO: In the case of -A, we need to read all the data from the - -- specified directory and shove it into an %into event. - initialEvents = [boatEv] - - runSync :: RAcquire e (SyncEf -> IO ()) - runSync = handleEffect <$> mkRAcquire start stop - - start :: RIO e ClayDrv - start = ClayDrv <$> newTVarIO mempty - stop c = pure () - - handleEffect :: ClayDrv -> SyncEf -> IO () - handleEffect cd = runRIO env . \case - SyncEfHill _ mountPoints -> do - logInfo $ displayShow ("(clay) known mount points:", mountPoints) - pierPath <- view pierPathL - mountPairs <- flip mapM mountPoints $ \desk -> do - ss <- takeFilesystemSnapshot (pierPath (deskToPath desk)) - pure (desk, ss) - atomically $ writeTVar (cdMountPoints cd) (M.fromList mountPairs) - - SyncEfDirk p desk -> do - logInfo $ displayShow ("(clay) dirk:", p, desk) - m <- atomically $ readTVar (cdMountPoints cd) - let snapshot = M.findWithDefault M.empty desk m - pierPath <- view pierPathL - let dir = pierPath deskToPath desk - actions <- buildActionListFromDifferences dir snapshot - - logInfo $ displayShow ("(clay) dirk actions: ", actions) - - let !intoList = map (actionsToInto dir) actions - - let syncEv = EvBlip - $ BlipEvSync - $ SyncEvInto (Some (king, ())) desk False intoList - - let syncFailed _ = pure () - - atomically $ plan (EvErr syncEv syncFailed) - - - atomically $ modifyTVar' - (cdMountPoints cd) - (applyActionsToMountPoints desk actions) - - SyncEfErgo p desk actions -> do - logInfo $ displayShow ("(clay) ergo:", p, desk, actions) - - m <- atomically $ readTVar (cdMountPoints cd) - let mountPoint = M.findWithDefault M.empty desk m - - pierPath <- view pierPathL - let dir = pierPath deskToPath desk - let hashedActions = map (calculateActionHash dir) actions - for_ hashedActions (performAction mountPoint) - - atomically $ modifyTVar' - (cdMountPoints cd) - (applyActionsToMountPoints desk hashedActions) - - SyncEfOgre p desk -> do - logInfo $ displayShow ("(clay) ogre:", p, desk) - pierPath <- view pierPathL - removeDirectoryRecursive $ pierPath deskToPath desk - atomically $ modifyTVar' (cdMountPoints cd) (M.delete desk) - - - -- Change the structures off of the event into something we can work with - -- in Unix. - calculateActionHash :: FilePath -> (Path, Maybe Mime) - -> (FilePath, Maybe (Mime, Int)) - calculateActionHash base (p, Nothing) = (base pathToFilePath p, Nothing) - calculateActionHash base (p, Just (Mime t f)) = - (base pathToFilePath p, Just ((Mime t f), (hash $ unOcts $ unFile f))) - - -- Performs the actions on the actual filesystem - performAction :: (Map FilePath Int) -> (FilePath, Maybe (Mime, Int)) - -> RIO e () - performAction m (fp, Nothing) = do - logInfo $ displayShow ("(clay) deleting file ", fp) - removeFile fp - performAction m (fp, Just ((Mime _ (File (Octs bs)), hash))) - | skip = logInfo $ - displayShow ("(clay) skipping unchanged file update " , fp) - | otherwise = do - logInfo $ displayShow ("(clay) updating file " , fp) - createDirectoryIfMissing True $ takeDirectory fp - writeFile fp bs - where - skip = case M.lookup fp m of - Nothing -> False - Just i -> i == hash - - -- Apply the actions to our internal snapshots - applyActionsToMountPoints :: Desk - -> [(FilePath, Maybe (Mime, Int))] - -> (Map Desk (Map FilePath Int)) - -> (Map Desk (Map FilePath Int)) - applyActionsToMountPoints desk actions m = M.alter change desk m - where - change (Just fileMap) = Just (foldl' applySyncAction fileMap actions) - change Nothing = change (Just M.empty) - - -- Applies the sync mutations specified. - applySyncAction :: (Map FilePath Int) - -> (FilePath, Maybe (Mime, Int)) - -> (Map FilePath Int) - applySyncAction m (fp, Nothing) = M.delete fp m - applySyncAction m (fp, (Just (_, h))) = M.insert fp h m - - -- Changes an action list item into a form injectable into Urbit - actionsToInto :: FilePath -> (FilePath, Maybe (Mime, Int)) - -> (Path, Maybe Mime) - actionsToInto prefix (fp, mybData) = (p, mybOutData) - where - p = filePathToPath strippedFp - strippedFp = case stripPrefix prefix fp of - Nothing -> error "Impossible missing prefix" - Just x -> x - mybOutData = case mybData of - Nothing -> Nothing - Just (m, i) -> Just m diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Dawn.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Dawn.hs deleted file mode 100644 index 9d1475749..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Dawn.hs +++ /dev/null @@ -1,489 +0,0 @@ -{-| - Use L2 to access PKI information. --} - -module Urbit.Vere.Dawn ( dawnVent - , dawnCometList - , renderShip - , mineComet - -- Used only in testing - , mix - , shas - , shaf - , deriveCode - , cometFingerprintBS - , cometFingerprint - ) where - -import Urbit.Arvo.Common -import Urbit.Arvo.Event hiding (Address) -import Urbit.Prelude hiding (rights, to, (.=)) - -import Prelude (read) - -import Data.Bits (xor) -import Data.List (nub) -import Data.Text (splitOn) -import Data.Aeson -import Data.HexString - -import qualified Crypto.Hash.SHA256 as SHA256 -import qualified Crypto.Hash.SHA512 as SHA512 -import qualified Crypto.Sign.Ed25519 as Ed -import qualified Data.Binary as B -import qualified Data.ByteString as BS -import qualified Data.ByteString.Char8 as C -import qualified Data.ByteString.Lazy as L -import qualified Network.HTTP.Client as C -import qualified Urbit.Ob as Ob - -import qualified Network.HTTP.Client.TLS as TLS -import qualified Network.HTTP.Types as HT - --- Conversion Utilities -------------------------------------------------------- - -passFromBytes :: ByteString -> ByteString -> Int -> Pass -passFromBytes enc aut sut - | sut /= 1 = Pass (Ed.PublicKey mempty) (Ed.PublicKey mempty) - | otherwise = Pass (Ed.PublicKey aut) (Ed.PublicKey enc) - -clanFromShip :: Ship -> Ob.Class -clanFromShip = Ob.clan . Ob.patp . fromIntegral - -shipSein :: Ship -> Ship -shipSein = Ship . fromIntegral . Ob.fromPatp . Ob.sein . Ob.patp . fromIntegral - -renderShip :: Ship -> Text -renderShip = Ob.renderPatp . Ob.patp . fromIntegral - -onLeft :: (a -> b) -> Either a c -> Either b c -onLeft fun = bimap fun id - --- Data Validation ------------------------------------------------------------- - --- Derive public key structure from the key derivation seed structure -ringToPass :: Ring -> Pass -ringToPass Ring{..} = Pass{..} - where - passCrypt = decode ringCrypt - passSign = decode ringSign - decode = fst . fromJust . Ed.createKeypairFromSeed_ - fromJust = \case - Nothing -> error "Invalid seed passed to createKeypairFromSeed" - Just x -> x - --- JSONRPC Functions ----------------------------------------------------------- - --- Our use case here is simple enough. --- Network.JSONRPC appeared fragile and has no documentation. --- So, like with Vere, we roll our own. - -dawnSendHTTP :: String -> L.ByteString -> RIO e (Either Int L.ByteString) -dawnSendHTTP endpoint requestData = liftIO do - manager <- C.newManager TLS.tlsManagerSettings - - initialRequest <- C.parseRequest endpoint - let request = initialRequest - { C.method = "POST" - , C.requestBody = C.RequestBodyLBS $ requestData - , C.requestHeaders = [("Accept", "application/json"), - ("Content-Type", "application/json"), - ("Charsets", "utf-8")] - } - - response <- C.httpLbs request manager - - -- Return body if 200. - let code = HT.statusCode $ C.responseStatus response - case code of - 200 -> pure $ Right $ C.responseBody response - _ -> pure $ Left code - -class RequestMethod m where - getRequestMethod :: m -> Text - -data RawResponse r = RawResponse - { rrId :: Int - , rrResult :: r - } - deriving (Show) - -instance FromJSON r => FromJSON (RawResponse r) where - parseJSON = withObject "Response" $ \v -> do - rawId <- v .: "id" - rrResult <- v .: "result" - let rrId = read rawId - pure RawResponse{..} - - --- Given a list of methods and parameters, return a list of decoded responses. -dawnPostRequests :: forall req e resp res - . (ToJSON req, RequestMethod req, FromJSON res) - => String - -> (req -> res -> resp) - -> [req] - -> RIO e [resp] -dawnPostRequests endpoint responseBuilder requests = do - -- Encode our input requests - let requestPayload = - encode $ Array $ fromList $ fmap toFullRequest $ zip [0..] requests - - -- Send to the server - responses <- dawnSendHTTP endpoint requestPayload >>= \case - Left err -> error $ "error fetching " <> endpoint <> ": HTTP " <> (show err) - Right x -> pure x - - -- Get a list of the result texts in the order of the submitted requests - rawSorted <- case decode responses of - Nothing -> error $ "couldn't decode json" - Just x -> pure $ map rrResult $ sortOn rrId x - - -- Build the final result structure by calling the passed in builder with the - -- request (some outputs need data from the request structure, eitherwise, - -- we'd lean on FromJSON). - let results = map (uncurry responseBuilder) (zip requests rawSorted) - pure results - - where - toFullRequest :: (Int, req) -> Value - toFullRequest (rid, req) = object [ "jsonrpc" .= ("2.0" :: Text) - , "method" .= getRequestMethod req - , "params" .= req - , "id" .= (show rid) - ] - --- Azimuth JSON Requests ------------------------------------------------------- - -data PointResponse = PointResponse - -- NOTE also contains dominion and ownership, but not actually used here - { prNetwork :: PointNetwork - } deriving (Show, Eq, Generic) - -instance FromJSON PointResponse where - parseJSON = withObject "PointResponse" $ \o -> do - prNetwork <- o .: "network" - pure PointResponse{..} - -data PointNetwork = PointNetwork - { pnKeys :: PointKeys - , pnSponsor :: PointSponsor - , pnRift :: ContNum - } deriving (Show, Eq, Generic) - -instance FromJSON PointNetwork where - parseJSON = withObject "PointNetwork" $ \o -> do - pnKeys <- o .: "keys" - pnSponsor <- o .: "sponsor" - pnRift <- o .: "rift" - pure PointNetwork{..} - -data PointKeys = PointKeys - { pkLife :: Life - , pkSuite :: Int - , pkAuth :: ByteString - , pkCrypt :: ByteString - } deriving (Show, Eq, Generic) - -instance FromJSON PointKeys where - parseJSON = withObject "PointKeys" $ \o -> do - pkLife <- o .: "life" - pkSuite <- o .: "suite" - rawAuth <- o .: "auth" - rawCrypt <- o .: "crypt" - let pkAuth = parseKey rawAuth - let pkCrypt = parseKey rawCrypt - pure PointKeys{..} - where - parseKey = reverse . toBytes . hexString . removePrefix . encodeUtf8 - -data PointSponsor = PointSponsor - { psHas :: Bool - , psWho :: Text - } deriving (Show, Eq, Generic) - -instance FromJSON PointSponsor where - parseJSON = withObject "PointSponsor" $ \o -> do - psHas <- o .: "has" - psWho <- o .: "who" - pure PointSponsor{..} - -data PointRequest = PointRequest Ship - -instance RequestMethod PointRequest where - getRequestMethod PointRequest{} = "getPoint" - -instance ToJSON PointRequest where - toJSON (PointRequest point) = object [ "ship" .= renderShip point ] - -parseAzimuthPoint :: PointRequest -> PointResponse -> EthPoint -parseAzimuthPoint (PointRequest point) response = EthPoint{..} - where - net = prNetwork response - key = pnKeys net - - -- Vere doesn't set ownership information, neither did the old Dawn.hs - -- implementation. - epOwn = (0, 0, 0, 0) - - sponsorShip = Ob.parsePatp $ psWho $ pnSponsor net - epNet = if pkLife key == 0 - then Nothing - else case sponsorShip of - Left _ -> Nothing - Right s -> Just - ( fromIntegral $ pkLife key - , passFromBytes (pkCrypt key) (pkAuth key) (pkSuite key) - , fromIntegral $ pnRift net - , (psHas $ pnSponsor net, Ship $ fromIntegral $ Ob.fromPatp s) - , Nothing -- NOTE goes unused currently, so we simply put Nothing - ) - - -- I don't know what this is supposed to be, other than the old Dawn.hs and - -- dawn.c do the same thing. - -- zero-fill spawn data - epKid = case clanFromShip (Ship $ fromIntegral point) of - Ob.Galaxy -> Just (0, setToHoonSet mempty) - Ob.Star -> Just (0, setToHoonSet mempty) - _ -> Nothing - --- Preprocess data from a point request into the form used in the galaxy table. -parseGalaxyTableEntry :: PointRequest -> PointResponse -> (Ship, (Rift, Life, Pass)) -parseGalaxyTableEntry (PointRequest point) response = (ship, (rift, life, pass)) - where - net = prNetwork response - keys = pnKeys net - - ship = Ship $ fromIntegral point - rift = fromIntegral $ pnRift net - life = fromIntegral $ pkLife keys - pass = passFromBytes (pkCrypt keys) (pkAuth keys) (pkSuite keys) - -removePrefix :: ByteString -> ByteString -removePrefix withOhEx - | prefix == "0x" = suffix - | otherwise = error "not prefixed with 0x" - where - (prefix, suffix) = splitAt 2 withOhEx - -data TurfRequest = TurfRequest - -instance RequestMethod TurfRequest where - getRequestMethod TurfRequest = "getDns" - -instance ToJSON TurfRequest where - toJSON TurfRequest = object [] -- NOTE getDns takes no parameters - -parseTurfResponse :: TurfRequest -> [Text] -> [Turf] -parseTurfResponse TurfRequest = map turf - where - turf t = Turf $ fmap Cord $ reverse $ splitOn "." t - --- Azimuth Functions ----------------------------------------------------------- - -retrievePoint :: String -> Ship -> RIO e EthPoint -retrievePoint endpoint ship = - dawnPostRequests endpoint parseAzimuthPoint [PointRequest ship] - >>= \case - [x] -> pure x - _ -> error "JSON server returned multiple return values." - -validateFeedAndGetSponsor :: String - -> Feed - -> RIO e (Seed, Ship) -validateFeedAndGetSponsor endpoint = \case - Feed0 s -> do - r <- validateSeed s - case r of - Left e -> error e - Right r -> pure (s, r) - Feed1 s -> validateGerms s - - where - validateGerms Germs{..} = - case gFeed of - [] -> error "no usable keys in keyfile" - (Germ{..}:f) -> do - let seed = Seed gShip gLife gRing Nothing - r :: Either String Ship - <- validateSeed seed - case r of - Left _ -> validateGerms $ Germs gShip f - Right r -> pure (seed, r) - - validateSeed (Seed ship life ring oaf) = do - case clanFromShip ship of - Ob.Comet -> pure validateComet - Ob.Moon -> pure validateMoon - _ -> validateRest - where - cometFromPass = cometFingerprint $ ringToPass ring - validateComet - -- A comet address is the fingerprint of the keypair - | (ship /= cometFromPass) = - Left ("comet name doesn't match fingerprint " <> - show ship <> " vs " <> - show cometFromPass) - | (life /= 1) = - Left "comet can never be re-keyed" - | otherwise = - Right (shipSein ship) - - validateMoon = - -- TODO: The current code in zuse does nothing, but we should be able - -- to try to validate the oath against the current as exists planet - -- on chain. - Right $ shipSein ship - - validateRest = do - putStrLn ("boot: retrieving " <> renderShip ship <> "'s public keys") - - --TODO could cache this lookup - whoP <- retrievePoint endpoint ship - case epNet whoP of - Nothing -> pure $ Left "ship not keyed" - Just (netLife, pass, contNum, (hasSponsor, who), _) -> do - if (netLife /= life) then - pure $ Left ("keyfile life mismatch; keyfile claims life " <> - show life <> ", but Azimuth claims life " <> - show netLife) - else if ((ringToPass ring) /= pass) then - pure $ Left "keyfile does not match Azimuth" - -- TODO: The hoon code does a breach check, but the C code never - -- supplies the data necessary for it to function. - else - pure $ Right who - - --- Walk through the sponsorship chain retrieving the actual sponsorship chain --- as it exists on Azimuth. -getSponsorshipChain :: String -> Ship -> RIO e [(Ship,EthPoint)] -getSponsorshipChain endpoint = loop - where - loop ship = do - putStrLn ("boot: retrieving keys for sponsor " <> renderShip ship) - ethPoint <- retrievePoint endpoint ship - - case (clanFromShip ship, epNet ethPoint) of - (Ob.Comet, _) -> error "Comets cannot be sponsors" - (Ob.Moon, _) -> error "Moons cannot be sponsors" - - (_, Nothing) -> - error $ unpack ("Ship " <> renderShip ship <> " not booted") - - (Ob.Galaxy, Just _) -> pure [(ship, ethPoint)] - - (_, Just (_, _, _, (False, _), _)) -> - error $ unpack ("Ship " <> renderShip ship <> " has no sponsor") - - (_, Just (_, _, _, (True, sponsor), _)) -> do - chain <- loop sponsor - pure $ chain <> [(ship, ethPoint)] - --- Produces either an error or a validated boot event structure. -dawnVent :: HasLogFunc e => String -> Feed -> RIO e (Either Text Dawn) -dawnVent provider feed = - -- The type checker can't figure this out on its own. - (onLeft tshow :: Either SomeException Dawn -> Either Text Dawn) <$> try do - putStrLn ("boot: requesting L2 Azimuth information from " <> pack provider) - - (dSeed, immediateSponsor) - <- validateFeedAndGetSponsor provider feed - dSponsor <- getSponsorshipChain provider immediateSponsor - - putStrLn "boot: retrieving galaxy table" - dCzar <- (mapToHoonMap . mapFromList) <$> - (dawnPostRequests provider parseGalaxyTableEntry (map (PointRequest . Ship . fromIntegral) [0..255])) - - putStrLn "boot: retrieving network domains" - dTurf <- (dawnPostRequests provider parseTurfResponse [TurfRequest]) - >>= \case - [] -> pure [] - [t] -> pure (nub t) - _ -> error "too many turf responses" - - let dNode = Nothing - - -- NOTE blocknum of 0 is fine because jael ignores it. - -- should probably be removed from dawn event. - let dBloq = 0 - - pure MkDawn{..} - - --- Comet List ------------------------------------------------------------------ - -dawnCometList :: RIO e [Ship] -dawnCometList = do - -- Get the jamfile with the list of stars accepting comets right now. - manager <- io $ C.newManager TLS.tlsManagerSettings - request <- io $ C.parseRequest "https://bootstrap.urbit.org/comet-stars.jam" - response <- io $ C.httpLbs (C.setRequestCheckStatus request) manager - let body = toStrict $ C.responseBody response - - noun <- cueBS body & either throwIO pure - fromNounErr noun & either (throwIO . uncurry ParseErr) pure - - --- Comet Mining ---------------------------------------------------------------- - -mix :: BS.ByteString -> BS.ByteString -> BS.ByteString -mix a b = BS.pack $ loop (BS.unpack a) (BS.unpack b) - where - loop [] [] = [] - loop a [] = a - loop [] b = b - loop (x:xs) (y:ys) = (xor x y) : loop xs ys - -shax :: BS.ByteString -> BS.ByteString -shax = SHA256.hash - -shas :: BS.ByteString -> BS.ByteString -> BS.ByteString -shas salt = shax . mix salt . shax - -shaf :: BS.ByteString -> BS.ByteString -> BS.ByteString -shaf salt ruz = (mix a b) - where - haz = shas salt ruz - a = (take 16 haz) - b = (drop 16 haz) - --- Given a ring, derives the network login code. --- --- Note that the network code is a patp, not a patq: the bytes have been --- scrambled. -deriveCode :: Ring -> Ob.Patp -deriveCode Ring {..} = Ob.patp $ - bytesAtom $ - take 8 $ - shaf (C.pack "pass") $ - shax $ - C.singleton 'B' <> ringSign <> ringCrypt - -cometFingerprintBS :: Pass -> ByteString -cometFingerprintBS = (shaf $ C.pack "bfig") . passToBS - -cometFingerprint :: Pass -> Ship -cometFingerprint = Ship . B.decode . fromStrict . reverse . cometFingerprintBS - -tryMineComet :: Set Ship -> Word64 -> Maybe Seed -tryMineComet ships seed = - if member shipSponsor ships - then Just $ Seed shipName 1 ring Nothing - else Nothing - where - -- Hash the incoming seed into a 64 bytes. - baseHash = SHA512.hash $ toStrict $ B.encode seed - signSeed = (take 32 baseHash) - ringSeed = (drop 32 baseHash) - ring = Ring signSeed ringSeed - pass = ringToPass ring - shipName = cometFingerprint pass - shipSponsor = shipSein shipName - -mineComet :: Set Ship -> Word64 -> Seed -mineComet ships = loop - where - loop eny = - case (tryMineComet ships eny) of - Nothing -> loop (eny + 1) - Just x -> x diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre.hs deleted file mode 100644 index b426009f1..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre.hs +++ /dev/null @@ -1,386 +0,0 @@ -{-| - Eyre: Http Server Driver --} - -module Urbit.Vere.Eyre - ( eyre - , eyre' - ) -where - -import Urbit.Prelude hiding (Builder) - -import Urbit.Arvo hiding (ServerId, reqUrl) -import Urbit.King.App ( killKingActionL - , HasKingId(..) - , HasMultiEyreApi(..) - , HasPierEnv(..) - ) -import Urbit.King.Config -import Urbit.Vere.Eyre.Multi -import Urbit.Vere.Eyre.PortsFile -import Urbit.Vere.Eyre.Serv -import Urbit.Vere.Eyre.Service -import Urbit.Vere.Eyre.Wai -import Urbit.Vere.Pier.Types - -import Data.List.NonEmpty (NonEmpty((:|))) -import Data.PEM (pemParseBS, pemWriteBS) -import RIO.Prelude (decodeUtf8Lenient) -import System.Random (randomIO) -import Urbit.Vere.Http (convertHeaders, unconvertHeaders) -import Urbit.Vere.Eyre.KingSubsite (KingSubsite) - -import qualified Network.HTTP.Types as H - - --- Types ----------------------------------------------------------------------- - -type HasShipEnv e = (HasLogFunc e, HasNetworkConfig e, HasPierConfig e) - -type ReqId = UD - -newtype Drv = Drv (MVar (Maybe Serv)) - -data SockOpts = SockOpts - { soLocalhost :: Bool - , soWhich :: ServPort - } - -data PortsToTry = PortsToTry - { pttSec :: SockOpts - , pttIns :: SockOpts - , pttLop :: SockOpts - } - -data Serv = Serv - { sServId :: ServId - , sConfig :: HttpServerConf - , sLop :: ServApi - , sIns :: ServApi - , sSec :: Maybe ServApi - , sPorts :: Ports - , sPortsFile :: FilePath - , sLiveReqs :: TVar LiveReqs - } - - --- Utilities for Constructing Events ------------------------------------------- - -servEv :: HttpServerEv -> Ev -servEv = EvBlip . BlipEvHttpServer - -bornEv :: KingId -> Ev -bornEv king = servEv $ HttpServerEvBorn (king, ()) () - -liveEv :: ServId -> Ports -> Ev -liveEv sId Ports {..} = servEv $ HttpServerEvLive (sId, ()) pHttp pHttps - -cancelEv :: ServId -> ReqId -> EvErr -cancelEv sId reqId = - EvErr (servEv (HttpServerEvCancelRequest (sId, reqId, 1, ()) ())) cancelFailed - -cancelFailed :: WorkError -> IO () -cancelFailed _ = pure () - -reqEv :: ServId -> ReqId -> WhichServer -> Address -> HttpRequest -> Ev -reqEv sId reqId which addr req = case which of - Loopback -> servEv $ HttpServerEvRequestLocal (sId, reqId, 1, ()) - $ HttpServerReq False addr req - _ -> servEv $ HttpServerEvRequest (sId, reqId, 1, ()) - $ HttpServerReq (which == Secure) addr req - - --- Based on Pier+Config, which ports should each server run? ------------------- - -httpServerPorts :: HasShipEnv e => Bool -> RIO e PortsToTry -httpServerPorts fak = do - ins <- view (networkConfigL . ncHttpPort . to (fmap fromIntegral)) - sec <- view (networkConfigL . ncHttpsPort . to (fmap fromIntegral)) - lop <- view (networkConfigL . ncLocalPort . to (fmap fromIntegral)) - localMode <- view (networkConfigL . ncNetMode . to (== NMLocalhost)) - - let local = localMode || fak - - let pttSec = case (sec, fak) of - (Just p , _ ) -> SockOpts local (SPChoices $ singleton p) - (Nothing, False) -> SockOpts local (SPChoices (443 :| [8443 .. 8453])) - (Nothing, True ) -> SockOpts local (SPChoices (8443 :| [8444 .. 8453])) - - let pttIns = case (ins, fak) of - (Just p , _ ) -> SockOpts local (SPChoices $ singleton p) - (Nothing, False) -> SockOpts local (SPChoices (80 :| [8080 .. 8090])) - (Nothing, True ) -> SockOpts local (SPChoices (8080 :| [8081 .. 8090])) - - let pttLop = case (lop, fak) of - (Just p , _) -> SockOpts local (SPChoices $ singleton p) - (Nothing, _) -> SockOpts local SPAnyPort - - pure (PortsToTry { .. }) - - --- Convert Between Urbit and WAI types. ---------------------------------------- - -parseTlsConfig :: (Key, Cert) -> Maybe TlsConfig -parseTlsConfig (PEM key, PEM certs) = do - let (cerByt, keyByt) = (wainBytes certs, wainBytes key) - pems <- pemParseBS cerByt & either (const Nothing) Just - (cert, chain) <- case pems of - [] -> Nothing - p : ps -> pure (pemWriteBS p, pemWriteBS <$> ps) - pure $ TlsConfig keyByt cert chain - where - wainBytes :: Wain -> ByteString - wainBytes = encodeUtf8 . unWain - -parseHttpEvent :: HttpEvent -> [RespAct] -parseHttpEvent = \case - Start h b True -> [RAFull (hSta h) (hHdr h) (fByt $ fromMaybe "" b)] - Start h b False -> [RAHead (hSta h) (hHdr h) (fByt $ fromMaybe "" b)] - Cancel () -> [RADone] - Continue b done -> toList (RABloc . fByt <$> b) - <> if done then [RADone] else [] - where - hHdr :: ResponseHeader -> [H.Header] - hHdr = unconvertHeaders . headers - - hSta :: ResponseHeader -> H.Status - hSta = toEnum . fromIntegral . statusCode - - fByt :: File -> ByteString - fByt = unOcts . unFile - -requestEvent :: ServId -> WhichServer -> Word64 -> ReqInfo -> Ev -requestEvent srvId which reqId ReqInfo{..} = reqEv srvId reqUd which riAdr evReq - where - evBod = bodFile riBod - evHdr = convertHeaders riHdr - evUrl = Cord (decodeUtf8Lenient riUrl) - evReq = HttpRequest riMet evUrl evHdr evBod - reqUd = fromIntegral reqId - - bodFile :: ByteString -> Maybe File - bodFile "" = Nothing - bodFile bs = Just $ File $ Octs bs - - --- Running Servers ------------------------------------------------------------- - -execRespActs :: HasLogFunc e => Drv -> Ship -> Word64 -> HttpEvent -> RIO e () -execRespActs (Drv v) who reqId ev = readMVar v >>= \case - Nothing -> logError "Got a response to a request that does not exist." - Just sv -> do - logDebug $ displayShow ev - for_ (parseHttpEvent ev) $ \act -> do - atomically (routeRespAct who (sLiveReqs sv) reqId act) - -startServ - :: (HasPierConfig e, HasLogFunc e, HasMultiEyreApi e, HasNetworkConfig e) - => Ship - -> Bool - -> HttpServerConf - -> (EvErr -> STM ()) - -> (Text -> RIO e ()) - -> IO () - -> KingSubsite - -> RIO e Serv -startServ who isFake conf plan stderr onFatal sub = do - logInfo (displayShow ("EYRE", "startServ")) - - multi <- view multiEyreApiL - - let vLive = meaLive multi - - srvId <- io $ ServId . UV . fromIntegral <$> (randomIO :: IO Word32) - - let mTls = hscSecure conf >>= parseTlsConfig - - mCre <- mTls & \case - Nothing -> pure Nothing - Just tc -> configCreds tc & \case - Right rs -> pure (Just (tc, rs)) - Left err -> do - logError "Couldn't Load TLS Credentials." - pure Nothing - - ptt <- httpServerPorts isFake - - {- - TODO If configuration requests a redirect, get the HTTPS port (if - configuration specifies a specific port, use that. Otherwise, wait - for the HTTPS server to start and then use the port that it chose). - and run an HTTP server that simply redirects to the HTTPS server. - -} - let secRedi = Nothing - - let soHost :: SockOpts -> ServHost - soHost so = if soLocalhost so then SHLocalhost else SHAnyHostOk - - noHttp <- view (networkConfigL . ncNoHttp) - noHttps <- view (networkConfigL . ncNoHttps) - - let reqEvFailed _ = pure () - - let onReq :: WhichServer -> Ship -> Word64 -> ReqInfo -> STM () - onReq which _ship reqId reqInfo = - plan $ EvErr (requestEvent srvId which reqId reqInfo) reqEvFailed - - let onKilReq :: Ship -> Word64 -> STM () - onKilReq _ship = plan . cancelEv srvId . fromIntegral - - logInfo (displayShow ("EYRE", "joinMultiEyre", who, mTls, mCre)) - - atomically (joinMultiEyre multi who mCre onReq onKilReq sub) - - logInfo $ displayShow ("EYRE", "Starting loopback server") - lop <- serv vLive onFatal $ ServConf - { scHost = soHost (pttLop ptt) - , scPort = soWhich (pttLop ptt) - , scRedi = Nothing - , scFake = False - , scType = STHttp who sub $ ReqApi - { rcReq = onReq Loopback - , rcKil = onKilReq - } - } - - logInfo $ displayShow ("EYRE", "Starting insecure server") - ins <- serv vLive onFatal $ ServConf - { scHost = soHost (pttIns ptt) - , scPort = soWhich (pttIns ptt) - , scRedi = secRedi - , scFake = noHttp - , scType = STHttp who sub $ ReqApi - { rcReq = onReq Insecure - , rcKil = onKilReq - } - } - - mSec <- for mTls $ \tls -> do - logInfo "Starting secure server" - serv vLive onFatal $ ServConf - { scHost = soHost (pttSec ptt) - , scPort = soWhich (pttSec ptt) - , scRedi = Nothing - , scFake = noHttps - , scType = STHttps who tls sub $ ReqApi - { rcReq = onReq Secure - , rcKil = onKilReq - } - } - - pierPath <- view pierPathL - - lopPor <- atomically (fmap fromIntegral $ saPor lop) - insPor <- atomically (fmap fromIntegral $ saPor ins) - secPor <- for mSec (fmap fromIntegral . atomically . saPor) - - let por = Ports secPor insPor lopPor - fil = pierPath <> "/.http.ports" - - logInfo $ displayShow ("EYRE", "All Servers Started.", srvId, por, fil) - for secPor $ \p -> - stderr ("http: secure web interface live on https://localhost:" <> tshow p) - stderr ("http: web interface live on http://localhost:" <> tshow insPor) - stderr ("http: loopback live on http://localhost:" <> tshow lopPor) - - pure (Serv srvId conf lop ins mSec por fil vLive) - - --- Eyre Driver ----------------------------------------------------------------- - -_bornFailed :: e -> WorkError -> IO () -_bornFailed env _ = runRIO env $ do - pure () -- TODO What should this do? - -eyre' - :: (HasPierEnv e, HasMultiEyreApi e) - => Ship - -> Bool - -> (Text -> RIO e ()) - -> KingSubsite - -> RIO e ([Ev], RAcquire e (DriverApi HttpServerEf)) - -eyre' who isFake stderr sub = do - ventQ :: TQueue EvErr <- newTQueueIO - env <- ask - - let (bornEvs, startDriver) = - eyre env who (writeTQueue ventQ) isFake stderr sub - - let runDriver = do - diOnEffect <- startDriver - let diEventSource = fmap RRWork <$> tryReadTQueue ventQ - pure (DriverApi {..}) - - pure (bornEvs, runDriver) - -{-| - Eyre -- HTTP Server Driver - - Inject born events. - Until born events succeeds, ignore effects. - Wait until born event callbacks invoked. - If success, signal success. - If failure, try again several times. - If still failure, bring down ship. - Once born event succeeds: - - Begin normal operation (start accepting requests) --} -eyre - :: forall e - . (HasPierEnv e) - => e - -> Ship - -> (EvErr -> STM ()) - -> Bool - -> (Text -> RIO e ()) - -> KingSubsite - -> ([Ev], RAcquire e (HttpServerEf -> IO ())) -eyre env who plan isFake stderr sub = (initialEvents, runHttpServer) - where - king = fromIntegral (env ^. kingIdL) - multi = env ^. multiEyreApiL - - initialEvents :: [Ev] - initialEvents = [bornEv king] - - runHttpServer :: RAcquire e (HttpServerEf -> IO ()) - runHttpServer = handleEf <$> mkRAcquire - (Drv <$> newMVar Nothing) - (\(Drv v) -> stopService v kill >>= fromEither) - - kill :: HasLogFunc e => Serv -> RIO e () - kill Serv{..} = do - atomically (leaveMultiEyre multi who) - io (saKil sLop) - io (saKil sIns) - io $ for_ sSec (\sec -> (saKil sec)) - io (removePortsFile sPortsFile) - - restart :: Drv -> HttpServerConf -> RIO e Serv - restart (Drv var) conf = do - logInfo "Restarting http server" - let onFatal = runRIO env $ do - -- XX instead maybe restart following logic under HSESetConfig below - stderr "A web server problem has occurred. Please restart your ship." - view killKingActionL >>= atomically - let startAct = startServ who isFake conf plan stderr onFatal sub - res <- fromEither =<< restartService var startAct kill - logInfo "Done restating http server" - pure res - - liveFailed _ = pure () - - handleEf :: Drv -> HttpServerEf -> IO () - handleEf drv = runRIO env . \case - HSESetConfig (i, ()) conf -> do - logInfo (displayShow ("EYRE", "%set-config")) - Serv {..} <- restart drv conf - logInfo (displayShow ("EYRE", "%set-config", "Sending %live")) - atomically $ plan (EvErr (liveEv sServId sPorts) liveFailed) - logInfo "Write ports file" - io (writePortsFile sPortsFile sPorts) - HSEResponse (i, req, _seq, ()) ev -> do - logDebug (displayShow ("EYRE", "%response")) - execRespActs drv who (fromIntegral req) ev diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/KingSubsite.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/KingSubsite.hs deleted file mode 100644 index ae4d59d63..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/KingSubsite.hs +++ /dev/null @@ -1,126 +0,0 @@ -{-| - KingSubsite: runtime-exclusive HTTP request handling, for /~_~ --} - -module Urbit.Vere.Eyre.KingSubsite - ( KingSubsite - , kingSubsite - , runKingSubsite - , fourOhFourSubsite - ) where - -import Urbit.Prelude hiding (Builder) - -import Data.ByteString.Builder -import Urbit.King.Scry - -import Data.Conduit (ConduitT, Flush(..), yield) -import Data.Text.Encoding (encodeUtf8Builder) -import Urbit.Vere.Stat (RenderedStat) - -import qualified Data.Text.Encoding as E -import qualified Network.HTTP.Types as H -import qualified Network.Wai as W -import qualified Network.Wai.Conduit as W - -newtype KingSubsite = KS { runKingSubsite :: W.Application } - -data SlogAction - = KeepAlive - | Slog (Atom, Tank) - -streamSlog :: Monad m => SlogAction -> ConduitT () (Flush Builder) m () -streamSlog a = do - case a of - KeepAlive -> pure () - Slog (_, t) -> for_ (wash (WashCfg 0 80) (tankTree t)) $ \l -> do - yield $ Chunk "data:" - yield $ Chunk $ encodeUtf8Builder $ unTape l - yield $ Chunk "\n" - yield $ Chunk "\n" - yield $ Flush - -kingSubsite :: HasLogFunc e - => Ship - -> ScryFunc - -> IO RenderedStat - -> TVar ((Atom, Tank) -> IO ()) - -> RAcquire e KingSubsite -kingSubsite who scry stat func = do - clients <- newTVarIO (mempty :: Map Word (SlogAction -> IO ())) - nextId <- newTVarIO (0 :: Word) - baton <- newTMVarIO () - env <- ask - - atomically $ writeTVar func $ \s -> readTVarIO clients >>= traverse_ ($ Slog s) - - acquireWorker "Runtime subsite keep-alive" $ forever $ do - threadDelay 20_000_000 - io $ readTVarIO clients >>= traverse_ ($ KeepAlive) - - pure $ KS $ \req respond -> case W.pathInfo req of - ["~_~", "slog"] -> bracket - (do - id <- atomically $ do - id <- readTVar nextId - modifyTVar' nextId (+ 1) - pure id - slogQ <- newTQueueIO - atomically $ - modifyTVar' clients (insertMap id (atomically . writeTQueue slogQ)) - pure (id, slogQ)) - (\(id, _) -> atomically $ modifyTVar' clients (deleteMap id)) - (\(_, q) -> do - authed <- authenticated env req - if not authed - then respond $ emptyResponse 403 "Permission Denied" - else - let loop = yield Flush - >> forever (atomically (readTQueue q) >>= streamSlog) - in respond $ W.responseSource (H.mkStatus 200 "OK") slogHeads loop) - - ["~_~", "stat"] -> do - authed <- authenticated env req - if not authed - then respond $ emptyResponse 403 "Permission Denied" - else do - lines <- stat - let msg = mconcat ((<> "\n") . encodeUtf8Builder <$> lines) - <> "\nRefresh for more current data." - respond $ W.responseBuilder (H.mkStatus 200 "OK") statHeads msg - - _ -> respond $ emptyResponse 404 "Not Found" - - where - slogHeads = [ ("Content-Type", "text/event-stream") - , ("Cache-Control", "no-cache") - , ("Connection", "keep-alive") - ] - - statHeads = [ ("Content-Type", "text/plain") - , ("Cache-Control", "no-cache") - ] - - emptyResponse cod mes = W.responseLBS (H.mkStatus cod mes) [] "" - - authenticated env req = runRIO env - $ (scryAuth $ getCookie req) - >>= pure . fromMaybe False - - getCookie req = intercalate "; " - $ fmap (E.decodeUtf8 . snd) - $ filter ((== "cookie") . fst) - $ W.requestHeaders req - - scryAuth :: HasLogFunc e - => Text - -> RIO e (Maybe Bool) - scryAuth cookie = - scryNow scry "ex" "" ["authenticated", "cookie", textAsT cookie] - -fourOhFourSubsite :: Ship -> KingSubsite -fourOhFourSubsite who = KS $ \req respond -> - respond $ W.responseLBS (H.mkStatus 404 "Not Found") [] body - where - body = toLazyByteString $ foldMap charUtf8 $ msg - msg = "Ship " <> show who <> " not docked." diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/Multi.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/Multi.hs deleted file mode 100644 index 09d1f974e..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/Multi.hs +++ /dev/null @@ -1,143 +0,0 @@ -{-| - Eyre: Http Server Driver --} - -module Urbit.Vere.Eyre.Multi - ( WhichServer(..) - , MultiEyreConf(..) - , OnMultiReq - , OnMultiKil - , MultiEyreApi(..) - , joinMultiEyre - , leaveMultiEyre - , multiEyre - ) -where - -import Urbit.Prelude hiding (Builder) - -import Urbit.Arvo hiding (ServerId, reqUrl) -import Urbit.Vere.Eyre.Serv -import Urbit.Vere.Eyre.Wai - -import Network.TLS (Credential) -import Urbit.Vere.Eyre.KingSubsite (KingSubsite, fourOhFourSubsite) - - --- Types ----------------------------------------------------------------------- - -data WhichServer = Secure | Insecure | Loopback - deriving (Eq) - -data MultiEyreConf = MultiEyreConf - { mecHttpsPort :: Maybe Port - , mecHttpPort :: Maybe Port - , mecLocalhostOnly :: Bool - } - deriving (Show) - -type OnMultiReq = WhichServer -> Ship -> Word64 -> ReqInfo -> STM () - -type OnMultiKil = Ship -> Word64 -> STM () - -data MultiEyreApi = MultiEyreApi - { meaConf :: MultiEyreConf - , meaLive :: TVar LiveReqs - , meaPlan :: TVar (Map Ship OnMultiReq) - , meaCanc :: TVar (Map Ship OnMultiKil) - , meaTlsC :: TVar (Map Ship (TlsConfig, Credential)) - , meaSite :: TVar (Map Ship KingSubsite) - , meaKill :: IO () - } - - --- Multi-Tenet HTTP ------------------------------------------------------------ - -joinMultiEyre - :: MultiEyreApi - -> Ship - -> Maybe (TlsConfig, Credential) - -> OnMultiReq - -> OnMultiKil - -> KingSubsite - -> STM () -joinMultiEyre api who mTls onReq onKil sub = do - modifyTVar' (meaPlan api) (insertMap who onReq) - modifyTVar' (meaCanc api) (insertMap who onKil) - for_ mTls $ \creds -> do - modifyTVar' (meaTlsC api) (insertMap who creds) - modifyTVar' (meaSite api) (insertMap who sub) - -leaveMultiEyre :: MultiEyreApi -> Ship -> STM () -leaveMultiEyre MultiEyreApi {..} who = do - modifyTVar' meaCanc (deleteMap who) - modifyTVar' meaPlan (deleteMap who) - modifyTVar' meaTlsC (deleteMap who) - modifyTVar' meaSite (deleteMap who) - -multiEyre :: HasLogFunc e => IO () -> MultiEyreConf -> RIO e MultiEyreApi -multiEyre onFatal conf@MultiEyreConf {..} = do - logInfo (displayShow ("EYRE", "MULTI", conf)) - - vLive <- io emptyLiveReqs >>= newTVarIO - vPlan <- newTVarIO mempty - vCanc <- newTVarIO (mempty :: Map Ship (Ship -> Word64 -> STM ())) - vTlsC <- newTVarIO mempty - vSite <- newTVarIO mempty - - let site :: Ship -> STM KingSubsite - site who = do - sites <- readTVar vSite - pure $ maybe (fourOhFourSubsite who) id $ lookup who sites - - let host = if mecLocalhostOnly then SHLocalhost else SHAnyHostOk - - let onReq :: WhichServer -> Ship -> Word64 -> ReqInfo -> STM () - onReq which who reqId reqInfo = do - plan <- readTVar vPlan - lookup who plan & \case - Nothing -> pure () - Just cb -> cb which who reqId reqInfo - - let onKil :: Ship -> Word64 -> STM () - onKil who reqId = do - canc <- readTVar vCanc - lookup who canc & \case - Nothing -> pure () - Just cb -> cb who reqId - - mIns <- for mecHttpPort $ \por -> do - logInfo (displayShow ("EYRE", "MULTI", "HTTP", por)) - serv vLive onFatal $ ServConf - { scHost = host - , scPort = SPChoices $ singleton $ fromIntegral por - , scRedi = Nothing -- TODO - , scFake = False - , scType = STMultiHttp site $ ReqApi - { rcReq = onReq Insecure - , rcKil = onKil - } - } - - mSec <- for mecHttpsPort $ \por -> do - logInfo (displayShow ("EYRE", "MULTI", "HTTPS", por)) - serv vLive onFatal $ ServConf - { scHost = host - , scPort = SPChoices $ singleton $ fromIntegral por - , scRedi = Nothing - , scFake = False - , scType = STMultiHttps (MTC vTlsC) site $ ReqApi - { rcReq = onReq Secure - , rcKil = onKil - } - } - - pure $ MultiEyreApi - { meaLive = vLive - , meaPlan = vPlan - , meaCanc = vCanc - , meaTlsC = vTlsC - , meaSite = vSite - , meaConf = conf - , meaKill = traverse_ saKil (toList mIns <> toList mSec) - } diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/PortsFile.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/PortsFile.hs deleted file mode 100644 index 20e073122..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/PortsFile.hs +++ /dev/null @@ -1,44 +0,0 @@ -{-| - Eyre: Http Server Driver --} - -module Urbit.Vere.Eyre.PortsFile - ( Ports(..) - , writePortsFile - , removePortsFile - ) -where - -import Urbit.Prelude - -import System.Directory (doesFileExist, removeFile) -import Urbit.Arvo (Port(unPort)) - - --- Types ----------------------------------------------------------------------- - -data Ports = Ports - { pHttps :: Maybe Port - , pHttp :: Port - , pLoop :: Port - } - deriving (Eq, Ord, Show) - - --- Creating and Deleting `.http.ports` files. ---------------------------------- - -portsFileText :: Ports -> Text -portsFileText Ports {..} = unlines $ catMaybes - [ pHttps <&> \p -> (tshow p <> " secure public") - , Just (tshow (unPort pHttp) <> " insecure public") - , Just (tshow (unPort pLoop) <> " insecure loopback") - ] - -removePortsFile :: FilePath -> IO () -removePortsFile pax = do - doesFileExist pax >>= \case - True -> removeFile pax - False -> pure () - -writePortsFile :: FilePath -> Ports -> IO () -writePortsFile f = writeFile f . encodeUtf8 . portsFileText diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/Serv.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/Serv.hs deleted file mode 100644 index 2bd8a2264..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/Serv.hs +++ /dev/null @@ -1,384 +0,0 @@ -{-| - Runs a single HTTP (or HTTPS) server for the eyre driver. - - A server is given: - - - A port, or a range or ports. - - Opens a socket on one of those ports. - - If this fails, try again repeatedly. - - Once a socket is opened, runs an HTTP server on the specified port. - - Once the server is up, calls a callback with the port that was opened. - - Once we have chosen a port, we commit to that port (ignoring the - original range). - - If the socket ever goes down, keep trying to reopen that port forever. - - When the server is shutdown, make sure the socket is closed. - - TODO How to detect socket closed during server run? --} - -module Urbit.Vere.Eyre.Serv - ( ServApi(..) - , TlsConfig(..) - , MultiTlsConfig(..) - , ReqApi(..) - , ServType(..) - , ServPort(..) - , ServHost(..) - , ServConf(..) - , configCreds - , serv - , fakeServ - ) -where - -import Urbit.Prelude hiding (Builder) - -import Data.Default (def) -import Data.List.NonEmpty (NonEmpty((:|))) -import GHC.IO.Exception (IOException(..), IOErrorType(..)) -import Network.TLS ( Credential - , Credentials(..) - , ServerHooks(..) - ) -import Network.TLS (credentialLoadX509ChainFromMemory) -import RIO.Prelude (decodeUtf8Lenient) -import Urbit.Vere.Eyre.KingSubsite (KingSubsite) - -import qualified Control.Monad.STM as STM -import qualified Data.Char as C -import qualified Network.Socket as Net -import qualified Network.Wai as W -import qualified Network.Wai.Handler.Warp as W -import qualified Network.Wai.Handler.WarpTLS as W -import qualified Urbit.Ob as Ob -import qualified Urbit.Vere.Eyre.Wai as E - - --- Internal Types -------------------------------------------------------------- - -data ServApi = ServApi - { saKil :: IO () - , saPor :: STM W.Port - } - -data TlsConfig = TlsConfig - { tcPrKey :: ByteString - , tcCerti :: ByteString - , tcChain :: [ByteString] - } - deriving (Show) - -newtype MultiTlsConfig = MTC (TVar (Map Ship (TlsConfig, Credential))) - -data ReqApi = ReqApi - { rcReq :: Ship -> Word64 -> E.ReqInfo -> STM () - , rcKil :: Ship -> Word64 -> STM () - } - -data ServType - = STHttp Ship KingSubsite ReqApi - | STHttps Ship TlsConfig KingSubsite ReqApi - | STMultiHttp (Ship -> STM KingSubsite) ReqApi - | STMultiHttps MultiTlsConfig (Ship -> STM KingSubsite) ReqApi - -instance Show ServType where - show = \case - STHttp who _ _ -> "STHttp " <> show who - STHttps who tls _ _ -> "STHttps " <> show who <> " " <> show tls - STMultiHttp _ _ -> "STMultiHttp" - STMultiHttps tls _ _ -> "STMultiHttps" - -data ServPort - = SPAnyPort - | SPChoices (NonEmpty W.Port) - deriving (Show) - -data ServHost - = SHLocalhost - | SHAnyHostOk - deriving (Show) - -data ServConf = ServConf - { scType :: ServType - , scHost :: ServHost - , scPort :: ServPort - , scRedi :: Maybe W.Port - , scFake :: Bool - } - deriving (Show) - - --- Opening Sockets ------------------------------------------------------------- - -getBindAddr :: String -> W.Port -> IO Net.SockAddr -getBindAddr hos por = - Net.getAddrInfo Nothing (Just hos) (Just (show por)) >>= \case - [] -> error "this should never happen." - x : _ -> pure (Net.addrAddress x) - -bindListenPort :: String -> W.Port -> Net.Socket -> IO Net.PortNumber -bindListenPort hos por sok = do - Net.bind sok =<< getBindAddr hos por - Net.listen sok 1 - Net.socketPort sok - -tcpSocket :: IO (Either IOError Net.Socket) -tcpSocket = - tryIOError (Net.socket Net.AF_INET Net.Stream Net.defaultProtocol) - -tryOpen :: String -> W.Port -> IO (Either IOError (W.Port, Net.Socket)) -tryOpen hos por = - tcpSocket >>= \case - Left exn -> pure (Left exn) - Right sok -> tryIOError (bindListenPort hos por sok) >>= \case - Left exn -> Net.close sok $> Left exn - Right por -> pure (Right (fromIntegral por, sok)) - -openFreePort :: String -> IO (Either IOError (W.Port, Net.Socket)) -openFreePort hos = do - tcpSocket >>= \case - Left exn -> pure (Left exn) - Right sok -> tryIOError (doBind sok) >>= \case - Left exn -> Net.close sok $> Left exn - Right ps -> pure (Right ps) - where - doBind sok = do - adr <- - Net.getAddrInfo Nothing (Just hos) Nothing >>= \case - [] -> error ("unable to determine numeric hostname from " ++ hos) - ip : _ -> pure (Net.addrAddress ip) - - Net.bind sok adr - Net.listen sok 1 - port <- Net.socketPort sok - pure (fromIntegral port, sok) - -retry :: HasLogFunc e => RIO e (Either IOError a) -> RIO e a -retry act = act >>= \case - Right res -> pure res - Left exn -> do - logDbg ctx ("Failed to open ports. Waiting 5s, then trying again.", exn) - threadDelay 5_000_000 - retry act - where - ctx = ["EYRE", "SERV", "retry"] - -tryOpenChoices - :: HasLogFunc e - => String - -> NonEmpty W.Port - -> RIO e (Either IOError (W.Port, Net.Socket)) -tryOpenChoices hos = go - where - go (p :| ps) = do - logInfo (displayShow ("EYRE", "Trying to open port.", p)) - io (tryOpen hos p) >>= \case - Left err -> do - logError (displayShow ("EYRE", "Failed to open port.", p)) - case ps of - [] -> pure (Left err) - q : qs -> go (q :| qs) - Right (p, s) -> do - pure (Right (p, s)) - -tryOpenAny - :: HasLogFunc e => String -> RIO e (Either IOError (W.Port, Net.Socket)) -tryOpenAny hos = do - let ctx = ["EYRE", "SERV", "tryOpenAny"] - logDbg ctx "Asking the OS for any free port." - io (openFreePort hos) >>= \case - Left exn -> pure (Left exn) - Right (p, s) -> do - pure (Right (p, s)) - -logDbg :: (HasLogFunc e, Show a) => [Text] -> a -> RIO e () -logDbg ctx msg = logInfo (prefix <> suffix) - where - prefix = display (concat $ fmap (<> ": ") ctx) - suffix = displayShow msg - -forceOpenSocket - :: forall e - . HasLogFunc e - => ServHost - -> ServPort - -> RAcquire e (W.Port, Net.Socket) -forceOpenSocket hos por = mkRAcquire opn kil - where - kil = io . Net.close . snd - - opn = do - let ctx = ["EYRE", "SERV", "forceOpenSocket"] - logDbg ctx (hos, por) - (p, s) <- retry $ case por of - SPAnyPort -> tryOpenAny bind - SPChoices ps -> tryOpenChoices bind ps - logDbg ctx ("Opened port.", p) - pure (p, s) - - bind = case hos of - SHLocalhost -> "127.0.0.1" - SHAnyHostOk -> "0.0.0.0" - - --- Starting WAI ---------------------------------------------------------------- - -hostShip :: Maybe ByteString -> IO Ship -hostShip Nothing = error "Request must contain HOST header." -hostShip (Just bs) = byteShip (hedLabel bs) & \case - Left err -> error ("Bad host prefix. Must be a ship name: " <> unpack err) - Right sp -> pure sp - where - byteShip = fmap (fromIntegral . Ob.fromPatp) . bytePatp - bytePatp = Ob.parsePatp . decodeUtf8Lenient - hedLabel = fst . break (== fromIntegral (C.ord '.')) - -onSniHdr - :: HasLogFunc e => e -> MultiTlsConfig -> Maybe String -> IO Credentials -onSniHdr env (MTC mtls) mHos = do - tabl <- atomically (readTVar mtls) - runRIO env $ logDbg ctx (tabl, mHos) - ship <- hostShip (encodeUtf8 . pack <$> mHos) - runRIO env $ logDbg ctx ship - tcfg <- lookup ship tabl & maybe (notRunning ship) (pure . snd) - runRIO env $ logDbg ctx tcfg - pure (Credentials [tcfg]) - where - notRunning ship = error ("Ship not running: ~" <> show ship) - ctx = ["EYRE", "HTTPS", "SNI"] - -startServer - :: HasLogFunc e - => ServType - -> ServHost - -> W.Port - -> Net.Socket - -> Maybe W.Port - -> TVar E.LiveReqs - -> IO () - -> RIO e () -startServer typ hos por sok red vLive onFatal = do - envir <- ask - - let host = case hos of - SHLocalhost -> "127.0.0.1" - SHAnyHostOk -> "*" - - let handler r e = do - when (isFatal e) $ do - runRIO envir $ logError $ display $ msg r e - onFatal - when (W.defaultShouldDisplayException e) $ do - runRIO envir $ logWarn $ display $ msg r e - - isFatal e - | Just (IOError {ioe_type = ResourceExhausted}) <- fromException e - = True - | otherwise = False - - msg r e = case r of - Just r -> "eyre: failed request from " <> (tshow $ W.remoteHost r) - <> " for " <> (tshow $ W.rawPathInfo r) <> ": " <> tshow e - Nothing -> "eyre: server exception: " <> tshow e - - let opts = - W.defaultSettings - & W.setHost host - & W.setPort (fromIntegral por) - & W.setTimeout 30 - & W.setOnException handler - - -- TODO build Eyre.Site.app in pier, thread through here - let runAppl who = E.app envir who vLive - reqShip = hostShip . W.requestHeaderHost - - case typ of - STHttp who sub api -> do - let app = runAppl who (rcReq api who) (rcKil api who) sub - io (W.runSettingsSocket opts sok app) - - STHttps who TlsConfig {..} sub api -> do - let tls = W.tlsSettingsChainMemory tcCerti tcChain tcPrKey - let app = runAppl who (rcReq api who) (rcKil api who) sub - io (W.runTLSSocket tls opts sok app) - - STMultiHttp fub api -> do - let app req resp = do - who <- reqShip req - sub <- atomically $ fub who - runAppl who (rcReq api who) (rcKil api who) sub req resp - io (W.runSettingsSocket opts sok app) - - STMultiHttps mtls fub api -> do - TlsConfig {..} <- atomically (getFirstTlsConfig mtls) - - let sni = def { onServerNameIndication = onSniHdr envir mtls } - - let tlsSing = (W.tlsSettingsChainMemory tcCerti tcChain tcPrKey) - let tlsMany = tlsSing { W.tlsServerHooks = sni } - - let ctx = ["EYRE", "HTTPS", "REQ"] - - let - app = \req resp -> do - runRIO envir $ logDbg ctx "Got request" - who <- reqShip req - runRIO envir $ logDbg ctx ("Parsed HOST", who) - sub <- atomically $ fub who - runAppl who (rcReq api who) (rcKil api who) sub req resp - - io (W.runTLSSocket tlsMany opts sok app) - - --------------------------------------------------------------------------------- - -configCreds :: TlsConfig -> Either Text Credential -configCreds TlsConfig {..} = - credentialLoadX509ChainFromMemory tcCerti tcChain tcPrKey & \case - Left str -> Left (pack str) - Right rs -> Right rs - -fakeServ :: HasLogFunc e => ServConf -> RIO e ServApi -fakeServ conf = do - let por = fakePort (scPort conf) - logInfo (displayShow ("EYRE", "SERV", "Running Fake Server", por)) - pure $ ServApi - { saKil = pure () - , saPor = pure por - } - where - fakePort :: ServPort -> W.Port - fakePort SPAnyPort = 55555 - fakePort (SPChoices (x :| _)) = x - -getFirstTlsConfig :: MultiTlsConfig -> STM TlsConfig -getFirstTlsConfig (MTC var) = do - map <- readTVar var - case toList map of - [] -> STM.retry - x:_ -> pure (fst x) - -realServ :: HasLogFunc e - => TVar E.LiveReqs -> IO () -> ServConf -> RIO e ServApi -realServ vLive onFatal conf@ServConf {..} = do - logInfo (displayShow ("EYRE", "SERV", "Running Real Server")) - por <- newEmptyTMVarIO - - tid <- async (runServ por) - - pure $ ServApi - { saKil = cancel tid - , saPor = readTMVar por - } - where - runServ vPort = do - logInfo (displayShow ("EYRE", "SERV", "runServ")) - rwith (forceOpenSocket scHost scPort) $ \(por, sok) -> do - atomically (putTMVar vPort por) - startServer scType scHost por sok scRedi vLive onFatal - -serv :: HasLogFunc e => TVar E.LiveReqs -> IO () -> ServConf -> RIO e ServApi -serv vLive onFatal conf = do - if scFake conf - then fakeServ conf - else realServ vLive onFatal conf diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/Service.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/Service.hs deleted file mode 100644 index af571afc9..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/Service.hs +++ /dev/null @@ -1,67 +0,0 @@ -{-| - Eyre: Http Server Driver --} - -module Urbit.Vere.Eyre.Service - ( restartService - , stopService - ) -where - -import Urbit.Prelude - - --- Generic Service Stop/Restart -- Using an MVar for Atomicity ----------------- - -{-| - Restart a running service. - - This can probably be made simpler, but it - - - Sets the MVar to Nothing if there was an exception while starting - or stopping the service. - - - Keeps the MVar lock until the restart process finishes. --} -restartService - :: forall e s - . HasLogFunc e - => MVar (Maybe s) - -> RIO e s - -> (s -> RIO e ()) - -> RIO e (Either SomeException s) -restartService vServ sstart kkill = do - logInfo "restartService" - modifyMVar vServ $ \case - Nothing -> doStart - Just sv -> doRestart sv - where - doRestart :: s -> RIO e (Maybe s, Either SomeException s) - doRestart serv = do - logInfo "doStart" - try (kkill serv) >>= \case - Left exn -> pure (Nothing, Left exn) - Right () -> doStart - - doStart :: RIO e (Maybe s, Either SomeException s) - doStart = do - logInfo "doStart" - try sstart <&> \case - Right s -> (Just s, Right s) - Left exn -> (Nothing, Left exn) - -{-| - Stop a running service. Do nothing if it's already stopped. --} -stopService - :: HasLogFunc e - => MVar (Maybe s) - -> (s -> RIO e ()) - -> RIO e (Either SomeException ()) -stopService vServ kkill = do - logInfo "stopService" - modifyMVar vServ $ \case - Nothing -> pure (Nothing, Right ()) - Just sv -> do - res <- try (kkill sv) - pure (Nothing, res) diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/Wai.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/Wai.hs deleted file mode 100644 index b47725498..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Eyre/Wai.hs +++ /dev/null @@ -1,234 +0,0 @@ -{-| - WAI Application for `eyre` driver. - - # Request Lifecycles - - - Requests come in, are given an identifier and are passed to a callback. - - - When requests timeout, the identifier is passed to anothing callback. - - - The server pulls response actions, and passes them to the associated - request. --} - -module Urbit.Vere.Eyre.Wai - ( RespAct(..) - , RespApi(..) - , LiveReqs(..) - , ReqInfo(..) - , emptyLiveReqs - , routeRespAct - , rmLiveReq - , newLiveReq - , app - ) -where - -import Urbit.Prelude hiding (Builder) - -import Data.Binary.Builder (Builder, fromByteString) -import Data.Bits (shiftL, (.|.)) -import Data.Conduit (ConduitT, Flush(Chunk, Flush), yield) -import Network.Socket (SockAddr(..)) -import System.Random (newStdGen, randoms) -import Urbit.Arvo (Address(..), Ipv4(..), Ipv6(..), Method) -import Urbit.Vere.Eyre.KingSubsite (KingSubsite, runKingSubsite) - -import qualified Network.HTTP.Types as H -import qualified Network.Wai as W -import qualified Network.Wai.Conduit as W - - --- Types ----------------------------------------------------------------------- - -data RespAct - = RAFull H.Status [H.Header] ByteString - | RAHead H.Status [H.Header] ByteString - | RABloc ByteString - | RADone - deriving (Eq, Ord, Show) - -data RespApi = RespApi - { raAct :: RespAct -> STM Bool - , raKil :: STM () - } - -data LiveReqs = LiveReqs - { reqIdSuply :: [Word64] - , activeReqs :: Map Word64 (Ship, RespApi) - } - -data ReqInfo = ReqInfo - { riAdr :: Address - , riMet :: H.StdMethod - , riUrl :: ByteString - , riHdr :: [H.Header] - , riBod :: ByteString - } - - --- Live Requests Table -- All Requests Still Waiting for Responses ------------- - -emptyLiveReqs :: IO LiveReqs -emptyLiveReqs = io $ do - gen <- newStdGen - pure (LiveReqs (randoms gen) mempty) - -routeRespAct :: Ship -> TVar LiveReqs -> Word64 -> RespAct -> STM Bool -routeRespAct who vLiv reqId act = - (lookup reqId . activeReqs <$> readTVar vLiv) >>= \case - Nothing -> pure False - Just (own, tv) -> do - if (who == own) - then raAct tv act - else pure False - -rmLiveReq :: TVar LiveReqs -> Word64 -> STM () -rmLiveReq var reqId = modifyTVar' var - $ \liv -> liv { activeReqs = deleteMap reqId (activeReqs liv) } - -allocateReqId :: TVar LiveReqs -> STM Word64 -allocateReqId var = do - LiveReqs supply tbl <- readTVar var - - let loop :: [Word64] -> (Word64, [Word64]) - loop [] = error "impossible" - loop (x:xs) | member x tbl = loop xs - loop (x:xs) | otherwise = (x, xs) - - let (fresh, supply') = loop supply - writeTVar var (LiveReqs supply' tbl) - pure fresh - -newLiveReq :: Ship -> TVar LiveReqs -> STM (Word64, STM RespAct) -newLiveReq who var = do - tmv <- newTQueue - kil <- newEmptyTMVar - nex <- allocateReqId var - - LiveReqs sup tbl <- readTVar var - - let waitAct = (<|>) (readTMVar kil $> RADone) (readTQueue tmv) - respApi = RespApi - { raKil = putTMVar kil () - , raAct = \act -> tryReadTMVar kil >>= \case - Nothing -> writeTQueue tmv act $> True - Just () -> pure False - } - - - writeTVar var (LiveReqs sup (insertMap nex (who, respApi) tbl)) - - pure (nex, waitAct) - - --- Random Helpers -------------------------------------------------------------- - -cookMeth :: W.Request -> Maybe Method -cookMeth = H.parseMethod . W.requestMethod >>> \case - Left _ -> Nothing - Right m -> Just m - -reqAddr :: W.Request -> Address -reqAddr = W.remoteHost >>> \case - SockAddrInet _ a -> AIpv4 (Ipv4 a) - SockAddrInet6 _ _ a _ -> AIpv6 (mkIpv6 a) - _ -> error "invalid sock addr" - -mkIpv6 :: (Word32, Word32, Word32, Word32) -> Ipv6 -mkIpv6 (p, q, r, s) = Ipv6 (pBits .|. qBits .|. rBits .|. sBits) - where - pBits = shiftL (fromIntegral p) 0 - qBits = shiftL (fromIntegral q) 32 - rBits = shiftL (fromIntegral r) 64 - sBits = shiftL (fromIntegral s) 96 - -reqUrl :: W.Request -> ByteString -reqUrl r = W.rawPathInfo r <> W.rawQueryString r - - --- Responses ------------------------------------------------------------------- - -noHeader :: HasLogFunc e => RIO e a -noHeader = do - logError "Response block with no response header." - error "Bad HttpEvent: Response block with no response header." - -dupHead :: HasLogFunc e => RIO e a -dupHead = do - logError "Multiple %head actions on one request" - error "Bad HttpEvent: Multiple header actions per on one request." - -{-| - - Immediately yield all of the initial chunks - - Yield the data from %bloc action. - - Close the stream when we hit a %done action. --} -streamBlocks - :: HasLogFunc e - => e - -> ByteString - -> STM RespAct - -> ConduitT () (Flush Builder) IO () -streamBlocks env init getAct = send init >> loop - where - loop = atomically getAct >>= \case - RAHead _ _ _ -> runRIO env dupHead - RAFull _ _ _ -> runRIO env dupHead - RADone -> pure () - RABloc c -> send c >> loop - - send "" = pure () - send c = do - runRIO env (logDebug (display ("sending chunk " <> tshow c))) - yield $ Chunk $ fromByteString c - yield Flush - -sendResponse - :: HasLogFunc e - => (W.Response -> IO W.ResponseReceived) - -> STM RespAct - -> RIO e W.ResponseReceived -sendResponse cb waitAct = do - env <- ask - atomically waitAct >>= \case - RADone -> io $ cb $ W.responseLBS (H.mkStatus 444 "No Response") [] "" - RAFull s h b -> io $ cb $ W.responseLBS s h $ fromStrict b - RAHead s h b -> io $ cb $ W.responseSource s h $ streamBlocks env b waitAct - RABloc _ -> noHeader - -liveReq :: Ship -> TVar LiveReqs -> RAcquire e (Word64, STM RespAct) -liveReq who vLiv = mkRAcquire ins del - where - ins = atomically (newLiveReq who vLiv) - del = atomically . rmLiveReq vLiv . fst - -app - :: HasLogFunc e - => e - -> Ship - -> TVar LiveReqs - -> (Word64 -> ReqInfo -> STM ()) - -> (Word64 -> STM ()) - -> KingSubsite - -> W.Application -app env who liv inform cancel sub req respond = - case W.pathInfo req of - ("~_~":_) -> runKingSubsite sub req respond - _ -> - runRIO env $ rwith (liveReq who liv) $ \(reqId, respApi) -> do - bod <- io (toStrict <$> W.strictRequestBody req) - met <- maybe (error "bad method") pure (cookMeth req) - - let adr = reqAddr req - hdr = W.requestHeaders req - url = reqUrl req - - atomically $ inform reqId $ ReqInfo adr met url hdr bod - - try (sendResponse respond respApi) >>= \case - Right rr -> pure rr - Left exn -> do - atomically (cancel reqId) - logError $ display ("Exception during request" <> tshow exn) - throwIO (exn :: SomeException) diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Http.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Http.hs deleted file mode 100644 index 54b926cdc..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Http.hs +++ /dev/null @@ -1,24 +0,0 @@ -{-| - HTTP Driver --} - -module Urbit.Vere.Http where - -import Urbit.Prelude -import Urbit.Arvo - -import qualified Data.CaseInsensitive as CI -import qualified Network.HTTP.Types as HT - --------------------------------------------------------------------------------- - -convertHeaders :: [HT.Header] -> [Header] -convertHeaders = fmap f - where - f (k, v) = Header (Cord $ decodeUtf8 $ CI.foldedCase k) - (MkBytes v) - -unconvertHeaders :: [Header] -> [HT.Header] -unconvertHeaders = fmap f - where - f (Header (Cord k) (MkBytes v)) = (CI.mk (encodeUtf8 k), v) diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Http/Client.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Http/Client.hs deleted file mode 100644 index 88cddb505..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Http/Client.hs +++ /dev/null @@ -1,218 +0,0 @@ -{-| - Http Client Driver - - TODO When making a request, handle the case where the request id is - already in use. --} - -module Urbit.Vere.Http.Client where - -import Urbit.Prelude hiding (Builder, finally) - -import Urbit.Vere.Http -import Urbit.Vere.Pier.Types -import Urbit.King.App - -import Urbit.Arvo (BlipEv(..), Ev(..), HttpClientEf(..), HttpClientEv(..), - HttpClientReq(..), HttpEvent(..), KingId, ResponseHeader(..)) - -import RIO.Orphans () -import Control.Monad.Catch (finally) - -import qualified Data.Map.Strict as M -import qualified Network.HTTP.Client as H -import qualified Network.HTTP.Client.TLS as TLS -import qualified Network.HTTP.Types as HT - - --- Types ----------------------------------------------------------------------- - -type ReqId = Word - -data HttpClientDrv = HttpClientDrv - { hcdManager :: H.Manager - , hcdLive :: TVar (Map ReqId (Async ())) - } - --------------------------------------------------------------------------------- - -cvtReq :: HttpClientReq -> Maybe H.Request -cvtReq r = - H.parseRequest (unpack (unCord $ url r)) <&> \init -> init - { H.method = encodeUtf8 $ tshow (method r) - , H.requestHeaders = unconvertHeaders (headerList r) - , H.requestBody = - H.RequestBodyBS $ case body r of - Nothing -> "" - Just (Octs bs) -> bs - } - -cvtRespHeaders :: H.Response a -> ResponseHeader -cvtRespHeaders resp = - ResponseHeader (fromIntegral $ HT.statusCode (H.responseStatus resp)) heads - where - heads = convertHeaders (H.responseHeaders resp) - -bornEv :: KingId -> Ev -bornEv king = - EvBlip $ BlipEvHttpClient $ HttpClientEvBorn (king, ()) () - --------------------------------------------------------------------------------- - -_bornFailed :: e -> WorkError -> IO () -_bornFailed env _ = runRIO env $ do - pure () -- TODO What to do in this case? - -client' - :: HasPierEnv e - => RIO e ([Ev], RAcquire e (DriverApi HttpClientEf)) -client' = do - ventQ :: TQueue EvErr <- newTQueueIO - env <- ask - - let (bornEvs, startDriver) = client env (writeTQueue ventQ) - - let runDriver = do - diOnEffect <- startDriver - let diEventSource = fmap RRWork <$> tryReadTQueue ventQ - pure (DriverApi {..}) - - pure (bornEvs, runDriver) - - -{-| - Iris -- HTTP Client Driver - - Until born events succeeds, ignore effects. - Wait until born event callbacks invoked. - If success, signal success. - If failure, try again several times. - If still failure, bring down ship. - Once born event succeeds, hold on to effects. - Once all other drivers have booted: - - Execute stashed effects. - - Begin normal operation (start accepting requests) --} -client - :: forall e - . (HasLogFunc e, HasKingId e) - => e - -> (EvErr -> STM ()) - -> ([Ev], RAcquire e (HttpClientEf -> IO ())) -client env plan = (initialEvents, runHttpClient) - where - kingId = view (kingIdL . to fromIntegral) env - - initialEvents :: [Ev] - initialEvents = [bornEv kingId] - - runHttpClient :: RAcquire e (HttpClientEf -> IO ()) - runHttpClient = handleEffect <$> mkRAcquire start stop - - start :: RIO e (HttpClientDrv) - start = HttpClientDrv <$> - (io $ H.newManager TLS.tlsManagerSettings) <*> - newTVarIO M.empty - - stop :: HttpClientDrv -> RIO e () - stop HttpClientDrv{..} = do - -- Cancel all the outstanding asyncs, ignoring any exceptions. - liveThreads <- atomically $ readTVar hcdLive - mapM_ cancel liveThreads - - handleEffect :: HttpClientDrv -> HttpClientEf -> IO () - handleEffect drv = \case - HCERequest _ id req -> runRIO env (newReq drv id req) - HCECancelRequest _ id -> runRIO env (cancelReq drv id) - - newReq :: HttpClientDrv -> ReqId -> HttpClientReq -> RIO e () - newReq drv id req = do - async <- runReq drv id req - -- If the async has somehow already completed, don't put it in the map, - -- because then it might never get out. - atomically $ pollSTM async >>= \case - Nothing -> modifyTVar' (hcdLive drv) (insertMap id async) - Just _ -> pure () - - -- The problem with the original http client code was that it was written - -- to the idea of what the events "should have" been instead of what they - -- actually were. This means that this driver doesn't run like the vere - -- http client driver. The vere driver was written assuming that parts of - -- events could be compressed together: a Start might contain the only - -- chunk of data and immediately complete, where here the Start event, the - -- Continue (with File) event, and the Continue (completed) event are three - -- separate things. - runReq :: HttpClientDrv -> ReqId -> HttpClientReq -> RIO e (Async ()) - runReq HttpClientDrv{..} id req = async $ flip finally aftr $ - case cvtReq req of - Nothing -> do - logInfo $ displayShow ("(malformed http client request)", id, req) - planEvent id (Cancel ()) - Just r -> do - logDebug $ displayShow ("(http client request)", id, req) - withRunInIO $ \run -> - H.withResponse r hcdManager $ \x -> run (exec x) - where - -- Make sure to remove our entry from hcdLive after we're done so the - -- map doesn't grow without bound. - aftr :: RIO e () - aftr = atomically $ modifyTVar' hcdLive (deleteMap id) - - recv :: H.BodyReader -> RIO e (Maybe ByteString) - recv read = io $ read <&> \case chunk | null chunk -> Nothing - | otherwise -> Just chunk - - exec :: H.Response H.BodyReader -> RIO e () - exec resp = do - let headers = cvtRespHeaders resp - getChunk = recv (H.responseBody resp) - loop = getChunk >>= \case - Nothing -> planEvent id (Continue Nothing True) - Just bs -> do - planEvent id $ - Continue (Just $ File $ Octs bs) False - loop - planEvent id (Start headers Nothing False) - loop - - planEvent :: ReqId -> HttpEvent -> RIO e () - planEvent id ev = do - logDebug $ displayShow ("(http client response)", id, (describe ev)) - - let recvEv = EvBlip - $ BlipEvHttpClient - $ HttpClientEvReceive (kingId, ()) (fromIntegral id) ev - - let recvFailed _ = pure () - - atomically $ plan (EvErr recvEv recvFailed) - - -- show an HttpEvent with byte count instead of raw data - describe :: HttpEvent -> String - describe (Start header Nothing final) = - "(Start " ++ (show header) ++ " ~ " ++ (show final) - describe (Start header (Just (File (Octs bs))) final) = - "(Start " ++ (show header) ++ " (" ++ (show $ length bs) ++ " bytes) " ++ - (show final) - describe (Continue Nothing final) = - "(Continue ~ " ++ (show final) - describe (Continue (Just (File (Octs bs))) final) = - "(Continue (" ++ (show $ length bs) ++ " bytes) " ++ (show final) - describe (Cancel ()) = "(Cancel ())" - - waitCancel :: Async a -> RIO e (Either SomeException a) - waitCancel async = cancel async >> waitCatch async - - cancelThread :: ReqId -> Async a -> RIO e () - cancelThread id = - waitCancel >=> \case Left _ -> planEvent id $ Cancel () - Right _ -> pure () - - cancelReq :: HttpClientDrv -> ReqId -> RIO e () - cancelReq drv id = - join $ atomically $ do - tbl <- readTVar (hcdLive drv) - case lookup id tbl of - Nothing -> pure (pure ()) - Just async -> do writeTVar (hcdLive drv) (deleteMap id tbl) - pure (cancelThread id async) diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/LockFile.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/LockFile.hs deleted file mode 100644 index c1aef5d45..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/LockFile.hs +++ /dev/null @@ -1,47 +0,0 @@ -{-| - Acquire and release the vere lockfile. --} - -module Urbit.Vere.LockFile (lockFile) where - -import Urbit.Prelude - -import Urbit.King.App.Class - -import Data.Default (def) -import RIO.Directory (createDirectoryIfMissing) -import System.IO.LockFile.Internal (LockingParameters(..), RetryStrategy(..), - LockingException(..), lock, unlock) - --------------------------------------------------------------------------------- - -lockFile :: (HasLogFunc e, HasStderrLogFunc e) => FilePath -> RAcquire e () -lockFile pax = void $ mkRAcquire start stop - where - fil = pax <> "/.vere.lock" - - stop handle = do - logInfo $ display @Text $ ("Releasing lock file: " <> pack fil) - io $ unlock fil handle - - params = def { retryToAcquireLock = No } - - start = do - createDirectoryIfMissing True pax - logInfo $ display @Text $ ("Taking lock file: " <> pack fil) - handle failure $ io (lock params fil) - - failure (e :: LockingException) = do - logStderr $ logError $ display @Text $ - "Cannot acquire lock file " <> pack fil <> "." - logStderr $ logError $ - "Please make sure there are no other instances of this ship running, " - <> "then try again." - logStderr $ logError $ - "If you are sure, you can delete the file and try again." - throwIO e - -logStderr :: HasStderrLogFunc e => RIO LogFunc a -> RIO e a -logStderr action = do - logFunc <- view stderrLogFuncL - runRIO logFunc action diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/NounServ.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/NounServ.hs deleted file mode 100644 index 4f60929ac..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/NounServ.hs +++ /dev/null @@ -1,186 +0,0 @@ -{-| - Use websockets to pass nouns between a client and server. --} - -module Urbit.Vere.NounServ - ( Conn(..) - , Server(..) - , Client(..) - , wsServer - , wsClient - , testIt - , wsServApp - , mkConn - , wsConn - ) where - -import Urbit.Prelude - -import qualified Network.Wai.Handler.Warp as W -import qualified Network.WebSockets as WS - --------------------------------------------------------------------------------- - -data Conn i o = Conn - { cRecv :: STM (Maybe i) - , cSend :: o -> STM () - } - -mkConn :: TBMChan i -> TBMChan o -> Conn i o -mkConn inp out = Conn (readTBMChan inp) (writeTBMChan out) - --------------------------------------------------------------------------------- - -data Client i o = Client - { cConn :: Conn i o - , cAsync :: Async () - } - -data Server i o a = Server - { sAccept :: STM (Maybe (Conn i o)) - , sAsync :: Async () - , sData :: a - } - --------------------------------------------------------------------------------- - -withRIOThread :: RIO e a -> RIO e (Async a) -withRIOThread act = do - env <- ask - io $ async $ runRIO env $ act - -wsConn :: (FromNoun i, ToNoun o, Show i, Show o, HasLogFunc e) - => Utf8Builder - -> TBMChan i -> TBMChan o - -> WS.Connection - -> RIO e () -wsConn pre inp out wsc = do - logDebug (pre <> "(wcConn) Connected!") - - writer <- withRIOThread $ forever $ do - logDebug (pre <> "(wsConn) Waiting for data.") - byt <- io $ toStrict <$> WS.receiveData wsc - logDebug (pre <> "Got data") - dat <- cueBSExn byt >>= fromNounExn - logDebug (pre <> "(wsConn) Decoded data, writing to chan") - atomically $ writeTBMChan inp dat - - reader <- withRIOThread $ forever $ do - logDebug (pre <> "Waiting for data from chan") - atomically (readTBMChan out) >>= \case - Nothing -> do - logDebug (pre <> "(wsConn) Connection closed") - error "dead-conn" - Just msg -> do - logDebug (pre <> "(wsConn) Got message! " <> displayShow msg) - io $ WS.sendBinaryData wsc $ fromStrict $ jamBS $ toNoun msg - - let cleanup = do - atomically (closeTBMChan inp >> closeTBMChan out) - cancel writer - cancel reader - - flip finally cleanup $ do - res <- atomically (waitCatchSTM writer <|> waitCatchSTM reader) - logInfo $ displayShow (res :: Either SomeException ()) - - --------------------------------------------------------------------------------- - -wsClient :: forall i o e. (ToNoun o, FromNoun i, Show o, Show i, HasLogFunc e) - => Text -> W.Port -> RIO e (Client i o) -wsClient pax por = do - env <- ask - inp <- io $ newTBMChanIO 5 - out <- io $ newTBMChanIO 5 - con <- pure (mkConn inp out) - - logInfo "NOUNSERV (wsClie) Trying to connect" - - tid <- io $ async - $ WS.runClient "127.0.0.1" por (unpack pax) - $ \con -> WS.withPingThread con 15 (pure ()) $ - runRIO env (wsConn "NOUNSERV (wsClie) " inp out con) - - pure $ Client con tid - --------------------------------------------------------------------------------- - -wsServApp :: (HasLogFunc e, ToNoun o, FromNoun i, Show i, Show o) - => (Conn i o -> STM ()) - -> WS.PendingConnection - -> RIO e () -wsServApp cb pen = do - logInfo "NOUNSERV (wsServer) Got connection!" - wsc <- io $ WS.acceptRequest pen - inp <- io $ newTBMChanIO 5 - out <- io $ newTBMChanIO 5 - atomically $ cb (mkConn inp out) - wsConn "NOUNSERV (wsServ) " inp out wsc - -wsServer :: forall i o e. (ToNoun o, FromNoun i, Show i, Show o, HasLogFunc e) - => RIO e (Server i o W.Port) -wsServer = do - con <- io $ newTBMChanIO 5 - - tid <- async $ do - env <- ask - logInfo "NOUNSERV (wsServer) Starting server" - io $ WS.runServer "127.0.0.1" 9999 - $ runRIO env . wsServApp (writeTBMChan con) - logInfo "NOUNSERV (wsServer) Server died" - atomically $ closeTBMChan con - - pure $ Server (readTBMChan con) tid 9999 - - --- Hacky Integration Test ------------------------------------------------------ - -fromJust :: MonadIO m => Text -> Maybe a -> m a -fromJust err Nothing = error (unpack err) -fromJust _ (Just x) = pure x - -type Example = Maybe (Word, (), Word) - -example :: Example -example = Just (99, (), 44) - -testIt :: HasLogFunc e => RIO e () -testIt = do - logDebug "(testIt) Starting Server" - Server{..} <- wsServer @Example @Example - logDebug "(testIt) Connecting" - Client{..} <- wsClient @Example @Example "/" sData - - logDebug "(testIt) Accepting connection" - sConn <- fromJust "accept" =<< atomically sAccept - - let - clientSend = do - logDebug "(testIt) Sending from client" - atomically (cSend cConn example) - logDebug "(testIt) Waiting for response" - res <- atomically (cRecv sConn) - print ("clientSend", res, example) - unless (res == Just example) $ do - error "Bad data" - logDebug "(testIt) Success" - - serverSend = do - logDebug "(testIt) Sending from server" - atomically (cSend sConn example) - logDebug "(testIt) Waiting for response" - res <- atomically (cRecv cConn) - print ("serverSend", res, example) - unless (res == Just example) $ do - error "Bad data" - logDebug "(testIt) Success" - - clientSend - clientSend - clientSend - serverSend - serverSend - - cancel sAsync - cancel cAsync diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Pier.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Pier.hs deleted file mode 100644 index 886da15c8..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Pier.hs +++ /dev/null @@ -1,702 +0,0 @@ -{-| - Top-Level Pier Management - - This is the code that starts the IO drivers and deals with communication - between the serf, the event log, and the IO drivers. --} -module Urbit.Vere.Pier - ( booted - , runSerf - , resumed - , getSnapshot - , pier - , runPersist - , runCompute - , genBootSeq - ) -where - -import Urbit.Prelude - -import Control.Monad.Trans.Maybe -import RIO.Directory -import Urbit.Arvo -import Urbit.King.App -import Urbit.Vere.Pier.Types -import Urbit.Vere.Stat - -import Control.Monad.STM (retry) -import System.Environment (getExecutablePath) -import System.FilePath (splitFileName) -import System.Posix.Files (ownerModes, setFileMode) -import Urbit.EventLog.LMDB (EventLog) -import Urbit.EventLog.Event (buildLogEvent) -import Urbit.King.API (TermConn) -import Urbit.TermSize (TermSize(..), termSize) -import Urbit.Vere.Serf (Serf) - -import qualified Data.Text as T -import qualified Data.List as L -import qualified System.Entropy as Ent -import qualified Urbit.EventLog.LMDB as Log -import qualified Urbit.King.API as King -import qualified Urbit.Noun.Time as Time -import qualified Urbit.Vere.Ames as Ames -import qualified Urbit.Vere.Behn as Behn -import qualified Urbit.Vere.Clay as Clay -import qualified Urbit.Vere.Eyre as Eyre -import qualified Urbit.Vere.Eyre.KingSubsite as Site -import qualified Urbit.Vere.Http.Client as Iris -import qualified Urbit.Vere.Serf as Serf -import qualified Urbit.Vere.Term as Term -import qualified Urbit.Vere.Term.API as Term -import qualified Urbit.Vere.Term.Demux as Term - - --- Initialize pier directory. -------------------------------------------------- - -data PierDirectoryAlreadyExists = PierDirectoryAlreadyExists - deriving (Show, Exception) - -setupPierDirectory :: FilePath -> RIO e () -setupPierDirectory shipPath = do - -- shipPath will already exist because we put a lock file there. - alreadyExists <- doesPathExist (shipPath ".urb") - when alreadyExists $ do - throwIO PierDirectoryAlreadyExists - for_ ["put", "get", "log", "chk"] $ \seg -> do - let pax = shipPath ".urb" seg - createDirectoryIfMissing True pax - io $ setFileMode pax ownerModes - - --- Load pill into boot sequence. ----------------------------------------------- - -data CannotBootFromIvoryPill = CannotBootFromIvoryPill - deriving (Show, Exception) - -genEntropy :: MonadIO m => m Entropy -genEntropy = Entropy . fromIntegral . bytesAtom <$> io (Ent.getEntropy 64) - -genBootSeq :: HasKingEnv e - => Ship -> Pill -> Bool -> LegacyBootEvent -> Feed -> RIO e BootSeq -genBootSeq _ PillIvory {} _ _ _ = throwIO CannotBootFromIvoryPill -genBootSeq ship PillPill {..} lite boot feed = do - ent <- io genEntropy - wyr <- wyrd - let ova = preKern ent - <> [wyr] - <> pKernelOva - <> postKern - <> extraKeys - <> pUserspaceOva - pure $ BootSeq ident pBootFormulae ova - where - ident = LogIdentity ship isFake (fromIntegral $ length pBootFormulae) - preKern ent = - [ EvBlip $ BlipEvArvo $ ArvoEvWhom () ship - , EvBlip $ BlipEvArvo $ ArvoEvWack () ent - ] - postKern = [EvBlip $ BlipEvTerm $ TermEvBoot (1, ()) lite boot] - isFake = case boot of - Fake _ -> True - _ -> False - extraKeys = case feed of - Feed0 _ -> [] - Feed1 Germs{..} -> fmap rekey gFeed - rekey Germ{..} = EvBlip $ BlipEvJael $ JaelEvRekey () (gLife, gRing) - - --- Write to the log. ----------------------------------------------------------- - --- | Write a batch of jobs to the event log. -writeJobs :: EventLog -> Vector Job -> RIO e () -writeJobs log !jobs = do - expect <- atomically (Log.nextEv log) - events <- fmap fromList $ traverse fromJob (zip [expect ..] $ toList jobs) - Log.appendEvents log events - where - fromJob :: (EventId, Job) -> RIO e ByteString - fromJob (expectedId, job) = do - unless (expectedId == jobId job) $ error $ show - ("bad job id!", expectedId, jobId job) - pure $ buildLogEvent (jobMug job) (jobPayload job) - - jobMug :: Job -> Mug - jobMug (RunNok (LifeCyc _ m _)) = m - jobMug (DoWork (Work _ m _ _)) = m - - jobPayload :: Job -> Noun - jobPayload (RunNok (LifeCyc _ _ n)) = toNoun n - jobPayload (DoWork (Work _ _ d o)) = toNoun (d, o) - - --- Acquire a running serf. ----------------------------------------------------- - -runSerf - :: HasPierEnv e - => TVar ((Atom, Tank) -> IO ()) - -> FilePath - -> RAcquire e Serf -runSerf vSlog pax = do - env <- ask - serfProg <- io getSerfProg - Serf.withSerf (config env serfProg) - where - slog s = atomically (readTVar vSlog) >>= (\f -> f s) - config env serfProg = Serf.Config - { scSerf = env ^. pierConfigL . pcSerfExe . to (maybe serfProg unpack) - , scPier = pax - , scFlag = env ^. pierConfigL . pcSerfFlags - , scSlog = slog - , scStdr = \txt -> slog (0, (textToTank txt)) - , scDead = pure () -- TODO: What can be done? - } - getSerfProg :: IO FilePath - getSerfProg = do - (path, filename) <- splitFileName <$> getExecutablePath - pure $ case filename of - "urbit" -> path "urbit-worker" - "urbit-king" -> path "urbit-worker" - _ -> "urbit-worker" - - --- Boot a new ship. ------------------------------------------------------------ - -booted - :: TVar ((Atom, Tank) -> IO ()) - -> Pill - -> Bool - -> Ship - -> LegacyBootEvent - -> Feed - -> RAcquire PierEnv (Serf, EventLog) -booted vSlog pill lite ship boot feed = do - rio $ bootNewShip pill lite ship boot feed - resumed vSlog Nothing - -bootSeqJobs :: Time.Wen -> BootSeq -> [Job] -bootSeqJobs now (BootSeq ident nocks ovums) = zipWith ($) bootSeqFns [1 ..] - where - wen :: EventId -> Time.Wen - wen off = Time.addGap now ((fromIntegral off - 1) ^. from Time.microSecs) - - bootSeqFns :: [EventId -> Job] - bootSeqFns = fmap nockJob nocks <> fmap ovumJob ovums - where - nockJob nok eId = RunNok $ LifeCyc eId 0 nok - ovumJob ov eId = DoWork $ Work eId 0 (wen eId) ov - -bootNewShip - :: HasPierEnv e - => Pill - -> Bool - -> Ship - -> LegacyBootEvent - -> Feed - -> RIO e () -bootNewShip pill lite ship bootEv feed = do - seq@(BootSeq ident x y) <- genBootSeq ship pill lite bootEv feed - logInfo "BootSeq Computed" - - pierPath <- view pierPathL - - rio (setupPierDirectory pierPath) - logInfo "Directory setup." - - let logPath = (pierPath ".urb/log") - - rwith (Log.new logPath ident) $ \log -> do - logInfo "Event log initialized." - jobs <- (\now -> bootSeqJobs now seq) <$> io Time.now - writeJobs log (fromList jobs) - - logInfo "Finsihed populating event log with boot sequence" - - --- Resume an existing ship. ---------------------------------------------------- - -resumed - :: TVar ((Atom, Tank) -> IO ()) - -> Maybe Word64 - -> RAcquire PierEnv (Serf, EventLog) -resumed vSlog replayUntil = do - rio $ logTrace "Resuming ship" - top <- view pierPathL - tap <- fmap (fromMaybe top) $ rio $ runMaybeT $ do - ev <- MaybeT (pure replayUntil) - MaybeT (getSnapshot top ev) - - rio $ do - logTrace $ display @Text ("pier: " <> pack top) - logTrace $ display @Text ("running serf in: " <> pack tap) - - log <- Log.existing (top ".urb/log") - serf <- runSerf vSlog tap - - rio $ do - logInfo "Replaying events" - Serf.execReplay serf log replayUntil >>= \case - Left err -> error (show err) - Right 0 -> do - logInfo "No work during replay so no snapshot" - pure () - Right _ -> do - logInfo "Taking snapshot" - io (Serf.snapshot serf) - logInfo "SNAPSHOT TAKEN" - - pure (serf, log) - --- | Get a fake pier directory for partial snapshots. -getSnapshot :: forall e . FilePath -> Word64 -> RIO e (Maybe FilePath) -getSnapshot top last = do - lastSnapshot <- lastMay <$> listReplays - pure (replayToPath <$> lastSnapshot) - where - replayDir = top ".partial-replay" - replayToPath eId = replayDir show eId - - listReplays :: RIO e [Word64] - listReplays = do - createDirectoryIfMissing True replayDir - snapshotNums <- mapMaybe readMay <$> listDirectory replayDir - pure $ sort (filter (<= fromIntegral last) snapshotNums) - - --- Run Pier -------------------------------------------------------------------- - -pier - :: (Serf, EventLog) - -> TVar ((Atom, Tank) -> IO ()) - -> MVar () - -> [Ev] - -> RAcquire PierEnv () -pier (serf, log) vSlog startedSig injected = do - let logId = Log.identity log :: LogIdentity - let ship = who logId :: Ship - - -- TODO Instead of using a TMVar, pull directly from the IO driver - -- event sources. - computeQ :: TMVar RunReq <- newEmptyTMVarIO - persistQ :: TBQueue (Fact, FX) <- newTBQueueIO 10 -- TODO tuning? - executeQ :: TBQueue FX <- newTBQueueIO 10 - saveSig :: TMVar () <- newEmptyTMVarIO - kingApi :: King.King <- King.kingAPI - - termApiQ :: TQueue TermConn <- atomically $ do - q <- newTQueue - writeTVar (King.kTermConn kingApi) (Just $ writeTQueue q) - pure q - - initialTermSize <- io $ termSize - - (demux :: Term.Demux, muxed :: Term.Client) <- atomically $ do - res <- Term.mkDemux initialTermSize - pure (res, Term.useDemux res) - - void $ acquireWorker "TERMSERV Listener" $ forever $ do - logInfo "TERMSERV Waiting for external terminal." - atomically $ do - ext <- Term.connClient <$> readTQueue termApiQ - Term.addDemux ext demux - logInfo "TERMSERV External terminal connected." - - scryQ <- newTQueueIO - onKill <- view onKillPierSigL - - -- Our call above to set the logging function which echos errors from the - -- Serf doesn't have the appended \r\n because those \r\n s are added in - -- the c serf code. Logging output from our haskell process must manually - -- add them. - let compute = putTMVar computeQ - let execute = writeTBQueue executeQ - let persist = writeTBQueue persistQ - let sigint = Serf.sendSIGINT serf - let scry = \g r -> do - res <- newEmptyMVar - atomically $ writeTQueue scryQ (g, r, putMVar res) - takeMVar res - - -- Set up the runtime stat counters. - stat <- newStat - - -- Set up the runtime subsite server and its capability to slog - -- and display stats. - siteSlog <- newTVarIO (const $ pure ()) - runtimeSubsite <- Site.kingSubsite ship scry (renderStat stat) siteSlog - - -- Slogs go to stderr, to the runtime subsite, and to the terminal. - env <- ask - atomically $ writeTVar vSlog $ \s@(_, tank) -> runRIO env $ do - atomically $ Term.slog muxed s - io $ readTVarIO siteSlog >>= ($ s) - logOther "serf" (display $ T.strip $ tankToText tank) - - let err = atomically . Term.trace muxed - (bootEvents, startDrivers) <- do - env <- ask - siz <- atomically $ Term.curDemuxSize demux - let fak = isFake logId - drivers env ship fak compute scry (siz, muxed) err sigint stat runtimeSubsite - - let computeConfig = ComputeConfig { ccOnWork = takeTMVar computeQ - , ccOnKill = onKill - , ccOnSave = takeTMVar saveSig - , ccOnScry = readTQueue scryQ - , ccPutResult = persist - , ccShowSpinner = Term.spin muxed - , ccHideSpinner = Term.stopSpin muxed - , ccLastEvInLog = Log.lastEv log - } - - tSerf <- acquireWorker "Serf" (runCompute serf computeConfig) - - doVersionNegotiation compute err - - -- Run all born events and retry them until they succeed. - wackEv <- EvBlip . BlipEvArvo . ArvoEvWack () <$> genEntropy - rio $ for_ (wackEv : bootEvents) $ \ev -> do - okaySig <- newEmptyMVar - - let inject n = atomically $ compute $ RRWork $ EvErr ev $ cb n - - -- TODO Make sure this dies cleanly. - cb :: Int -> WorkError -> IO () - cb n | n >= 3 = error ("boot event failed: " <> show ev) - cb n = \case - RunOkay _ _ -> putMVar okaySig () - RunSwap _ _ _ _ _ -> putMVar okaySig () - RunBail _ -> inject (n + 1) - - -- logTrace ("[BOOT EVENT]: " <> display (summarizeEvent ev)) - io (inject 0) - - let slog :: Text -> IO () - slog txt = do - fn <- atomically (readTVar vSlog) - fn (0, textToTank txt) - - drivz <- startDrivers - tExec <- acquireWorker "Effects" (router slog (readTBQueue executeQ) drivz) - tDisk <- acquireWorkerBound "Persist" (runPersist log persistQ execute) - - -- Now that the Serf is configured, the IO drivers are hooked up, their - -- starting events have been dispatched, and the terminal is live, we can now - -- handle injecting events requested from the command line. - for_ (zip [1..] injected) $ \(num, ev) -> rio $ do - logTrace $ display @Text ("Injecting event " ++ (tshow num) ++ " of " ++ - (tshow $ length injected) ++ "...") - okaySig :: MVar (Either [Goof] ()) <- newEmptyMVar - - let inject = atomically $ compute $ RRWork $ EvErr ev $ cb - cb :: WorkError -> IO () - cb = \case - RunOkay _ _ -> putMVar okaySig (Right ()) - RunSwap _ _ _ _ _ -> putMVar okaySig (Right ()) - RunBail goofs -> putMVar okaySig (Left goofs) - - io inject - - takeMVar okaySig >>= \case - Left goof -> logError $ display @Text ("Goof in injected event: " <> - tshow goof) - Right () -> pure () - - - let snapshotEverySecs = 120 - - void $ acquireWorker "Save" $ forever $ do - threadDelay (snapshotEverySecs * 1_000_000) - void $ atomically $ tryPutTMVar saveSig () - - putMVar startedSig () - - -- Wait for something to die. - - let ded = asum - [ death "effects thread" tExec - , death "persist thread" tDisk - , death "compute thread" tSerf - ] - - atomically ded >>= \case - Left (tag, exn) -> logError $ displayShow (tag, "crashed", exn) - Right "compute thread" -> pure () - Right tag -> logError $ displayShow (tag, "exited unexpectly") - - atomically $ (Term.spin muxed) (Just "shutdown") - -death :: Text -> Async () -> STM (Either (Text, SomeException) Text) -death tag tid = do - waitCatchSTM tid <&> \case - Left exn -> Left (tag, exn) - Right () -> Right tag - --- %wyrd version negotiation --------------------------------------------------- - -data PierVersionNegotiationFailed = PierVersionNegotiationFailed - deriving (Show, Exception) - -zuseVersion :: Word -zuseVersion = 419 - -wyrd :: HasKingEnv e => RIO e Ev -wyrd = do - king <- tshow <$> view kingIdL - - let k = Wynn [("zuse", zuseVersion), - ("lull", 330), - ("arvo", 240), - ("hoon", 140), - ("nock", 4)] - sen = MkTerm king - v = Vere sen [Cord "king-haskell", Cord "1.0"] k - - pure $ EvBlip $ BlipEvArvo $ ArvoEvWyrd () v - -doVersionNegotiation - :: HasPierEnv e - => (RunReq -> STM ()) - -> (Text -> RIO e ()) - -> RAcquire e () -doVersionNegotiation compute stderr = do - ev <- rio wyrd - - okaySig :: MVar (Either [Goof] FX) <- newEmptyMVar - let inject = atomically $ compute $ RRWork $ EvErr ev $ cb - cb :: WorkError -> IO () - cb = \case - RunOkay _ fx -> putMVar okaySig (Right fx) - RunSwap _ _ _ _ fx -> putMVar okaySig (Right fx) - RunBail goofs -> putMVar okaySig (Left goofs) - - rio $ stderr "vere: checking version compatibility" - io inject - - takeMVar okaySig >>= \case - Left goof -> do - rio $ stderr "pier: version negotation failed" - logError $ display @Text ("Goof in wyrd event: " <> tshow goof) - throwIO PierVersionNegotiationFailed - - Right fx -> do - -- Walk through the returned fx looking for a wend effect. If we find - -- one, check the zuse versions. - rio $ for_ fx $ \case - GoodParse (EfWend (Wynn xs)) -> case L.lookup "zuse" xs of - Nothing -> pure () - Just zuseVerInWynn -> - if zuseVerInWynn /= zuseVersion - then do - rio $ stderr "pier: pier: version negotiation failed; downgrade" - throwIO PierVersionNegotiationFailed - else - pure () - _ -> pure () - - --- Start All Drivers ----------------------------------------------------------- - -data Drivers = Drivers - { dBehn :: BehnEf -> IO () - , dIris :: HttpClientEf -> IO () - , dEyre :: HttpServerEf -> IO () - , dNewt :: NewtEf -> IO () - , dSync :: SyncEf -> IO () - , dTerm :: TermEf -> IO () - } - -drivers - :: HasPierEnv e - => e - -> Ship - -> Bool - -> (RunReq -> STM ()) - -> ScryFunc - -> (TermSize, Term.Client) - -> (Text -> RIO e ()) - -> IO () - -> Stat - -> Site.KingSubsite - -> RAcquire e ([Ev], RAcquire e Drivers) -drivers env who isFake plan scry termSys stderr serfSIGINT stat sub = do - let Stat{..} = stat - - (behnBorn, runBehn) <- rio Behn.behn' - (termBorn, runTerm) <- rio (Term.term' termSys (renderStat stat) serfSIGINT) - (amesBorn, runAmes) <- rio (Ames.ames' who isFake statAmes scry stderr) - (httpBorn, runEyre) <- rio (Eyre.eyre' who isFake stderr sub) - (clayBorn, runClay) <- rio Clay.clay' - (irisBorn, runIris) <- rio Iris.client' - - putStrLn ("ship is " <> tshow who) - - let initialEvents = mconcat [behnBorn,clayBorn,amesBorn,httpBorn,irisBorn,termBorn] - - let runDrivers = do - behn <- runBehn - term <- runTerm - ames <- runAmes - iris <- runIris - eyre <- runEyre - clay <- runClay - - -- Sources lower in the list are starved until sources above them - -- have no events to offer. - acquireWorker "Event Prioritization" $ forever $ atomically $ do - let x = diEventSource - let eventSources = [x term, x clay, x behn, x iris, x eyre, x ames] - pullEvent eventSources >>= \case - Nothing -> retry - Just rr -> plan rr - - pure $ Drivers - { dTerm = diOnEffect term - , dBehn = diOnEffect behn - , dNewt = diOnEffect ames - , dIris = diOnEffect iris - , dEyre = diOnEffect eyre - , dSync = diOnEffect clay - } - - pure (initialEvents, runDrivers) - where - pullEvent :: [STM (Maybe a)] -> STM (Maybe a) - pullEvent [] = pure Nothing - pullEvent (d:ds) = d >>= \case - Just r -> pure (Just r) - Nothing -> pullEvent ds - - --- Route Effects to Drivers ---------------------------------------------------- - -router :: HasPierEnv e => (Text -> IO ()) -> STM FX -> Drivers -> RIO e () -router slog waitFx Drivers {..} = do - kill <- view killPierActionL - let exit = io (slog "<<>>\r\n") >> atomically kill - let vega = io (slog "<<>>\r\n") - forever $ do - fx <- atomically waitFx - for_ fx $ \ef -> do - logEffect ef - case ef of - GoodParse (EfVega _ _ ) -> vega - GoodParse (EfExit _ _ ) -> exit - GoodParse (EfWend _ ) -> pure () - GoodParse (EfVane (VEBehn ef)) -> io (dBehn ef) - GoodParse (EfVane (VEBoat ef)) -> io (dSync ef) - GoodParse (EfVane (VEClay ef)) -> io (dSync ef) - GoodParse (EfVane (VEHttpClient ef)) -> io (dIris ef) - GoodParse (EfVane (VEHttpServer ef)) -> io (dEyre ef) - GoodParse (EfVane (VENewt ef)) -> io (dNewt ef) - GoodParse (EfVane (VESync ef)) -> io (dSync ef) - GoodParse (EfVane (VETerm ef)) -> io (dTerm ef) - FailParse n -> logError $ display $ pack @Text (ppShow n) - - --- Compute (Serf) Thread ------------------------------------------------------- - -logEvent :: HasLogFunc e => Ev -> RIO e () -logEvent ev = do - --logInfo $ "<- " <> display (summarizeEvent ev) - logDebug $ "[EVENT]\n" <> display pretty - where - pretty :: Text - pretty = pack $ unlines $ fmap ("\t" <>) $ lines $ ppShow ev - -logEffect :: HasLogFunc e => Lenient Ef -> RIO e () -logEffect ef = do - --logInfo $ " -> " <> display (summarizeEffect ef) - logDebug $ display $ "[EFFECT]\n" <> pretty ef - where - pretty :: Lenient Ef -> Text - pretty = \case - GoodParse e -> pack $ unlines $ fmap ("\t" <>) $ lines $ ppShow e - FailParse n -> pack $ unlines $ fmap ("\t" <>) $ lines $ ppShow n - -data ComputeConfig = ComputeConfig - { ccOnWork :: STM RunReq - , ccOnKill :: STM () - , ccOnSave :: STM () - , ccOnScry :: STM (Gang, ScryReq, Maybe (Term, Noun) -> IO ()) - , ccPutResult :: (Fact, FX) -> STM () - , ccShowSpinner :: Maybe Text -> STM () - , ccHideSpinner :: STM () - , ccLastEvInLog :: STM EventId - } - -runCompute :: forall e . HasKingEnv e => Serf.Serf -> ComputeConfig -> RIO e () -runCompute serf ComputeConfig {..} = do - logDebug "runCompute" - - let onRR = asum [ ccOnKill <&> Serf.RRKill - , ccOnSave <&> Serf.RRSave - , ccOnWork - , ccOnScry <&> \(g,r,k) -> Serf.RRScry g r k - ] - - vEvProcessing :: TMVar Ev <- newEmptyTMVarIO - - void $ async $ forever (atomically (takeTMVar vEvProcessing) >>= logEvent) - - let onSpin :: Maybe Ev -> STM () - onSpin = \case - Nothing -> ccHideSpinner - Just ev -> do - ccShowSpinner (getSpinnerNameForEvent ev) - putTMVar vEvProcessing ev - - let maxBatchSize = 10 - - io (Serf.run serf maxBatchSize ccLastEvInLog onRR ccPutResult onSpin) - - --- Event-Log Persistence Thread ------------------------------------------------ - -data PersistExn = BadEventId EventId EventId - deriving Show - -instance Exception PersistExn where - displayException (BadEventId expected got) = - unlines [ "Out-of-order event id send to persist thread." - , "\tExpected " <> show expected <> " but got " <> show got - ] - -runPersist - :: forall e - . HasPierEnv e - => EventLog - -> TBQueue (Fact, FX) - -> (FX -> STM ()) - -> RIO e () -runPersist log inpQ out = do - dryRun <- view dryRunL - forever $ do - -- This is not a memory leak because eventually the TBQueue at out will - -- fill up, blocking the loop. - writs <- atomically getBatchFromQueue - events <- validateFactsAndGetBytes (fst <$> toNullable writs) - unless dryRun (Log.appendEvents log events) - atomically $ for_ writs $ \(_, fx) -> do - out fx - - where - validateFactsAndGetBytes :: [Fact] -> RIO e (Vector ByteString) - validateFactsAndGetBytes facts = do - expect <- atomically (Log.nextEv log) - lis <- for (zip [expect ..] facts) $ \(expectedId, Fact eve mug wen non) -> - do - unless (expectedId == eve) $ do - throwIO (BadEventId expectedId eve) - pure $ buildLogEvent mug $ toNoun (wen, non) - pure (fromList lis) - - -- Read as much out of the queue as possible (i.e. the entire contents), - -- blocking if empty. - getBatchFromQueue :: STM (NonNull [(Fact, FX)]) - getBatchFromQueue = readTBQueue inpQ >>= go . singleton - where - go acc = tryReadTBQueue inpQ >>= \case - Nothing -> pure (reverse acc) - Just item -> go (item <| acc) diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Pier/Types.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Pier/Types.hs deleted file mode 100644 index 5f3fd11ea..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Pier/Types.hs +++ /dev/null @@ -1,119 +0,0 @@ -{-| - A bunch of common types. - - TODO Most of these could probably find better homes. --} -module Urbit.Vere.Pier.Types - ( module Urbit.Vere.Serf.Types - , LogIdentity(..) - , Pill(..) - , Job(..) - , LifeCyc(..) - , BootSeq(..) - , Work(..) - , jobId - , jobMug - , DriverApi(..) - , ScryFunc - ) -where - -import Urbit.Prelude - -import Urbit.Arvo -import Urbit.Noun.Time -import Urbit.Vere.Serf.Types - -import Urbit.EventLog.LMDB (LogIdentity(..)) - - --- Avoid touching Nock values. ------------------------------------------------- - -{-| - Nock values are raw nouns with tons of duplicated structure, so - printing or comparing them is insane. --} -newtype Nock = Nock Noun - deriving newtype (FromNoun, ToNoun) - -instance Eq Nock where - (==) (Nock x) (Nock y) = jamBS x == jamBS y - -instance Show Nock where - show _ = "Nock" - - --------------------------------------------------------------------------------- - -data Pill - = PillIvory [Noun] - | PillPill - { pName :: Noun - , pBootFormulae :: ![Nock] -- XX not actually nock, semantically - , pKernelOva :: ![Ev] - , pUserspaceOva :: ![Ev] - } - deriving (Eq, Show) - -data BootSeq = BootSeq !LogIdentity ![Nock] ![Ev] - deriving (Eq, Show) - -deriveNoun ''Pill - - --- Jobs ------------------------------------------------------------------------ - -data Work = Work EventId Mug Wen Ev - deriving (Eq, Show) - -data LifeCyc = LifeCyc EventId Mug Nock - deriving (Eq, Show) - -data Job - = DoWork Work - | RunNok LifeCyc - deriving (Eq, Show) - -jobId :: Job -> EventId -jobId (RunNok (LifeCyc eId _ _)) = eId -jobId (DoWork (Work eId _ _ _ )) = eId - -jobMug :: Job -> Mug -jobMug (RunNok (LifeCyc _ mug _)) = mug -jobMug (DoWork (Work _ mug _ _ )) = mug - - --- API To IO Drivers ----------------------------------------------------------- - -data DriverApi ef = DriverApi - { diEventSource :: STM (Maybe RunReq) - , diOnEffect :: ef -> IO () - } - - --- Scrying -------------------------------------------------------------------- - -type ScryFunc = Gang -> ScryReq -> IO (Maybe (Term, Noun)) - --- Instances ------------------------------------------------------------------- - -instance ToNoun Work where - toNoun (Work eid m d o) = toNoun (eid, Jammed (m, d, o)) - -instance FromNoun Work where - parseNoun n = named "Work" $ do - (eid, Jammed (m, d, o)) <- parseNoun n - pure (Work eid m d o) - -instance ToNoun LifeCyc where - toNoun (LifeCyc eid m n) = toNoun (eid, Jammed (m, n)) - -instance FromNoun LifeCyc where - parseNoun n = named "LifeCyc" $ do - (eid, Jammed (m, n)) <- parseNoun n - pure (LifeCyc eid m n) - --- | No FromNoun instance, because it depends on context (lifecycle length) -instance ToNoun Job where - toNoun (DoWork w) = toNoun w - toNoun (RunNok l) = toNoun l diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Ports.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Ports.hs deleted file mode 100644 index 024bd391f..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Ports.hs +++ /dev/null @@ -1,314 +0,0 @@ -module Urbit.Vere.Ports (HasPortControlApi(..), - PortControlApi, - buildInactivePorts, - buildNatPortsWhenPrivate, - buildNatPorts, - requestPortAccess) where - -import Control.Monad.STM (check) -import Urbit.Prelude -import Network.NatPmp -import Data.Time.Clock.POSIX -import Network.Socket - -import qualified Data.Heap as DH - --- This module deals with ports and port requests. When a component wants to --- ensure that it is externally reachable, possibly from outside a NAT, it --- makes a request to this module to hole-punch. - -class HasPortControlApi a where - portControlApiL :: Lens' a PortControlApi - -data PortControlApi = PortControlApi - { pAddPortRequest :: Word16 -> IO () - , pRemovePortRequest :: Word16 -> IO () - } - --- | Builds a PortControlApi struct which does nothing when called. -buildInactivePorts :: PortControlApi -buildInactivePorts = PortControlApi noop noop - where - noop x = pure () - --- | Builds a PortControlApi struct which tries to hole-punch by talking to the --- NAT gateway over NAT-PMP iff we are on a private network ip. -buildNatPortsWhenPrivate :: (HasLogFunc e) - => (Text -> RIO e ()) - -> RIO e PortControlApi -buildNatPortsWhenPrivate stderr = do - behind <- likelyBehindRouter - if behind - then buildNatPorts stderr - else pure buildInactivePorts - --- | Builds a PortControlApi struct which tries to hole-punch by talking to the --- NAT gateway over NAT-PMP. -buildNatPorts :: (HasLogFunc e) - => (Text -> RIO e ()) - -> RIO e PortControlApi -buildNatPorts stderr = do - q <- newTQueueIO - async $ portThread q stderr - - let addRequest port = do - resp <- newEmptyTMVarIO - atomically $ - writeTQueue q (PTMOpen port (putTMVar resp True)) - atomically $ takeTMVar resp - pure () - - let removeRequest port = atomically $ writeTQueue q (PTMClose port) - - pure $ PortControlApi addRequest removeRequest - -portLeaseLifetime :: Word32 -portLeaseLifetime = 15 * 60 - --- Be paranoid and renew leases a full minute before they would naturally expire. -portRenewalTime :: Word32 -portRenewalTime = portLeaseLifetime - 60 - --- Number of retries before we give up on performing nat operations. -maxRetries :: Int -maxRetries = 3 - --- How long to wait between retries. -networkRetryDelay :: Int -networkRetryDelay = 5 * 1_000_000 - --- Messages sent from the main thread to the port mapping communication thread. -data PortThreadMsg - = PTMOpen Word16 (STM ()) - -- ^ Does the open request, and then runs the passed in stm action to - -- signal completion to the main thread. We want to block on the initial - -- setting opening because we want the forwarding set up before we actually - -- start using the port. - - | PTMClose Word16 - -- ^ Close command. No synchronization because there's nothing we can do if - -- it fails. - --- We get requests to acquire a port as an RAII condition, but the actual APIs --- are timeout based, so we have to maintain a heap of the next timer to --- rerequest port access. -data RenewAction = RenewAction Word16 - --- The port thread is an async which reads commands from an STM queue and then --- executes them. This thread is here to bind the semantics that we want to how --- NAT-PMP sees the world. We want for an RAcquire to be able to start a --- request for port forwarding and then to release it when it goes out of --- scope. OTOH, NAT-PMP is all timeout based, and we want that timeout to be --- fairly short, such as 15 minutes, so the portThread needs to keep track of --- the time of the next port request. -portThread :: forall e. (HasLogFunc e) - => TQueue PortThreadMsg - -> (Text -> RIO e ()) - -> RIO e () -portThread q stderr = do - initNatPmp >>= \case - Left ErrCannotGetGateway -> do - assumeOnPublicInternet - Left err -> do - likelyIPAddress >>= \case - Just ip@(192, 168, _, _) -> warnBehindRouterAndErr ip err - Just ip@(172, x, _, _) - | (x >= 16 && x <= 31) -> warnBehindRouterAndErr ip err - Just ip@(10, _, _, _) -> warnBehindRouterAndErr ip err - _ -> assumeOnPublicInternet - Right pmp -> foundRouter pmp - where - warnBehindRouterAndErr (a, b, c, d) err = do - stderr $ "port: you appear to be behind a router since your ip " ++ - "is " ++ (tshow a) ++ "." ++ (tshow b) ++ "." ++ (tshow c) ++ - "." ++ (tshow d) ++ ", but " ++ - "we could not request port forwarding (NAT-PMP error: " ++ - (tshow err) ++ ")" - stderr $ "port: urbit performance will be degregaded unless you " ++ - "manually forward your ames port." - loopErr q - - assumeOnPublicInternet = do - stderr $ "port: couldn't find router; assuming on public internet" - loopErr q - - foundRouter :: NatPmpHandle -> RIO e () - foundRouter pmp = do - getPublicAddress pmp >>= \case - Left ErrCannotGetGateway -> assumeOnPublicInternet - Left ErrNoGatewaySupport -> assumeOnPublicInternet - Left err -> do - stderr $ "port: received error when asking router for public ip: " ++ - (tshow err) - loopErr q - Right addr -> do - let (a, b, c, d) = hostAddressToTuple addr - stderr $ "port: router reports that our public IP is " ++ (tshow a) ++ - "." ++ (tshow b) ++ "." ++ (tshow c) ++ "." ++ (tshow d) - loop pmp mempty - - loop :: NatPmpHandle -> DH.MinPrioHeap POSIXTime RenewAction -> RIO e () - loop pmp nextRenew = do - now <- io $ getPOSIXTime - delay <- case DH.viewHead nextRenew of - Nothing -> newTVarIO False - Just (fireTime, _) -> do - let timeTo = fireTime - now - let ms = round $ timeTo * 1000000 - registerDelay ms - command <- atomically $ - (Left <$> fini delay) <|> (Right <$> readTQueue q) - case command of - Left () -> handleRenew pmp nextRenew - Right msg -> handlePTM pmp msg nextRenew - - handlePTM :: NatPmpHandle - -> PortThreadMsg - -> DH.MinPrioHeap POSIXTime RenewAction - -> RIO e () - handlePTM pmp msg nextRenew = case msg of - PTMOpen p notifyComplete -> do - logInfo $ - displayShow ("port: sending initial request to NAT-PMP for port ", p) - setPortMapping pmp PTUdp p p portLeaseLifetime >>= \case - Left err | isResetAndRetry err -> do - closeNatPmp pmp - attemptReestablishNatPmpThen (\pmp -> handlePTM pmp msg nextRenew) - Left err -> do - logError $ - displayShow ("port: failed to request NAT-PMP for port ", p, - ":", err, ", disabling NAT-PMP") - loopErr q - Right _ -> do - -- Filter any existing references to this port on the heap to ensure - -- we don't double up on tasks. - let filteredHeap = filterPort p nextRenew - now <- io $ getPOSIXTime - let withRenew = - DH.insert (now + fromIntegral portRenewalTime, RenewAction p) - filteredHeap - atomically notifyComplete - loop pmp withRenew - - PTMClose p -> do - logInfo $ - displayShow ("port: releasing lease for ", p) - setPortMapping pmp PTUdp p p 0 - let removed = filterPort p nextRenew - loop pmp removed - - handleRenew :: NatPmpHandle - -> DH.MinPrioHeap POSIXTime RenewAction - -> RIO e () - handleRenew pmp nextRenew = do - case (DH.view nextRenew) of - Nothing -> error "Internal heap managing error." - Just ((_, RenewAction p), rest) -> do - logInfo $ - displayShow ("port: sending renewing request to NAT-PMP for port ", - p) - setPortMapping pmp PTUdp p p portLeaseLifetime >>= \case - Left err | isResetAndRetry err -> do - closeNatPmp pmp - attemptReestablishNatPmpThen (\pmp -> handleRenew pmp nextRenew) - Left err -> do - logError $ - displayShow ("port: failed to request NAT-PMP for port ", p, - ":", err, ". disabling NAT-PMP") - loopErr q - Right _ -> do - -- We don't need to filter the port because we just did. - now <- io $ getPOSIXTime - let withRenew = - DH.insert (now + fromIntegral portRenewalTime, RenewAction p) - rest - loop pmp withRenew - - -- If the internal natpmp socket is closed (laptop lid closed, network - -- change, etc), attempt to reestablish a connection. - attemptReestablishNatPmpThen :: (NatPmpHandle -> RIO e ()) - -> RIO e () - attemptReestablishNatPmpThen andThen = do - logInfo $ - displayShow ("port: network changed. Attempting NAT reconnect"); - loop 0 - where - loop :: Int -> RIO e () - loop tryNum = do - initNatPmp >>= \case - Left err -> do - if tryNum == maxRetries - then do - stderr $ "port: failed to reestablish a connection to your router" - loopErr q - else do - threadDelay networkRetryDelay - loop (tryNum + 1) - Right pmp -> do - andThen pmp - - filterPort :: Word16 - -> DH.MinPrioHeap POSIXTime RenewAction - -> DH.MinPrioHeap POSIXTime RenewAction - filterPort p = DH.filter okPort - where - okPort (_, RenewAction x) = p /= x - - -- block (retry) until the delay TVar is set to True - fini :: TVar Bool -> STM () - fini = check <=< readTVar - - -- The NAT system is considered "off" but we still need to signal back to - -- the main thread that blocking actions are complete. - loopErr q = forever $ do - (atomically $ readTQueue q) >>= \case - PTMOpen _ onComplete -> atomically onComplete - PTMClose _ -> pure () - --- When we were unable to connect to a router, get the ip address on the --- default ipv4 interface to check if we look like we're on an internal network --- or not. -likelyIPAddress :: MonadIO m => m (Maybe (Word8, Word8, Word8, Word8)) -likelyIPAddress = liftIO do - -- Try opening a socket to 1.1.1.1 to get our own IP address. Since UDP is - -- stateless and we aren't sending anything, we aren't actually contacting - -- them in any way. - sock <- socket AF_INET Datagram 0 - connect sock (SockAddrInet 53 (tupleToHostAddress (1, 1, 1, 1))) - sockAddr <- getSocketName sock - case sockAddr of - SockAddrInet _ addr -> pure $ Just $ hostAddressToTuple addr - _ -> pure $ Nothing - -likelyBehindRouter :: MonadIO m => m Bool -likelyBehindRouter = do - likelyIPAddress >>= \case - Just ip@(192, 168, _, _) -> pure True - Just ip@(172, x, _, _) - | (x >= 16 && x <= 31) -> pure True - Just ip@(10, _, _, _) -> pure True - _ -> pure False - --- Some of the errors that we encounter happen when the underlying sockets have --- closed out from under us. When this happens, we want to wait a short time --- and reset the system. -isResetAndRetry :: Error -> Bool -isResetAndRetry ErrRecvFrom = True -isResetAndRetry ErrSendErr = True -isResetAndRetry _ = False - --- Acquire a port for the duration of the RAcquire. -requestPortAccess :: forall e. (HasPortControlApi e) => Word16 -> RAcquire e () -requestPortAccess port = do - mkRAcquire request release - where - request :: RIO e () - request = do - api <- view portControlApiL - io $ pAddPortRequest api port - - release :: () -> RIO e () - release _ = do - api <- view portControlApiL - io $ pRemovePortRequest api port - diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Serf.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Serf.hs deleted file mode 100644 index 42c44df6b..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Serf.hs +++ /dev/null @@ -1,160 +0,0 @@ -{-| - High-Level Serf Interface --} - -module Urbit.Vere.Serf - ( withSerf - , execReplay - , collectFX - , module X - ) -where - -import Urbit.Prelude - -import Data.Conduit -import Urbit.Vere.Pier.Types -import Urbit.Vere.Serf.IPC - -import Control.Monad.Trans.Resource (runResourceT) -import Urbit.Arvo (FX) -import Urbit.King.App.Class (HasStderrLogFunc(..)) -import Urbit.EventLog.Event (parseLogEvent) - -import qualified Data.Conduit.Combinators as CC -import qualified System.ProgressBar as PB -import qualified Urbit.EventLog.LMDB as Log - -import qualified Urbit.Vere.Serf.IPC as X (Config (..), EvErr (..), Flag (..), - RunReq (..), Serf, WorkError (..), - run, sendSIGINT, snapshot, start, - stop) - - --------------------------------------------------------------------------------- - -withSerf :: HasLogFunc e => Config -> RAcquire e Serf -withSerf config = mkRAcquire startup kill - where - startup = do - (serf, st) <- io $ start config - logInfo (displayShow ("serf state", st)) - pure serf - kill serf = do - void $ rio $ stop serf - -execReplay - :: forall e - . (HasLogFunc e, HasStderrLogFunc e) - => Serf - -> Log.EventLog - -> Maybe Word64 - -> RIO e (Either PlayBail Word) -execReplay serf log last = do - lastEventInSnap <- io (serfLastEventBlocking serf) - if lastEventInSnap == 0 then doBoot else doReplay - where - doBoot :: RIO e (Either PlayBail Word) - doBoot = do - logInfo "Beginning boot sequence" - - let bootSeqLen = lifecycleLen (Log.identity log) - - evs <- runConduit $ Log.streamEvents log 1 - .| CC.take (fromIntegral bootSeqLen) - .| CC.mapM (fmap snd . parseLogEvent) - .| CC.sinkList - - let numEvs = fromIntegral (length evs) - - when (numEvs /= bootSeqLen) $ do - throwIO (MissingBootEventsInEventLog numEvs bootSeqLen) - - logInfo $ display ("Sending " <> tshow numEvs <> " boot events to serf") - - io (boot serf evs) >>= \case - Just err -> do - logInfo "Error on replay, exiting" - pure (Left err) - Nothing -> do - logInfo "Finished boot events, moving on to more events from log." - doReplay <&> \case - Left err -> Left err - Right num -> Right (num + numEvs) - - doReplay :: RIO e (Either PlayBail Word) - doReplay = do - logTrace "Beginning event log replay" - - lastEventInSnap <- io (serfLastEventBlocking serf) - - last & \case - Nothing -> pure () - Just lt -> logTrace $ display $ - "User requested to replay up to event #" <> tshow lt - - logLastEv :: Word64 <- atomically $ fromIntegral <$> Log.lastEv log - - logTrace $ display $ "Last event in event log is #" <> tshow logLastEv - - let replayUpTo = min (fromMaybe logLastEv last) logLastEv - - let numEvs :: Int = fromIntegral replayUpTo - fromIntegral lastEventInSnap - - when (numEvs < 0) $ do - throwIO (SnapshotAheadOfLog logLastEv lastEventInSnap) - - incProgress <- logStderr (trackProgress (fromIntegral numEvs)) - - logTrace $ display $ "Replaying up to event #" <> tshow replayUpTo - logTrace $ display $ "Will replay " <> tshow numEvs <> " in total." - - env <- ask - - res <- runResourceT - $ runConduit - $ Log.streamEvents log (lastEventInSnap + 1) - .| CC.take (fromIntegral numEvs) - .| CC.mapM (fmap snd . parseLogEvent) - .| replay 5 incProgress serf - - res & \case - Nothing -> pure (Right $ fromIntegral numEvs) - Just er -> pure (Left er) - -logStderr :: HasStderrLogFunc e => RIO LogFunc a -> RIO e a -logStderr action = do - logFunc <- view stderrLogFuncL - runRIO logFunc action - -trackProgress - :: HasLogFunc e - => Word64 - -> RIO e (Int -> IO ()) -trackProgress = \case - 0 -> pure $ const $ pure () - num -> do - let style = PB.defStyle { PB.stylePostfix = PB.exact } - let refresh = 10 - let init = PB.Progress 0 (fromIntegral num) () - bar <- PB.newProgressBar style refresh init - env <- ask - let incr = PB.incProgress bar - pure (runRIO env . incr) - - --- Collect FX ------------------------------------------------------------------ - -collectFX :: HasLogFunc e => Serf -> Log.EventLog -> RIO e () -collectFX serf log = do - lastEv <- io (serfLastEventBlocking serf) - runResourceT - $ runConduit - $ Log.streamEvents log (lastEv + 1) - .| CC.mapM (parseLogEvent >=> fromNounExn . snd) - .| swim serf - .| persistFX log - -persistFX :: MonadIO m => Log.EventLog -> ConduitT (EventId, FX) Void m () -persistFX log = CC.mapM_ $ \(eId, fx) -> do - Log.writeEffectsRow log eId $ jamBS $ toNoun fx diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Serf/IPC.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Serf/IPC.hs deleted file mode 100644 index 67128821f..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Serf/IPC.hs +++ /dev/null @@ -1,663 +0,0 @@ -{-| - Low-Level IPC flows for interacting with the serf process. - - - Serf process can be started and shutdown with `start` and `stop`. - - You can ask the serf what it's last event was with - `serfLastEventBlocking`. - - A running serf can be asked to compact it's heap or take a snapshot. - - You can scry into a running serf. - - A running serf can be asked to execute a boot sequence, replay from - existing events, and run a ship with `boot`, `replay`, and `run`. - - The `run` and `replay` flows will do batching of events to keep the - IPC pipe full. - - ``` - |% - :: +writ: from king to serf - :: - +$ writ - $% $: %live - $% [%cram eve=@] - [%exit cod=@] - [%save eve=@] - [%meld ~] - [%pack ~] - == == - :: sam=[gang (each path $%([%once @tas @tas path] [beam @tas beam]))] - [%peek mil=@ sam=*] - [%play eve=@ lit=(list ?((pair @da ovum) *))] - [%work mil=@ job=(pair @da ovum)] - == - :: +plea: from serf to king - :: - +$ plea - $% [%live ~] - [%ripe [pro=%1 hon=@ nok=@] eve=@ mug=@] - [%slog pri=@ tank] - [%flog cord] - $: %peek - $% [%done dat=(unit (cask))] - [%bail dud=goof] - == == - $: %play - $% [%done mug=@] - [%bail eve=@ mug=@ dud=goof] - == == - $: %work - $% [%done eve=@ mug=@ fec=(list ovum)] - [%swap eve=@ mug=@ job=(pair @da ovum) fec=(list ovum)] - [%bail lud=(list goof)] - == == - == - -- - ``` --} - -module Urbit.Vere.Serf.IPC - ( Serf - , start - , stop - , serfLastEventBlocking - , snapshot - , compact - , scry - , boot - , replay - , run - , swim - , sendSIGINT - , module Urbit.Vere.Serf.Types - ) -where - -import Urbit.Prelude hiding ((<|)) - -import Data.Bits -import Data.Conduit -import System.Process -import Urbit.Vere.Serf.Types -import Urbit.Vere.Serf.IPC.Types - -import Control.Monad.STM (retry) -import Control.Monad.Trans.Resource (MonadResource, allocate, runResourceT) -import Data.Sequence (Seq((:<|), (:|>))) -import Foreign.Marshal.Alloc (alloca) -import Foreign.Ptr (castPtr) -import Foreign.Storable (peek, poke) -import RIO.Prelude (decodeUtf8Lenient) -import System.Posix.Signals (sigINT, sigKILL, signalProcess) -import Urbit.Arvo (FX) -import Urbit.Arvo.Event -import Urbit.Noun.Time (Wen) - -import qualified Data.ByteString as BS -import qualified Data.ByteString.Unsafe as BS -import qualified System.IO.Error as IO -import qualified Urbit.Noun.Time as Time - - --- Serf API -------------------------------------------------------------------- - -data Serf = Serf - { serfSend :: Handle - , serfRecv :: Handle - , serfProc :: ProcessHandle - , serfSlog :: Slog -> IO () - , serfLock :: MVar (Maybe SerfState) - } - - --- Access Current Serf State --------------------------------------------------- - -serfLastEventBlocking :: Serf -> IO EventId -serfLastEventBlocking Serf{serfLock} = readMVar serfLock >>= \case - Nothing -> throwIO SerfNotRunning - Just ss -> pure (ssLast ss) - - --- Low Level IPC Functions ----------------------------------------------------- - -fromRightExn :: (Exception e, MonadIO m) => Either a b -> (a -> e) -> m b -fromRightExn (Left m) exn = throwIO (exn m) -fromRightExn (Right x) _ = pure x - --- TODO Support Big Endian -sendLen :: Serf -> Int -> IO () -sendLen s i = do - w <- evaluate (fromIntegral i :: Word64) - withWord64AsByteString w (hPut (serfSend s)) - where - withWord64AsByteString :: Word64 -> (ByteString -> IO a) -> IO a - withWord64AsByteString w k = alloca $ \wp -> do - poke wp w - bs <- BS.unsafePackCStringLen (castPtr wp, 8) - k bs - -sendBytes :: Serf -> ByteString -> IO () -sendBytes s bs = handle onIOError $ do - sendLen s (length bs) - hPut (serfSend s) bs - hFlush (serfSend s) - where - onIOError :: IOError -> IO () - onIOError = const (throwIO SerfConnectionClosed) - -recvBytes :: Serf -> Word64 -> IO ByteString -recvBytes serf = BS.hGet (serfRecv serf) . fromIntegral - -recvLen :: Serf -> IO Word64 -recvLen w = do - bs <- BS.hGet (serfRecv w) 8 - case length bs of - 8 -> BS.unsafeUseAsCString bs (peek @Word64 . castPtr) - _ -> throwIO SerfConnectionClosed - -recvResp :: Serf -> IO ByteString -recvResp serf = do - len <- recvLen serf - recvBytes serf len - - --- Send Writ / Recv Plea ------------------------------------------------------- - -sendWrit :: Serf -> Writ -> IO () -sendWrit s = sendBytes s . jamBS . toNoun - -recvPlea :: Serf -> IO Plea -recvPlea w = do - b <- recvResp w - n <- fromRightExn (cueBS b) (const $ BadPleaAtom $ bytesAtom b) - p <- fromRightExn (fromNounErr @Plea n) (\(p, m) -> BadPleaNoun n p m) - pure p - -recvPleaHandlingSlog :: Serf -> IO Plea -recvPleaHandlingSlog serf = loop - where - loop = recvPlea serf >>= \case - PSlog info -> serfSlog serf info >> loop - PFlog (Cord ofni) -> serfSlog serf (0, Tank $ Leaf $ Tape $ ofni) >> loop - other -> pure other - --- Higher-Level IPC Functions -------------------------------------------------- - -recvRipe :: Serf -> IO SerfInfo -recvRipe serf = recvPleaHandlingSlog serf >>= \case - PRipe ripe -> pure ripe - plea -> throwIO (UnexpectedPlea (toNoun plea) "expecting %play") - -recvPlay :: Serf -> IO Play -recvPlay serf = recvPleaHandlingSlog serf >>= \case - PPlay play -> pure play - plea -> throwIO (UnexpectedPlea (toNoun plea) "expecting %play") - -recvLive :: Serf -> IO () -recvLive serf = recvPleaHandlingSlog serf >>= \case - PLive () -> pure () - plea -> throwIO (UnexpectedPlea (toNoun plea) "expecting %live") - -recvWork :: Serf -> IO Work -recvWork serf = do - recvPleaHandlingSlog serf >>= \case - PWork work -> pure work - plea -> throwIO (UnexpectedPlea (toNoun plea) "expecting %work") - -recvPeek :: Serf -> IO (Maybe (Term, Noun)) -recvPeek serf = do - recvPleaHandlingSlog serf >>= \case - PPeek (SDone peek) -> pure peek - -- XX surface error content - PPeek (SBail dud) -> pure Nothing - plea -> throwIO (UnexpectedPlea (toNoun plea) "expecting %peek") - - --- Request-Response Points -- These don't touch the lock ----------------------- - -sendSnapshotRequest :: Serf -> EventId -> IO () -sendSnapshotRequest serf eve = do - sendWrit serf (WLive $ LSave eve) - recvLive serf - -sendCompactionRequest :: Serf -> IO () -sendCompactionRequest serf = do - sendWrit serf (WLive $ LPack ()) - recvLive serf - -sendScryRequest :: Serf -> Gang -> ScryReq -> IO (Maybe (Term, Noun)) -sendScryRequest serf g r = do - sendWrit serf (WPeek 0 g r) - recvPeek serf - -sendShutdownRequest :: Serf -> Atom -> IO () -sendShutdownRequest serf exitCode = do - sendWrit serf (WLive $ LExit exitCode) - pure () - - --- Starting the Serf ----------------------------------------------------------- - -compileFlags :: [Flag] -> Word -compileFlags = foldl' (\acc flag -> setBit acc (fromEnum flag)) 0 - -readStdErr :: Handle -> (Text -> IO ()) -> IO () -> IO () -readStdErr h onLine onClose = loop - where - loop = do - IO.tryIOError (BS.hGetLine h >>= onLine . decodeUtf8Lenient) >>= \case - Left exn -> onClose - Right () -> loop - -start :: Config -> IO (Serf, SerfInfo) -start (Config exePax pierPath flags onSlog onStdr onDead) = do - (Just i, Just o, Just e, p) <- createProcess pSpec - void $ async (readStdErr e onStdr onDead) - vLock <- newEmptyMVar - let serf = Serf i o p onSlog vLock - info <- recvRipe serf - putMVar vLock (Just $ siStat info) - pure (serf, info) - where - diskKey = "" - config = show (compileFlags flags) - rock = "0" -- XX support loading from rock - cache = "50000" -- XX support memo-cache size - args = ["serf", pierPath, diskKey, config, cache, rock] - pSpec = (proc exePax args) { std_in = CreatePipe - , std_out = CreatePipe - , std_err = CreatePipe - } - - --- Taking the SerfState Lock --------------------------------------------------- - -takeLock :: MonadIO m => Serf -> m SerfState -takeLock serf = io $ do - takeMVar (serfLock serf) >>= \case - Nothing -> putMVar (serfLock serf) Nothing >> throwIO SerfNotRunning - Just ss -> pure ss - -serfLockTaken - :: MonadResource m => Serf -> m (IORef (Maybe SerfState), SerfState) -serfLockTaken serf = snd <$> allocate take release - where - take = (,) <$> newIORef Nothing <*> takeLock serf - release (rv, _) = do - mRes <- readIORef rv - when (mRes == Nothing) (forcefullyKillSerf serf) - putMVar (serfLock serf) mRes - -withSerfLock - :: MonadResource m => Serf -> (SerfState -> m (SerfState, a)) -> m a -withSerfLock serf act = do - (vState , initialState) <- serfLockTaken serf - (newState, result ) <- act initialState - writeIORef vState (Just newState) - pure result - -withSerfLockIO :: Serf -> (SerfState -> IO (SerfState, a)) -> IO a -withSerfLockIO s a = runResourceT (withSerfLock s (io . a)) - - --- SIGINT ---------------------------------------------------------------------- - -sendSIGINT :: Serf -> IO () -sendSIGINT serf = do - getPid (serfProc serf) >>= \case - Nothing -> pure () - Just pid -> do - io $ signalProcess sigINT pid - - --- Killing the Serf ------------------------------------------------------------ - - -{-| - Ask the serf to shutdown. If it takes more than 2s, kill it with - SIGKILL. --} -stop :: HasLogFunc e => Serf -> RIO e () -stop serf = do - race_ niceKill (wait2sec >> forceKill) - where - wait2sec = threadDelay 2_000_000 - - niceKill = do - logTrace "Asking serf to shut down" - io (gracefullyKillSerf serf) - logTrace "Serf went down when asked." - - forceKill = do - logTrace "Serf taking too long to go down, kill with fire (SIGTERM)." - io (forcefullyKillSerf serf) - logTrace "Serf process killed with SIGTERM." - -{-| - Kill the serf by taking the lock, then asking for it to exit. --} -gracefullyKillSerf :: Serf -> IO () -gracefullyKillSerf serf@Serf{..} = do - finalState <- takeMVar serfLock - sendShutdownRequest serf 0 - waitForProcess serfProc - pure () - -{-| - Kill the serf by sending it a SIGKILL. --} -forcefullyKillSerf :: Serf -> IO () -forcefullyKillSerf serf = do - getPid (serfProc serf) >>= \case - Nothing -> pure () - Just pid -> do - io $ signalProcess sigKILL pid - io $ void $ waitForProcess (serfProc serf) - - --- Flows for Interacting with the Serf ----------------------------------------- - -{-| - Ask the serf to write a snapshot to disk. --} -snapshot :: Serf -> IO () -snapshot serf = withSerfLockIO serf $ \ss -> do - sendSnapshotRequest serf (ssLast ss) - pure (ss, ()) - -{-| - Ask the serf to de-duplicate and de-fragment it's heap. --} -compact :: Serf -> IO () -compact serf = withSerfLockIO serf $ \ss -> do - sendCompactionRequest serf - pure (ss, ()) - -{-| - Peek into the serf state. --} -scry :: Serf -> Gang -> ScryReq -> IO (Maybe (Term, Noun)) -scry serf g r = withSerfLockIO serf $ \ss -> do - (ss,) <$> sendScryRequest serf g r - -{-| - Given a list of boot events, send them to to the serf in a single - %play message. They must all be sent in a single %play event so that - the serf can determine the length of the boot sequence. --} -boot :: Serf -> [Noun] -> IO (Maybe PlayBail) -boot serf@Serf {..} seq = do - withSerfLockIO serf $ \ss -> do - sendWrit serf (WPlay 1 seq) - recvPlay serf >>= \case - PBail bail -> pure (ss, Just bail) - PDone mug -> pure (SerfState (fromIntegral $ length seq) mug, Nothing) - -{-| - Given a stream of nouns (from the event log), feed them into the serf - in batches of size `batchSize`. - - - On `%bail` response, return early. - - On IPC errors, kill the serf and rethrow. - - On success, return `Nothing`. --} -replay - :: forall m - . (MonadResource m, MonadUnliftIO m, MonadIO m) - => Int - -> (Int -> IO ()) - -> Serf - -> ConduitT Noun Void m (Maybe PlayBail) -replay batchSize cb serf = do - withSerfLock serf $ \ss -> do - (r, ss') <- loop ss - pure (ss', r) - where - loop :: SerfState -> ConduitT Noun Void m (Maybe PlayBail, SerfState) - loop ss@(SerfState lastEve lastMug) = do - awaitBatch batchSize >>= \case - [] -> pure (Nothing, SerfState lastEve lastMug) - evs -> do - let nexEve = lastEve + 1 - let newEve = lastEve + fromIntegral (length evs) - io $ sendWrit serf (WPlay nexEve evs) - io (recvPlay serf) >>= \case - PBail bail -> pure (Just bail, SerfState lastEve lastMug) - PDone newMug -> do - io (cb $ length evs) - loop (SerfState newEve newMug) - -{-| - TODO If this is slow, use a mutable vector instead of reversing a list. --} -awaitBatch :: Monad m => Int -> ConduitT i o m [i] -awaitBatch = go [] - where - go acc 0 = pure (reverse acc) - go acc n = await >>= \case - Nothing -> pure (reverse acc) - Just x -> go (x:acc) (n-1) - - --- Special Replay for Collecting FX -------------------------------------------- - -{-| - This does event-log replay using the running IPC flow so that we - can collect effects. - - We don't tolerate replacement events or bails since we are actually - replaying the log, so we just throw exceptions in those cases. --} -swim - :: forall m - . (MonadIO m, MonadUnliftIO m, MonadResource m) - => Serf - -> ConduitT (Wen, Ev) (EventId, FX) m () -swim serf = do - withSerfLock serf $ \SerfState {..} -> do - (, ()) <$> loop ssHash ssLast - where - loop - :: Mug - -> EventId - -> ConduitT (Wen, Ev) (EventId, FX) m SerfState - loop mug eve = await >>= \case - Nothing -> do - pure (SerfState eve mug) - Just (wen, evn) -> do - io (sendWrit serf (WWork 0 wen evn)) - io (recvWork serf) >>= \case - WBail goofs -> do - throwIO (BailDuringReplay eve goofs) - WSwap eid hash (wen, noun) fx -> do - throwIO (SwapDuringReplay eid hash (wen, noun) fx) - WDone eid hash fx -> do - yield (eid, fx) - loop hash eid - - - --- Running Ship Flow ----------------------------------------------------------- - -{-| - TODO Don't take snapshot until event log has processed current event. --} -run - :: Serf - -> Int - -> STM EventId - -> STM RunReq - -> ((Fact, FX) -> STM ()) - -> (Maybe Ev -> STM ()) - -> IO () -run serf maxBatchSize getLastEvInLog onInput sendOn spin = topLoop - where - topLoop :: IO () - topLoop = atomically onInput >>= \case - RRWork workErr -> doWork workErr - RRSave () -> doSave - RRKill () -> doKill - RRPack () -> doPack - RRScry g r k -> doScry g r k - - doPack :: IO () - doPack = compact serf >> topLoop - - waitForLog :: IO () - waitForLog = do - serfLast <- serfLastEventBlocking serf - atomically $ do - logLast <- getLastEvInLog - when (logLast < serfLast) retry - - doSave :: IO () - doSave = waitForLog >> snapshot serf >> topLoop - - doKill :: IO () - doKill = waitForLog >> snapshot serf >> pure () - - doScry :: Gang -> ScryReq -> (Maybe (Term, Noun) -> IO ()) -> IO () - doScry g r k = (scry serf g r >>= k) >> topLoop - - doWork :: EvErr -> IO () - doWork firstWorkErr = do - que <- newTBMQueueIO 1 - () <- atomically (writeTBMQueue que firstWorkErr) - tWork <- async (processWork serf maxBatchSize que onWorkResp spin) - -- Avoid wrapping all subsequent runs of the event loop in an exception - -- handler which retains tWork. - nexSt <- flip onException (cancel tWork) $ do - nexSt <- workLoop que - wait tWork - pure nexSt - nexSt - - workLoop :: TBMQueue EvErr -> IO (IO ()) - workLoop que = atomically onInput >>= \case - RRKill () -> atomically (closeTBMQueue que) >> pure doKill - RRSave () -> atomically (closeTBMQueue que) >> pure doSave - RRPack () -> atomically (closeTBMQueue que) >> pure doPack - RRScry g r k -> atomically (closeTBMQueue que) >> pure (doScry g r k) - RRWork workErr -> atomically (writeTBMQueue que workErr) >> workLoop que - - onWorkResp :: Wen -> EvErr -> Work -> IO () - onWorkResp wen (EvErr evn err) = \case - WDone eid hash fx -> do - io $ err (RunOkay eid fx) - atomically $ sendOn ((Fact eid hash wen (toNoun evn)), fx) - WSwap eid hash (wen, noun) fx -> do - io $ err (RunSwap eid hash wen noun fx) - atomically $ sendOn (Fact eid hash wen noun, fx) - WBail goofs -> do - io $ err (RunBail goofs) - - -{-| - Given: - - - A stream of incoming requests - - A sequence of in-flight requests that haven't been responded to - - A maximum number of in-flight requests. - - Wait until the number of in-fligh requests is smaller than the maximum, - and then take the next item from the stream of requests. --} -pullFromQueueBounded :: Int -> TVar (Seq a) -> TBMQueue b -> STM (Maybe b) -pullFromQueueBounded maxSize vInFlight queue = do - inFlight <- length <$> readTVar vInFlight - if inFlight >= maxSize - then retry - else readTBMQueue queue - -{-| - Given - - - `maxSize`: The maximum number of jobs to send to the serf before - getting a response. - - `q`: A bounded queue (which can be closed) - - `onResp`: a callback to call for each response from the serf. - - `spin`: a callback to tell the terminal driver which event is - currently being processed. - - Pull jobs from the queue and send them to the serf (eagerly, up to - `maxSize`) and call the callback with each response from the serf. - - When the queue is closed, wait for the serf to respond to all pending - work, and then return. - - Whenever the serf is idle, call `spin Nothing` and whenever the serf - is working on an event, call `spin (Just ev)`. --} -processWork - :: Serf - -> Int - -> TBMQueue EvErr - -> (Wen -> EvErr -> Work -> IO ()) - -> (Maybe Ev -> STM ()) - -> IO () -processWork serf maxSize q onResp spin = do - vDoneFlag <- newTVarIO False - vInFlightQueue <- newTVarIO empty - recvThread <- async (recvLoop serf vDoneFlag vInFlightQueue spin) - flip onException (print "KILLING: processWork" >> cancel recvThread) $ do - loop vInFlightQueue vDoneFlag - wait recvThread - where - loop :: TVar (Seq (Ev, Work -> IO ())) -> TVar Bool -> IO () - loop vInFlight vDone = do - atomically (pullFromQueueBounded maxSize vInFlight q) >>= \case - Nothing -> do - atomically (writeTVar vDone True) - Just evErr@(EvErr ev _) -> do - now <- Time.now - let cb = onResp now evErr - atomically $ modifyTVar' vInFlight (:|> (ev, cb)) - sendWrit serf (WWork 0 now ev) - loop vInFlight vDone - -{-| - Given: - - - `vDone`: A flag that no more work will be sent to the serf. - - - `vWork`: A list of work requests that have been sent to the serf, - haven't been responded to yet. - - If the serf has responded to all work requests, and no more work is - going to be sent to the serf, then return. - - If we are going to send more work to the serf, but the queue is empty, - then wait. - - If work requests have been sent to the serf, take the first one, - wait for a response from the serf, call the associated callback, - and repeat the whole process. --} -recvLoop - :: Serf - -> TVar Bool - -> TVar (Seq (Ev, Work -> IO ())) - -> (Maybe Ev -> STM ()) - -> IO () -recvLoop serf vDone vWork spin = do - withSerfLockIO serf \SerfState {..} -> do - loop ssLast ssHash - where - loop eve mug = do - atomically $ do - whenM (null <$> readTVar vWork) $ do - spin Nothing - atomically takeCallback >>= \case - Nothing -> pure (SerfState eve mug, ()) - Just (curEve, cb) -> do - atomically (spin (Just curEve)) - recvWork serf >>= \case - work@(WDone eid hash _) -> cb work >> loop eid hash - work@(WSwap eid hash _ _) -> cb work >> loop eid hash - work@(WBail _) -> cb work >> loop eve mug - - takeCallback :: STM (Maybe (Ev, Work -> IO ())) - takeCallback = do - ((,) <$> readTVar vDone <*> readTVar vWork) >>= \case - (False, Empty ) -> retry - (True , Empty ) -> pure Nothing - (_ , (e, x) :<| xs) -> writeTVar vWork xs $> Just (e, x) - (_ , _ ) -> error "impossible" diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Serf/IPC/Types.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Serf/IPC/Types.hs deleted file mode 100644 index 09f1b36a9..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Serf/IPC/Types.hs +++ /dev/null @@ -1,59 +0,0 @@ -{-# LANGUAGE StrictData #-} - -module Urbit.Vere.Serf.IPC.Types where - -import Urbit.Prelude hiding ((<|)) -import Urbit.Arvo (Ev, FX) -import Urbit.Noun.Time (Wen) -import Urbit.Vere.Serf.Types - --- Private data structures for Urbit.Vere.Serf.IPC, but made StrictData without --- making the rest of Urbit.Vere.Serf.IPC strict. - -data Live - = LExit Atom -- exit status code - | LSave EventId - | LCram EventId - | LPack () - deriving (Show) - -data Play - = PDone Mug - | PBail PlayBail - deriving (Show) - -data Scry - = SDone (Maybe (Term, Noun)) - | SBail Goof - deriving (Show) - -data Work - = WDone EventId Mug FX - | WSwap EventId Mug (Wen, Noun) FX - | WBail [Goof] - deriving (Show) - -data Writ - = WLive Live - | WPeek Atom Gang ScryReq - | WPlay EventId [Noun] - | WWork Atom Wen Ev - deriving (Show) - -data Plea - = PLive () - | PRipe SerfInfo - | PSlog Slog - | PFlog Cord - | PPeek Scry - | PPlay Play - | PWork Work - deriving (Show) - -deriveNoun ''Live -deriveNoun ''Play -deriveNoun ''Scry -deriveNoun ''Work -deriveNoun ''Writ -deriveNoun ''Plea - diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Serf/Types.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Serf/Types.hs deleted file mode 100644 index c0979a878..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Serf/Types.hs +++ /dev/null @@ -1,135 +0,0 @@ -module Urbit.Vere.Serf.Types where - -import Urbit.Prelude - -import Urbit.Arvo (Desk, Ev, FX) -import Urbit.Noun.Time (Wen) - - --- Types ----------------------------------------------------------------------- - -type EventId = Word64 - -type PlayBail = (EventId, Mug, Goof) - -type Slog = (Atom, Tank) - -data SerfState = SerfState - { ssLast :: !EventId - , ssHash :: !Mug - } - deriving (Show, Eq) - -data RipeInfo = RipeInfo - { riProt :: !Atom - , riHoon :: !Atom - , riNock :: !Atom - } - deriving (Show) - -data SerfInfo = SerfInfo - { siRipe :: !RipeInfo - , siStat :: !SerfState - } - deriving (Show) - -data Fact = Fact - { factEve :: EventId - , factMug :: Mug - , factWen :: Wen - , factNon :: Noun - } - -data Flag - = DebugRam - | DebugCpu - | CheckCorrupt - | CheckFatal - | Verbose - | DryRun - | Quiet - | Hashless - | Trace - deriving (Eq, Ord, Show, Enum, Bounded) - -data Config = Config - { scSerf :: FilePath -- Where is the urbit-worker executable? - , scPier :: FilePath -- Where is the pier directory? - , scFlag :: [Flag] -- Serf execution flags. - , scSlog :: Slog -> IO () -- What to do with slogs? - , scStdr :: Text -> IO () -- What to do with lines from stderr? - , scDead :: IO () -- What to do when the serf process goes down? - } - - --- Serf Commands --------------------------------------------------------------- - -type Gang = Maybe (HoonSet Ship) - -type Goof = (Term, [Tank]) - -data EvErr = EvErr Ev (WorkError -> IO ()) - -{-| - Two types of serf failures. - - - `RunSwap`: Event processing failed, but the serf replaced it with - another event which succeeded. - - - `RunBail`: Event processing failed and all attempt to replace it - with a failure-notice event also caused crashes. We are really fucked. --} -data WorkError -- TODO Rename type and constructors - = RunSwap EventId Mug Wen Noun FX -- TODO Maybe provide less info here? - | RunBail [Goof] - | RunOkay EventId FX - -{- - - RRWork: Ask the serf to do work, will output (Fact, FX) if work - succeeded and call callback on failure. - - RRSave: Wait for the serf to finish all pending work --} -data RunReq - = RRWork EvErr - | RRSave () - | RRKill () - | RRPack () - | RRScry Gang ScryReq (Maybe (Term, Noun) -> IO ()) - -type ScryReq = (Each Path Demi) - -data Demi - = DemiOnce Term Desk Path - | DemiBeam Term Beam - deriving (Show) - --- TODO -type Beam = Void - -deriveNoun ''Demi - - --- Exceptions ------------------------------------------------------------------ - -data SerfExn - = UnexpectedPlea Noun Text - | BadPleaAtom Atom - | BadPleaNoun Noun [Text] Text - | PeekBail Goof - | SerfConnectionClosed - | SerfHasShutdown - | BailDuringReplay EventId [Goof] - | SwapDuringReplay EventId Mug (Wen, Noun) FX - | SerfNotRunning - | MissingBootEventsInEventLog Word Word - | SnapshotAheadOfLog EventId EventId - | BailDuringWyrd [Goof] - | SwapDuringWyrd Mug (Wen, Noun) FX - deriving (Show, Exception) - - --- Instances ------------------------------------------------------------------- - -deriveNoun ''RipeInfo -deriveNoun ''SerfInfo -deriveNoun ''SerfState diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Stat.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Stat.hs deleted file mode 100644 index 910df9c34..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Stat.hs +++ /dev/null @@ -1,75 +0,0 @@ -module Urbit.Vere.Stat where - -import Urbit.Prelude - -data Stat = Stat - { statAmes :: AmesStat - } - -data AmesStat = AmesStat - { asUdp :: TVar Word - , asUqf :: TVar Word - , asUdf :: TVar Word - , asUi6 :: TVar Word - , asRcv :: TVar Word - , asSup :: TVar Word - , asSrf :: TVar Word - , asQuf :: TVar Word - , asFwd :: TVar Word - , asDrt :: TVar Word - , asDvr :: TVar Word - , asDml :: TVar Word - , asSwp :: TVar Word - , asBal :: TVar Word - , asOky :: TVar Word - } - -newStat :: MonadIO m => m Stat -newStat = do - asUdp <- newTVarIO 0 - asUqf <- newTVarIO 0 - asUdf <- newTVarIO 0 - asUi6 <- newTVarIO 0 - asRcv <- newTVarIO 0 - asSup <- newTVarIO 0 - asSrf <- newTVarIO 0 - asQuf <- newTVarIO 0 - asFwd <- newTVarIO 0 - asDrt <- newTVarIO 0 - asDvr <- newTVarIO 0 - asDml <- newTVarIO 0 - asSwp <- newTVarIO 0 - asBal <- newTVarIO 0 - asOky <- newTVarIO 0 - pure Stat{statAmes = AmesStat{..}} - -bump :: MonadIO m => TVar Word -> m () -bump s = atomically $ bump' s - -bump' :: TVar Word -> STM () -bump' s = modifyTVar' s (+ 1) - -type RenderedStat = [Text] - -renderStat :: MonadIO m => Stat -> m RenderedStat -renderStat Stat{statAmes = AmesStat{..}} = - sequence - [ pure "stat:" - , pure " ames:" - , (" udp ingress: " <>) <$> tshow <$> readTVarIO asUdp - , (" udp queue evict: " <>) <$> tshow <$> readTVarIO asUqf - , (" udp recv fail: " <>) <$> tshow <$> readTVarIO asUdf - , (" udp dropped non-ipv4: " <>) <$> tshow <$> readTVarIO asUi6 - , (" driver ingress: " <>) <$> tshow <$> readTVarIO asRcv - , (" enqueued for serf: " <>) <$> tshow <$> readTVarIO asSup - , (" sent to serf: " <>) <$> tshow <$> readTVarIO asSrf - , (" serf queue evict: " <>) <$> tshow <$> readTVarIO asQuf - , (" forwarded: " <>) <$> tshow <$> readTVarIO asFwd - , (" dropped (unroutable): " <>) <$> tshow <$> readTVarIO asDrt - , (" dropped (wrong version): " <>) <$> tshow <$> readTVarIO asDvr - , (" dropped (malformed): " <>) <$> tshow <$> readTVarIO asDml - , (" serf swapped: " <>) <$> tshow <$> readTVarIO asSwp - , (" serf bailed: " <>) <$> tshow <$> readTVarIO asBal - , (" serf okay: " <>) <$> tshow <$> readTVarIO asOky - ] - diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Term.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Term.hs deleted file mode 100644 index ccd4c676d..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Term.hs +++ /dev/null @@ -1,777 +0,0 @@ -{-| - Terminal Driver --} -module Urbit.Vere.Term - ( module Term - , localClient - , connectToRemote - , runTerminalClient - , connClient - , term - , term' - ) where - -import Data.Char -import Foreign.Marshal.Alloc -import Foreign.Ptr -import Foreign.Storable -import RIO.FilePath -import System.Posix.IO -import System.Posix.Terminal -import Urbit.Arvo -import Urbit.King.App -import Urbit.Noun.Time -import Urbit.Prelude hiding (getCurrentTime) -import Urbit.Vere.Pier.Types - -import Data.List ((!!)) -import RIO.Directory (createDirectoryIfMissing) -import Urbit.King.API (readPortsFile) -import Urbit.Vere.Stat (RenderedStat) -import Urbit.TermSize (TermSize(TermSize)) -import Urbit.Vere.Term.API (Client(Client), ClientTake(..)) - -import qualified Data.Set as S -import qualified Data.ByteString.Internal as BS -import qualified Data.ByteString.UTF8 as BS -import qualified System.Console.ANSI as ANSI -import qualified Urbit.TermSize as T -import qualified Urbit.Vere.NounServ as Serv -import qualified Urbit.Vere.Term.API as Term -import qualified Urbit.Vere.Term.Render as T - - --- Types ----------------------------------------------------------------------- - --- | All stateful data in the printing to stdOutput. -data LineState = LineState - { lsLine :: [(Stye, [Char])] - , lsCurPos :: CurPos - , lsSpinTimer :: Maybe (Async ()) - , lsSpinCause :: Maybe Text - , lsSpinFirstRender :: Bool - , lsSpinFrame :: Int - , lsPrevEndTime :: Wen - } - -data CurPos = CurPos - { row :: Int - , col :: Int - } - --- | A record used in reading data from stdInput. -data ReadData = ReadData - { rdBuf :: Ptr Word8 - , rdEscape :: Bool - , rdBracket :: Bool - , rdMouse :: Bool - , rdMouseBut :: Word8 - , rdMouseCol :: Word8 - , rdUTF8 :: ByteString - , rdUTF8width :: Int - } - --- | Private data to the Client that we keep around for stop(). -data Private = Private - { pReaderThread :: Async () - , pWriterThread :: Async () - , pPreviousConfiguration :: TerminalAttributes - } - --- Utils ----------------------------------------------------------------------- - -blewEvent :: Word -> Word -> Ev -blewEvent w h = EvBlip $ BlipEvTerm $ TermEvBlew (UD 1, ()) w h - -initialHail :: Ev -initialHail = EvBlip $ BlipEvTerm $ TermEvHail (UD 1, ()) () - --- Version one of this is punting on the ops_u.dem flag: whether we're running --- in daemon mode. - --------------------------------------------------------------------------------- - -rioAllocaBytes :: (MonadIO m, MonadUnliftIO m) - => Int -> (Ptr a -> m b) -> m b -rioAllocaBytes size action = - withRunInIO $ \run -> - allocaBytes size $ \x -> run (action x) - -{-| - Because of legacy reasons, some file operations are in the terminal - driver. These should be filtered out and handled locally instead of - in any abstractly connected terminal. --} -isTerminalBlit :: Blit -> Bool -isTerminalBlit (Sav _ _) = False -isTerminalBlit (Sag _ _) = False -isTerminalBlit _ = True - --------------------------------------------------------------------------------- - -connClient :: Serv.Conn ClientTake [Term.Ev] -> Client -connClient c = Client - { give = Serv.cSend c - , take = Serv.cRecv c - } - -connectToRemote :: forall e. HasLogFunc e - => Port - -> Client - -> RAcquire e (Async (), Async ()) -connectToRemote port local = mkRAcquire start stop - where - stop (x, y) = cancel x >> cancel y - start = do - Serv.Client{..} <- Serv.wsClient "/terminal/0" (fromIntegral port) - - -- TODO XX Handle disconnect more cleanly. - ferry <- async $ forever $ atomically $ asum - [ Term.take local >>= \case - Nothing -> empty - Just ev -> Serv.cSend cConn ev - , Serv.cRecv cConn >>= \case - Nothing -> empty - Just ev -> Term.give local ev - ] - - pure (ferry, cAsync) - -data HackConfigDir = HCD { _hcdPax :: FilePath } -makeLenses ''HackConfigDir -instance HasPierPath HackConfigDir where pierPathL = hcdPax - -runTerminalClient :: forall e. HasLogFunc e => FilePath -> RIO e () -runTerminalClient pier = runRAcquire $ do - mPort <- runRIO (HCD pier) readPortsFile - port <- maybe (error "Can't connect") pure mPort - mExit <- io newEmptyTMVarIO - cli <- localClient (putTMVar mExit ()) - (tid, sid) <- connectToRemote (Port $ fromIntegral port) cli - atomically $ waitSTM tid <|> waitSTM sid <|> takeTMVar mExit - - where - runRAcquire :: RAcquire e () -> RIO e () - runRAcquire act = rwith act $ const $ pure () - - --- Spinner --------------------------------------------------------------------- - --- Call an STM action after delay of `first` microseconds and then every --- `rest` microseconds after that. -repeatedly :: Int -> Int -> STM () -> IO () -repeatedly first rest action = do - threadDelay first - forever $ do - atomically action - threadDelay rest - -spinners :: [Text] -spinners = ["|", "/", "-", "\\"] - -leftBracket, rightBracket :: Text -leftBracket = "«" -rightBracket = "»" - -_spin_fast_us, _spin_cool_us, _spin_warm_us, _spin_rate_us, _spin_idle_us :: Integral i => i -_spin_fast_us = 100000 -_spin_cool_us = 500000 -_spin_warm_us = 50000 -_spin_rate_us = 250000 -_spin_idle_us = 500000 - - --- Client ---------------------------------------------------------------------- - -{-| - Initializes the generalized input/output parts of the terminal. --} -localClient :: forall e. HasLogFunc e - => STM () - -> RAcquire e Client -localClient doneSignal = fst <$> mkRAcquire start stop - where - start :: HasLogFunc e => RIO e (Client, Private) - start = do - tsWriteQueue <- newTQueueIO :: RIO e (TQueue [Term.Ev]) - spinnerMVar <- newEmptyTMVarIO :: RIO e (TMVar ()) - - -- Track the terminal size, keeping track of the size of the local - -- terminal for our own printing, as well as putting size changes into an - -- event queue so we can send changes to the terminal muxing system. - tsizeTVar <- newTVarIO (TermSize 80 24) -- Value doesn't matter. - tsSizeChange <- newEmptyTMVarIO - io $ T.liveTermSize (\ts -> atomically $ do - -- We keep track of the console's local size for - -- our own tank washing. - writeTVar tsizeTVar ts - - -- We queue up changes so we can broadcast them - -- to the muxing client. - putTMVar tsSizeChange ts) - - -- start mouse reporting - putStr "\x1b[?9h" - - pWriterThread <- asyncBound - (writeTerminal tsWriteQueue spinnerMVar tsizeTVar) - - pPreviousConfiguration <- io $ getTerminalAttributes stdInput - - -- Create a new configuration where we put the terminal in raw mode and - -- disable a bunch of preprocessing. - let newTermSettings = flip withTime 0 - $ flip withMinInput 1 - $ foldl' withoutMode pPreviousConfiguration - $ disabledFlags - - io $ setTerminalAttributes stdInput newTermSettings Immediately - - tsReadQueue <- newTQueueIO - pReaderThread <- asyncBound - (readTerminal tsReadQueue tsWriteQueue tsizeTVar (bell tsWriteQueue)) - - let client = Client { take = Just <$> asum - [ readTQueue tsReadQueue <&> ClientTakeBelt, - takeTMVar tsSizeChange <&> ClientTakeSize - ] - , give = writeTQueue tsWriteQueue - } - - pure (client, Private{..}) - - stop :: HasLogFunc e - => (Client, Private) -> RIO e () - stop (Client{..}, Private{..}) = do - -- Note that we don't `cancel pReaderThread` here. This is a deliberate - -- decision because fdRead calls into a native function which the runtime - -- can't kill. If we were to cancel here, the internal `waitCatch` would - -- block until the next piece of keyboard input. Since this only happens - -- at shutdown, just leak the file descriptor. - cancel pWriterThread - - -- stop mouse reporting - putStr "\x1b[?9l" - - -- inject one final newline, as we're usually on the prompt. - putStr "\r\n" - - -- take the terminal out of raw mode - io $ setTerminalAttributes stdInput pPreviousConfiguration Immediately - - {- - A list of terminal flags that we disable. - - TODO: Terminal library missing CSIZE? - -} - disabledFlags :: [TerminalMode] - disabledFlags = [ StartStopOutput - , KeyboardInterrupts - , EnableEcho - , EchoLF - , ProcessInput - , ExtendedFunctions - , MapCRtoLF - , CheckParity - , StripHighBit - , EnableParity - , ProcessOutput - ] - - - -- Writes data to the terminal. Both the terminal reading, normal logging, - -- and effect handling can all emit bytes which go to the terminal. - --TODO blanks, traces and slogs should only be written into the default - -- terminal session. - writeTerminal :: TQueue [Term.Ev] -> TMVar () -> TVar TermSize -> RIO e () - writeTerminal q spinner termSizeVar = do - currentTime <- io $ now - loop - termSizeVar - (LineState [] (CurPos 0 0) Nothing Nothing True 0 currentTime) - where - writeBlank :: LineState -> RIO e LineState - writeBlank ls = do - TermSize _ height <- readTVarIO termSizeVar - --NOTE hijack creates a blank line - T.hijack (fromIntegral height) $ pure () - pure ls - - writeTrace :: LineState -> Text -> RIO e LineState - writeTrace ls p = do - TermSize _ height <- readTVarIO termSizeVar - T.hijack (fromIntegral height) $ putStr p - pure ls - - writeSlog :: LineState -> (Atom, Tank) -> RIO e LineState - writeSlog ls slog = do - TermSize width height <- readTVarIO termSizeVar - T.hijack (fromIntegral height) do - let lines = fmap (pref . unTape) $ - wash (WashCfg 0 width) $ tankTree $ snd slog - T.putCsi 'm' styl - forM (intersperse "\n" lines) $ \line -> putStr line - T.putCsi 'm' [0] - pure ls - where - prio = fromIntegral $ fst slog - maxp = 3 - styl - | prio == 3 = [31] - | prio == 2 = [33] - | prio == 1 = [32] - | otherwise = [90] - pref - | prio > 0 && prio <= maxp = - ((replicate prio '>' ++ replicate (1 + maxp - prio) ' ') ++) - | otherwise = id - - {- - Figure out how long to wait to show the spinner. When we - don't have a vane name to display, we assume its a user - action and trigger immediately. Otherwise, if we receive an - event shortly after a previous spin, use a shorter delay to - avoid giving the impression of a half-idle system. - -} - doSpin :: LineState -> Maybe Text -> RIO e LineState - doSpin ls@LineState{..} mTxt = do - maybe (pure ()) cancel lsSpinTimer - - current <- io $ now - delay <- pure $ case mTxt of - Nothing -> _spin_fast_us - Just _ -> - if (gap current lsPrevEndTime ^. microSecs) < _spin_idle_us - then _spin_warm_us - else _spin_cool_us - - spinTimer <- io $ async - $ repeatedly delay _spin_rate_us - $ void - $ tryPutTMVar spinner () - - pure $ ls { lsSpinTimer = Just spinTimer - , lsSpinCause = mTxt - , lsSpinFirstRender = True - } - - unspin :: LineState -> RIO e LineState - unspin ls@LineState{..} = do - maybe (pure ()) cancel lsSpinTimer - -- We do a final flush of the spinner mvar to ensure we don't - -- have a lingering signal which will redisplay the spinner after - -- we call termRestoreLine below. - atomically $ tryTakeTMVar spinner - - -- If we ever actually ran the spinner display callback, we need - -- to force a redisplay of the command prompt. - if not lsSpinFirstRender - then termRestoreLine ls termSizeVar - else pure () - - endTime <- io $ now - pure $ ls { lsSpinTimer = Nothing, lsPrevEndTime = endTime } - - execEv :: LineState -> Term.Ev -> RIO e LineState - execEv ls = \case - Term.Blits bs -> foldM (writeBlit termSizeVar) ls bs - Term.Trace p -> writeTrace ls (unCord p) - Term.Slog s -> writeSlog ls s - Term.Blank -> writeBlank ls - Term.Spinr (Just txt) -> doSpin ls (unCord <$> txt) - Term.Spinr Nothing -> unspin ls - - spin :: TVar TermSize -> LineState -> RIO e LineState - spin ts ls@LineState{..} = do - let spinner = (spinners !! lsSpinFrame) ++ case lsSpinCause of - Nothing -> "" - Just str -> leftBracket ++ str ++ rightBracket - - --NOTE even after first render, because cursor might have moved... - if row lsCurPos > 0 - then do - TermSize _ h <- readTVarIO ts - T.cursorMove (fromIntegral h - 1) 0 - else - T.cursorRestore - - putStr (spinner <> pack (ANSI.cursorBackwardCode (length spinner))) - - let newFrame = (lsSpinFrame + 1) `mod` length spinners - - pure $ ls { lsSpinFirstRender = False - , lsSpinFrame = newFrame - } - - loop :: TVar TermSize -> LineState -> RIO e () - loop ts ls = do - join $ atomically $ asum - [ readTQueue q >>= pure . (foldM execEv ls >=> loop ts) - , takeTMVar spinner >> pure (spin ts ls >>= loop ts) - ] - - -- Writes an individual blit to the screen - writeBlit :: TVar TermSize -> LineState -> Blit -> RIO e LineState - writeBlit ts ls = \case - Bel () -> T.soundBell $> ls - Clr () -> do T.clearScreen - T.cursorRestore - pure ls - Hop t -> case t of - Col c -> termShowCursor ls ts 0 (fromIntegral c) - Roc r c -> termShowCursor ls ts (fromIntegral r) (fromIntegral c) - Klr s -> termShowStub ls s - Put c -> termShowLine ls (pack c) - Nel () -> termShowNewline ls - Sag path noun -> pure ls - Sav path atom -> pure ls - Url url -> pure ls - Wyp () -> termShowClear ls - -- - Lin c -> do termShowCursor ls ts 0 0 - termShowClear ls - termShowLine ls (pack c) - Mor () -> termShowNewline ls - - termRenderDeco :: Deco -> Char - termRenderDeco = \case - DecoBr -> '1' - DecoUn -> '4' - DecoBl -> '5' - DecoNull -> '0' - - termRenderTint :: Tint -> [Char] - termRenderTint = \case - TintK -> ['0'] - TintR -> ['1'] - TintG -> ['2'] - TintY -> ['3'] - TintB -> ['4'] - TintM -> ['5'] - TintC -> ['6'] - TintW -> ['7'] - TintNull -> ['9'] - TintTrue r g b -> - mconcat ["8;2;", show r, ";", show g, ";", show b] - - -- Wraps the appropriate escape sequence around a piece of styled text - termRenderStubSegment :: Stye -> [Char] -> [Char] - termRenderStubSegment Stye {..} tape = - case (S.null decoset, back, fore) of - (True, TintNull, TintNull) -> tape - _ -> styled - where - decoset = setFromHoonSet deco - escape = [chr 27, '['] - - styles = intercalate ";" $ filter (not . null) - [ intersperse ';' $ fmap termRenderDeco $ toList decoset - , case back of - TintNull -> [] - tint -> '4' : termRenderTint tint - , case fore of - TintNull -> [] - tint -> '3' : termRenderTint tint - ] - - styled = mconcat [escape, styles, "m", tape, escape, "0m"] - - bareStub :: [Char] -> [(Stye, [Char])] - bareStub c = [(Stye (setToHoonSet mempty) TintNull TintNull, c)] - - -- overwrite substring of base with put, starting at index - overwriteStub :: [(Stye, [Char])] -> Int -> [(Stye, [Char])] -> [(Stye, [Char])] - overwriteStub base index put = - scagStub index base - ++ ( let l = lentStub base in - if index <= l then [] - else bareStub $ take (index - l) [' ',' '..] - ) - ++ put - ++ slagStub (index + lentStub put) base - where - lentStub :: [(Stye, [Char])] -> Int - lentStub s = sum $ map (length . snd) s - - scagStub :: Int -> [(Stye, [Char])] -> [(Stye, [Char])] - scagStub 0 _ = [] - scagStub _ [] = [] - scagStub i ((y,c):s) = - (y, take i c) : scagStub (i - min i (length c)) s - - slagStub :: Int -> [(Stye, [Char])] -> [(Stye, [Char])] - slagStub 0 s = s - slagStub _ [] = [] - slagStub i ((y,c):s) - | i > l = slagStub (i - l) s - | otherwise = (y, drop i c) : s - where l = length c - - -- Displays styled text at the cursor - termShowStub :: LineState -> Stub -> RIO e LineState - termShowStub ls@LineState{lsCurPos, lsLine} (Stub s) = do - putStr $ pack $ mconcat $ fmap (uncurry termRenderStubSegment) s - T.cursorRestore - case row lsCurPos of - 0 -> pure ls { lsLine = overwriteStub lsLine (col lsCurPos) s } - _ -> pure ls - - -- Moves the cursor to the requested position - termShowCursor :: LineState -> TVar TermSize -> Int -> Int -> RIO e LineState - termShowCursor ls ts row col = do - TermSize _ h <- readTVarIO ts - T.cursorMove (max 0 (fromIntegral h - row - 1)) col - T.cursorSave - pure ls { lsCurPos = CurPos row col } - - -- Displays and sets the current line - termShowLine :: LineState -> Text -> RIO e LineState - termShowLine ls@LineState{lsCurPos, lsLine} newStr = do - putStr newStr - T.cursorRestore - case row lsCurPos of - 0 -> pure ls { lsLine = overwriteStub lsLine (col lsCurPos) (bareStub $ unpack newStr) } - _ -> pure ls - - termShowClear :: LineState -> RIO e LineState - termShowClear ls@LineState{lsCurPos} = do - putStr "\r" - T.clearLine - T.cursorRestore - case row lsCurPos of - 0 -> pure ls { lsLine = [] } - _ -> pure ls - - -- New Current Line - termShowNewline :: LineState -> RIO e LineState - termShowNewline ls@LineState{lsCurPos} = do - putStr "\r\n" - case row lsCurPos of - 0 -> pure ls { lsLine = [], lsCurPos = lsCurPos { col = 0 } } - r -> pure ls { lsCurPos = CurPos (r-1) 0 } - - -- Redraw the bottom LineState, maintaining the current curpos - termRestoreLine :: LineState -> TVar TermSize -> RIO e () - termRestoreLine ls@LineState{lsLine} ts = do - TermSize _ h <- readTVarIO ts - T.cursorMove (fromIntegral h - 1) 0 - T.clearLine - putStr $ pack $ mconcat $ fmap (uncurry termRenderStubSegment) lsLine - T.cursorRestore - - -- ring my bell - bell :: TQueue [Term.Ev] -> RIO e () - bell q = atomically $ writeTQueue q $ [Term.Blits [Bel ()]] - - -- Reads data from stdInput and emit the proper effect - -- - -- This entire path is a divergence from how term.c does things, - -- probably. First, the vtime is 0, not 1 in term.c. So (IIUC), we'll - -- always have a latency of 1/10 of a second. - -- - -- A better way to do this would be to get some sort of epoll on stdInput, - -- since that's kinda closer to what libuv does? - readTerminal :: forall e. HasLogFunc e - => TQueue Belt - -> TQueue [Term.Ev] - -> TVar TermSize - -> RIO e () - -> RIO e () - readTerminal rq wq ts bell = - rioAllocaBytes 1 $ \ buf - -> loop (ReadData buf False False False 0 0 mempty 0) - where - loop :: ReadData -> RIO e () - loop rd@ReadData{..} = do - -- The problem with using fdRead raw is that it will text encode - -- things like \ESC instead of 27. That makes it broken for our - -- purposes. - -- - io (try $ fdReadBuf stdInput rdBuf 1) >>= \case - Left (e :: IOException) -> do - -- Ignore EAGAINs when doing reads - loop rd - Right 0 -> loop rd - Right _ -> do - w <- io $ peek rdBuf - -- print ("{" ++ (show w) ++ "}") - let c = BS.w2c w - if rdEscape then - if rdBracket then do - case c of - 'A' -> sendBelt $ Bol $ Aro U - 'B' -> sendBelt $ Bol $ Aro D - 'C' -> sendBelt $ Bol $ Aro R - 'D' -> sendBelt $ Bol $ Aro L - 'M' -> pure () - _ -> bell - rd <- case c of - 'M' -> pure rd { rdMouse = True } - _ -> pure rd - loop rd { rdEscape = False, rdBracket = False } - else if isAsciiLower c then do - sendBelt $ Mod Met $ Key c - loop rd { rdEscape = False } - else if w == 8 || w == 127 then do - sendBelt $ Mod Met $ Bac () - loop rd { rdEscape = False } - else if c == '[' || c == '0' then do - loop rd { rdBracket = True } - else do - bell - loop rd { rdEscape = False } - else if rdMouse then - if rdMouseBut == 0 then do - loop rd { rdMouseBut = w - 31 } - else if rdMouseCol == 0 then do - loop rd { rdMouseCol = w - 32 } - else do - if rdMouseBut == 1 then do - let rdMouseRow = w - 32 - TermSize _ h <- readTVarIO ts - sendBelt $ Bol $ Hit - (fromIntegral h - fromIntegral rdMouseRow) - (fromIntegral rdMouseCol - 1) - else do pure () - loop rd { rdMouse = False, rdMouseBut = 0, rdMouseCol = 0 } - else if rdUTF8width /= 0 then do - -- continue reading into the utf8 accumulation buffer - rd@ReadData{..} <- pure rd { rdUTF8 = snoc rdUTF8 w } - if length rdUTF8 /= rdUTF8width then loop rd - else do - case BS.decode rdUTF8 of - Nothing -> - error "empty utf8 accumulation buffer" - Just (c, bytes) | bytes /= rdUTF8width -> - error "utf8 character size mismatch?!" - Just (c, bytes) -> sendBelt $ Bol $ Key c - loop rd { rdUTF8 = mempty, rdUTF8width = 0 } - else if w >= 32 && w < 127 then do - sendBelt $ Bol $ Key c - loop rd - else if w == 0 then do - bell - loop rd - else if w == 8 || w == 127 then do - sendBelt $ Bol $ Bac () - loop rd - else if w == 13 then do - sendBelt $ Bol $ Ret () - loop rd - else if w == 3 then do - -- ETX (^C) - logInfo $ "Ctrl-c interrupt" - atomically $ do - writeTQueue wq [Term.Trace "interrupt"] - writeTQueue rq $ Mod Ctl $ Key 'c' - loop rd - else if w <= 26 then do - case BS.w2c (w + 97 - 1) of - 'd' -> atomically doneSignal - c -> do sendBelt $ Mod Ctl $ Key c - loop rd - else if w == 27 then do - loop rd { rdEscape = True } - else do - -- start the utf8 accumulation buffer - loop rd { rdUTF8 = singleton w, - rdUTF8width = if w < 224 then 2 - else if w < 240 then 3 - else 4 } - - sendBelt :: HasLogFunc e => Belt -> RIO e () - sendBelt b = do - -- logDebug $ displayShow ("terminalBelt", b) - atomically $ writeTQueue rq b - - --------------------------------------------------------------------------------- - -{-| - Terminal Driver - - Until blew/hail events succeeds, ignore effects. - Wait until blew/hail event callbacks invoked. - If success, signal success. - If failure, try again several times. - If still failure, bring down ship. - Don't wait for other drivers to boot - Begin normal operation (start accepting requests) --} -term' - :: HasPierEnv e - => (TermSize, Client) - -> IO RenderedStat - -> IO () - -> RIO e ([Ev], RAcquire e (DriverApi TermEf)) -term' (tsize, client) stat serfSIGINT = do - let TermSize wi hi = tsize - initEv = [blewEvent wi hi, initialHail] - - pure (initEv, runDriver) - where - runDriver = do - env <- ask - ventQ :: TQueue EvErr <- newTQueueIO - diOnEffect <- term env (tsize, client) (writeTQueue ventQ) stat serfSIGINT - - let diEventSource = fmap RRWork <$> tryReadTQueue ventQ - - pure (DriverApi {..}) - -{-| - Terminal Driver --} -term :: forall e. (HasPierEnv e) - => e - -> (TermSize, Client) - -> (EvErr -> STM ()) - -> IO RenderedStat - -> IO () - -> RAcquire e (TermEf -> IO ()) -term env (tsize, Client{..}) plan stat serfSIGINT = runTerm - where - runTerm :: RAcquire e (TermEf -> IO ()) - runTerm = do - tim <- mkRAcquire (async readLoop) cancel - pure (runRIO env . handleEffect) - - {- - Because our terminals are always `Demux`ed, we don't have to - care about disconnections. - -} - readLoop :: RIO e () - readLoop = forever $ do - atomically take >>= \case - Nothing -> pure () - Just (ClientTakeBelt b) -> do - when (b == Mod Ctl (Key 'c')) $ do - io serfSIGINT - let beltEv = EvBlip $ BlipEvTerm $ TermEvBelt (UD 1, ()) $ b - let beltFailed _ = pure () - atomically $ plan (EvErr beltEv beltFailed) - Just (ClientTakeSize ts@(TermSize w h)) -> do - let blewFailed _ = pure () - atomically $ plan (EvErr (blewEvent w h) blewFailed) - - handleEffect :: TermEf -> RIO e () - handleEffect = \case - TermEfInit _ _ -> pure () - TermEfMass _ _ -> pure () - TermEfLogo _ _ -> atomically =<< view killPierActionL - TermEfBlit _ blits -> do - let (termBlits, fsWrites) = partition isTerminalBlit blits - atomically $ give [Term.Blits termBlits] - for_ fsWrites handleFsWrite - - handleFsWrite :: Blit -> RIO e () - handleFsWrite (Sag path noun) = performPut path (jamBS noun) - handleFsWrite (Sav path atom) = performPut path (atomBytes atom) - handleFsWrite _ = pure () - - performPut :: Path -> ByteString -> RIO e () - performPut path bs = do - pierPath <- view pierPathL - let putOutFile = pierPath ".urb" "put" (pathToFilePath path) - createDirectoryIfMissing True (takeDirectory putOutFile) - writeFile putOutFile bs diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Term/API.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Term/API.hs deleted file mode 100644 index d6b6fde60..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Term/API.hs +++ /dev/null @@ -1,80 +0,0 @@ -{-| - Interface Terminal API. --} -module Urbit.Vere.Term.API (Ev(..), - Client(..), - ClientTake(..), - trace, - slog, - spin, - stopSpin) where - -import Urbit.Prelude hiding (trace) - -import Urbit.Arvo (Belt, Blit) - -import Control.Monad.Fail (fail) -import Urbit.TermSize - --- External Types -------------------------------------------------------------- - -{-| - Input Event for terminal driver: - - %blits -- list of blits from arvo. - %trace -- stderr line from runtime (without trailing newline). - %slog -- nock worker logging with priority - %blank -- print a blank line - %spinr -- Start or stop the spinner --} -data Ev = Blits ![Blit] - | Trace !Cord - | Slog !(Atom, Tank) - | Blank - | Spinr !(Maybe (Maybe Cord)) - deriving (Show) - -data ClientTake - = ClientTakeBelt Belt - | ClientTakeSize TermSize - deriving (Show) - -instance ToNoun ClientTake where - toNoun = \case - ClientTakeBelt b -> toNoun $ (Cord "belt", b) - ClientTakeSize (TermSize w h) -> toNoun $ (Cord "size", (w, h)) - -instance FromNoun ClientTake where - parseNoun n = named "ClientTake" $ do - (Cord name, rest) <- parseNoun n - case name of - "belt" -> do - b <- parseNoun rest - pure (ClientTakeBelt b) - "size" -> do - (w, h) <- parseNoun rest - pure (ClientTakeSize (TermSize w h)) - _ -> fail "weird client take" - - -data Client = Client - { take :: STM (Maybe ClientTake) - , give :: [Ev] -> STM () - } - -deriveNoun ''Ev - - --- Utilities ------------------------------------------------------------------- - -trace :: Client -> Text -> STM () -trace ts = give ts . singleton . Trace . Cord - -slog :: Client -> (Atom, Tank) -> STM () -slog ts = give ts . singleton . Slog - -spin :: Client -> Maybe Text -> STM () -spin ts = give ts . singleton . Spinr . Just . fmap Cord - -stopSpin :: Client -> STM () -stopSpin ts = give ts [Spinr Nothing] diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Demux.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Demux.hs deleted file mode 100644 index e9e774867..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Demux.hs +++ /dev/null @@ -1,132 +0,0 @@ -{-| - This allows multiple (zero or more) terminal clients to connect to - the *same* logical arvo terminal. Terminals that connect will be - given full event history since the creation of the demuxer. --} - -module Urbit.Vere.Term.Demux (Demux, - mkDemux, - addDemux, - useDemux, - curDemuxSize) where - -import Urbit.Prelude -import Urbit.TermSize -import Urbit.Vere.Term.API (Client(Client), ClientTake(..)) - -import qualified Urbit.Vere.Term.API as Term -import qualified Urbit.Vere.Term.Logic as Logic - - --- External -------------------------------------------------------------------- - -data KeyedSet a = KeyedSet - { _ksTable :: IntMap a - , _nextKey :: Int - } - -instance Semigroup (KeyedSet a) where - KeyedSet t1 k1 <> KeyedSet t2 k2 = KeyedSet (t1 <> t2) (max k1 k2) - -instance Monoid (KeyedSet a) where - mempty = KeyedSet mempty 0 - -ksInsertKey :: a -> KeyedSet a -> (Int, KeyedSet a) -ksInsertKey x (KeyedSet tbl nex) = - (nex, KeyedSet (insertMap nex x tbl) (succ nex)) - -ksInsert :: a -> KeyedSet a -> KeyedSet a -ksInsert x s = snd $ ksInsertKey x s - -ksDelete :: Int -> KeyedSet a -> KeyedSet a -ksDelete k (KeyedSet t n) = KeyedSet (deleteMap k t) n - --------------------------------------------------------------------------------- - -data Demux = Demux - { dConns :: TVar (KeyedSet Client) - , dSizes :: TVar (IntMap TermSize) - , dStash :: TVar Logic.St - , dMinSize :: TVar TermSize - } - -mkDemux :: TermSize -> STM Demux -mkDemux ts = Demux <$> - newTVar mempty <*> - newTVar mempty <*> - newTVar Logic.init <*> - newTVar ts - -addDemux :: Client -> Demux -> STM () -addDemux conn Demux{..} = do - modifyTVar' dConns (ksInsert conn) - stash <- readTVar dStash - Term.give conn (Logic.toTermEv <$> Logic.drawState stash) - -useDemux :: Demux -> Client -useDemux d = Client { give = dGive d, take = dTake d } - -curDemuxSize :: Demux -> STM TermSize -curDemuxSize Demux{..} = readTVar dMinSize - --- Internal -------------------------------------------------------------------- - -steps :: [Term.Ev] -> Logic.St -> Logic.St -steps termEvs st = foldl' Logic.step st $ concat $ Logic.fromTermEv <$> termEvs - -dGive :: Demux -> [Term.Ev] -> STM () -dGive Demux{..} evs = do - modifyTVar' dStash (force $ steps evs) - conns <- readTVar dConns - for_ (_ksTable conns) $ \c -> Term.give c evs - -{-| - Returns Nothing if any connected client disconnected. A `Demux` - terminal lives forever, so you can continue to call this after it - returns `Nothing`. - - If there are no attached clients, this will not return until one - is attached. --} -dTake :: Demux -> STM (Maybe ClientTake) -dTake Demux{..} = do - conns <- readTVar dConns - waitForTake conns >>= \case - (_, Just (ClientTakeBelt b)) -> pure (Just (ClientTakeBelt b)) - - (k, Just (ClientTakeSize s)) -> do - newSizeTree <- modifyAndReadTVar' dSizes (insertMap k s) - maybeUpdateTerminalSize newSizeTree - - (k, Nothing) -> do - writeTVar dConns (ksDelete k conns) - newSizeTree <- modifyAndReadTVar' dSizes (deleteMap k) - maybeUpdateTerminalSize newSizeTree - - where - waitForTake :: KeyedSet Client -> STM (Int, Maybe ClientTake) - waitForTake ks = asum - $ fmap (\(k,c) -> (k,) <$> Term.take c) - $ mapToList - $ _ksTable ks - - maybeUpdateTerminalSize :: IntMap TermSize -> STM (Maybe ClientTake) - maybeUpdateTerminalSize newSizeTree = do - let termSize = foldr minTermSize (TermSize 1024 1024) newSizeTree - curSize <- readTVar dMinSize - if curSize == termSize - then pure Nothing - else do - writeTVar dMinSize termSize - pure $ Just (ClientTakeSize termSize) - - modifyAndReadTVar' :: TVar a -> (a -> a) -> STM a - modifyAndReadTVar' var fun = do - pre <- readTVar var - let !post = fun pre - writeTVar var post - pure post - - minTermSize :: TermSize -> TermSize -> TermSize - minTermSize (TermSize wa ha) (TermSize wb hb) = - TermSize (min wa wb) (min ha hb) diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Logic.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Logic.hs deleted file mode 100644 index 748b3fa5a..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Logic.hs +++ /dev/null @@ -1,164 +0,0 @@ -{-| - Tracks terminal state so that new terminal connections can be brought - up to speed. --} -module Urbit.Vere.Term.Logic - ( SpinnerCause(..), St, Ev(..), Ef(..) - , init - , step - , drawState - , fromTermEv - , toTermEv - ) where - -import Urbit.Prelude hiding (init) - -import Data.Sequence (Seq((:<|))) - -import qualified Urbit.Arvo as Arvo -import qualified Urbit.Vere.Term.API as Term - - --------------------------------------------------------------------------------- - -data SpinnerCause = User | Event Text - deriving (Show) - -type SpinnerState = Maybe SpinnerCause - -{-| - %line -- Output a line above the edit line. - %spin -- Set the spinner state. - %bell -- Ring a bell (no change to the state). - %draw -- Redraw the current line (no change to the state). - %move -- Move the cursor position. - %edit -- Set the edit line, moving the cursor to the end. - %more -- Write the edit line to history, and clear it. --} -data Ev - = EvLine Text - | EvSlog (Atom, Tank) - | EvSpin SpinnerState - | EvMove (Word, Word) - | EvBell - | EvDraw - | EvEdit Text - | EvNewl - deriving (Show) - -data Ef - = EfClear - | EfWrite Text - | EfShift Int - | EfRing - | EfSpin SpinnerState - deriving (Show) - -data History - = HistoryText !Text - | HistorySlog !(Atom, Tank) - deriving (Show) - -data St = St - { sHistory :: !(Seq History) - , sLine :: !Text - , sCurPos :: !(Word, Word) - , sSpinner :: !SpinnerState - } - deriving (Show) - --------------------------------------------------------------------------------- - -init :: St -init = St mempty "" (0, 0) Nothing - -{-| - When we process `EvNewl`, we need to append a newline to the end of - the current line. During normal play, the ENTER key inserts the - newline for us, so we need to recreate that newline when we rebuild - the state for a new terminal connection. --} -step :: St -> Ev -> St -step st@St{..} = \case - EvLine t -> st & recordText t - EvSlog s -> st & recordSlog s - EvSpin s -> st { sSpinner = s } - EvMove p -> st { sCurPos = p } - EvBell -> st - EvDraw -> st - EvEdit t | (0, _) <- sCurPos -> st { sLine = t } - | otherwise -> st - EvNewl | (0, _) <- sCurPos -> - st { sLine = "", sCurPos = (0, 0) } - & recordText (sLine <> "\n") - | otherwise -> - st { sCurPos = (fst sCurPos - 1, 0) } - where - recordText :: Text -> St -> St - recordText !t st@St{..} = st { - sHistory = trim (sHistory |> (HistoryText t)) - } - - recordSlog :: (Atom, Tank) -> St -> St - recordSlog !t st@St{..} = st { - sHistory = trim (sHistory |> (HistorySlog t)) - } - - trim :: Seq a -> Seq a - trim s | length s < 20 = s - trim (_ :<| s) = s - trim s = s - -drawState :: St -> [Ev] -drawState St{..} = hist <> out <> cur <> spin - where - hist = drawHistory <$> toList sHistory - out | null sLine = [] - | otherwise = [EvEdit sLine] - cur | (0, _) <- sCurPos = [] - | otherwise = [EvMove sCurPos] - spin = maybe [] (singleton . EvSpin . Just) sSpinner - - drawHistory (HistoryText t) = EvLine t - drawHistory (HistorySlog s) = EvSlog s - - --- Conversion ------------------------------------------------------------------ - -fromBlit :: Arvo.Blit -> Maybe Ev -fromBlit = \case - Arvo.Hop (Arvo.Col c) -> Just $ EvMove (0, fromIntegral c) - Arvo.Hop (Arvo.Roc r c) -> Just $ EvMove (fromIntegral r, fromIntegral c) - Arvo.Bel () -> Just EvBell - Arvo.Clr () -> Just EvDraw - Arvo.Put s -> Just $ EvEdit (pack s) - Arvo.Nel () -> Just EvNewl - _ -> Nothing - -toCause :: Maybe Cord -> SpinnerCause -toCause Nothing = User -toCause (Just (Cord c)) = Event c - -fromCause :: SpinnerCause -> Maybe Cord -fromCause User = Nothing -fromCause (Event t) = Just (Cord t) - -fromTermEv :: Term.Ev -> [Ev] -fromTermEv = \case - Term.Blits bs -> catMaybes (fromBlit <$> bs) - Term.Trace t -> [EvLine $ unCord t] - Term.Blank -> [EvLine ""] - Term.Spinr s -> [EvSpin $ toCause <$> s] - Term.Slog s -> [EvSlog s] - -toTermEv :: Ev -> Term.Ev -toTermEv = \case - EvLine "" -> Term.Blank - EvLine t -> Term.Trace (Cord t) - EvSlog s -> Term.Slog s - EvSpin s -> Term.Spinr (fromCause <$> s) - EvMove (r, c) -> Term.Blits [Arvo.Hop $ Arvo.Roc (fromIntegral r) (fromIntegral c)] - EvBell -> Term.Blits [Arvo.Bel ()] - EvDraw -> Term.Blits [Arvo.Clr ()] - EvEdit t -> Term.Blits [Arvo.Put $ unpack t] - EvNewl -> Term.Blits [Arvo.Nel ()] diff --git a/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Render.hs b/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Render.hs deleted file mode 100644 index 829003259..000000000 --- a/pkg/hs/urbit-king/lib/Urbit/Vere/Term/Render.hs +++ /dev/null @@ -1,54 +0,0 @@ -{-| - Terminal Driver --} -module Urbit.Vere.Term.Render - ( clearScreen - , clearLine - , soundBell - , cursorMove - , cursorSave - , cursorRestore - , putCsi - , hijack - ) where - -import Urbit.Prelude - -import qualified System.Console.ANSI as ANSI - - --- Types ----------------------------------------------------------------------- - -clearScreen :: MonadIO m => m () -clearScreen = liftIO $ ANSI.clearScreen - -clearLine :: MonadIO m => m () -clearLine = liftIO $ ANSI.clearLine - -soundBell :: MonadIO m => m () -soundBell = liftIO $ putStr "\a" - ---NOTE top-left-0-based coordinates -cursorMove :: MonadIO m => Int -> Int -> m () -cursorMove r c = liftIO $ ANSI.setCursorPosition r c - -cursorSave :: MonadIO m => m () -cursorSave = liftIO ANSI.saveCursor - -cursorRestore :: MonadIO m => m () -cursorRestore = liftIO ANSI.restoreCursor - -putCsi :: MonadIO m => Char -> [Int] -> m () -putCsi c a = liftIO do - putStr "\x1b[" - putStr $ pack $ mconcat $ intersperse ";" (fmap show a) - putStr $ pack [c] - -hijack :: MonadIO m => Int -> IO () -> m () -hijack h d = liftIO do - putCsi 'r' [1, h-1] -- set scroll region to exclude bottom line - putCsi 'S' [1] -- scroll up one line - cursorMove (h-2) 0 -- move cursor to empty space - d - putCsi 'r' [] -- reset scroll region - cursorRestore -- restory cursor position diff --git a/pkg/hs/urbit-king/package.yaml b/pkg/hs/urbit-king/package.yaml deleted file mode 100644 index 4e91c4ccb..000000000 --- a/pkg/hs/urbit-king/package.yaml +++ /dev/null @@ -1,184 +0,0 @@ -name: urbit-king -version: 1.8 -license: MIT -license-file: LICENSE -data-files: - - test/gold/hoontree.gold - - test/gold/hoontree.pill - -library: - source-dirs: lib - ghc-options: - - -Wall - - -Werror - - -Wno-type-defaults - - -Wno-unused-matches - - -Wno-name-shadowing - - -Wno-unused-do-bind - - -O2 - -tests: - urbit-king-tests: - source-dirs: test - main: Main.hs - dependencies: urbit-king - ghc-options: - - -threaded - - -rtsopts - - -with-rtsopts=-N - -dependencies: - - aeson - - ansi-terminal - - async - - base - - base-unicode-symbols - - binary - - bytestring - - case-insensitive - - cereal - - classy-prelude - - conduit - - containers - - cryptohash-sha256 - - cryptohash-sha512 - - data-default - - data-fix - - directory - - ed25519 - - entropy - - exceptions - - extra - - filepath - - fixed-vector - - flat - - ghc-prim - - Glob - - hashable - - hashtables - - heap - - hexstring - - http-client - - http-client-tls - - http-types - - integer-gmp - - iproute - - largeword - - lens - - lock-file - - megaparsec - - memory - - mtl - - multimap - - murmur3 - - natpmp-static - - network - - optparse-applicative - - para - - pem - - pretty-show - - primitive - - process - - psqueues - - QuickCheck - - racquire - - random - - regex-tdfa - - resourcet - - rio - - rio-orphans - - semigroups - - smallcheck - - stm - - stm-chans - - tasty - - tasty-golden - - tasty-hunit - - tasty-quickcheck - - tasty-th - - template-haskell - - terminal-progress-bar - - text - - these - - time - - tls - - transformers - - unix - - unliftio - - unliftio-core - - unordered-containers - - urbit-atom - - urbit-eventlog-lmdb - - urbit-hob - - urbit-noun - - urbit-noun-core - - urbit-termsize - - utf8-string - - vector - - wai - - wai-conduit - - wai-websockets - - warp - - warp-tls - - websockets - -default-extensions: - - ApplicativeDo - - BangPatterns - - BinaryLiterals - - BlockArguments - - ConstraintKinds - - DataKinds - - DefaultSignatures - - DeriveAnyClass - - DeriveDataTypeable - - DeriveFoldable - - DeriveGeneric - - DeriveTraversable - - DerivingStrategies - - EmptyCase - - EmptyDataDecls - - FlexibleContexts - - FlexibleInstances - - FunctionalDependencies - - GADTs - - GeneralizedNewtypeDeriving - - LambdaCase - - MagicHash - - MultiParamTypeClasses - - NamedFieldPuns - - NoImplicitPrelude - - NumericUnderscores - - OverloadedStrings - - PackageImports - - PartialTypeSignatures - - PatternGuards - - PatternSynonyms - - QuasiQuotes - - Rank2Types - - RankNTypes - - RecordWildCards - - ScopedTypeVariables - - StandaloneDeriving - - TemplateHaskell - - TupleSections - - TypeApplications - - TypeFamilies - - TypeOperators - - UnboxedTuples - - UnicodeSyntax - - ViewPatterns - -executables: - urbit-king: - main: Main.hs - source-dirs: app - dependencies: - - urbit-king - ghc-options: - - -threaded - - -rtsopts - - -static - - -O2 - - "-with-rtsopts=-N" - - -fwarn-incomplete-patterns diff --git a/pkg/hs/urbit-king/test/AmesTests.hs b/pkg/hs/urbit-king/test/AmesTests.hs deleted file mode 100644 index 11c31f5c8..000000000 --- a/pkg/hs/urbit-king/test/AmesTests.hs +++ /dev/null @@ -1,117 +0,0 @@ -module AmesTests (tests) where - -import Data.Conduit -import Data.Conduit.List hiding (take) -import Data.Ord.Unicode -import Test.QuickCheck hiding ((.&.)) -import Test.Tasty -import Test.Tasty.QuickCheck -import Test.Tasty.TH -import Urbit.Arvo -import Urbit.EventLog.LMDB -import Urbit.King.Config -import Urbit.Noun -import Urbit.Noun.Time -import Urbit.Prelude hiding (elements) -import Urbit.Vere.Ames -import Urbit.Vere.Ames.Packet -import Urbit.Vere.Pier.Types -import Urbit.Vere.Ports - -import Control.Concurrent (runInBoundThread) -import Data.Serialize (decode, encode) -import Data.LargeWord (LargeKey(..)) -import GHC.Natural (Natural) -import Network.Socket (tupleToHostAddress) -import Urbit.King.App (HasKingId(..)) - -import qualified Urbit.EventLog.LMDB as Log -import qualified Urbit.Noun.Time as Time - -packetSplitMorphism :: Packet -> Bool -packetSplitMorphism p = (decode . encode) p == Right p - -tests :: TestTree -tests = - testGroup "Ames" - [ testProperty "Packet coding looks good" $ - packetSplitMorphism - ] - - --- Generate Arbitrary Values --------------------------------------------------- - -arb :: Arbitrary a => Gen a -arb = arbitrary - -instance Arbitrary Ipv4 where arbitrary = Ipv4 <$> arb -instance Arbitrary Port where arbitrary = Port <$> arb -instance Arbitrary Wen where arbitrary = Wen <$> arb -instance Arbitrary Gap where arbitrary = Gap . abs <$> arb -instance Arbitrary Bytes where arbitrary = pure (MkBytes "wtfbbq") - -- MkBytes . take 100 <$> arb - -instance Arbitrary a => Arbitrary (Patp a) where - arbitrary = Patp <$> arb - -instance Arbitrary ByteString where - arbitrary = pack <$> arbitrary - -instance Arbitrary Natural where - arbitrary = fromIntegral . abs <$> (arbitrary :: Gen Integer) - -instance (Arbitrary a, Arbitrary b) => Arbitrary (LargeKey a b) where - arbitrary = LargeKey <$> arb <*> arb - -genIpv4 :: Gen Ipv4 -genIpv4 = do - x <- arbitrary - if (x == 0 || (x≥256 && x≤512)) - then genIpv4 - else pure (Ipv4 x) - -instance Arbitrary Text where - arbitrary = pack <$> arb - -instance Arbitrary Cord where - arbitrary = Cord <$> arb - -instance Arbitrary BigCord where - arbitrary = BigCord <$> arb - -instance Arbitrary AmesDest where - arbitrary = oneof [ EachYes <$> arb - , EachNo <$> arb - ] - -instance Arbitrary a => Arbitrary (Jammed a) where - arbitrary = Jammed <$> arbitrary - -instance Arbitrary AmesAddress where - arbitrary = AAIpv4 <$> arb <*> arb - -instance Arbitrary Ship where - arbitrary = Ship <$> elements - [ 0 - , 42 - , 256 - , 24_530 - , 2_071_856_128 - , 2_824_325_100 - , 430_648_908_188_615_680 - , 2^60 + 1337 - ] - -instance Arbitrary LogIdentity where - arbitrary = LogIdentity <$> arb <*> arb <*> arb - -instance Arbitrary Packet where - arbitrary = do - pktVersion <- suchThat arb (< 8) - pktSndr <- arb - pktRcvr <- arb - pktSndrTick <- suchThat arb (< 16) - pktRcvrTick <- suchThat arb (< 16) - pktOrigin <- arb - pktContent <- arb - pure Packet {..} diff --git a/pkg/hs/urbit-king/test/ArvoTests.hs b/pkg/hs/urbit-king/test/ArvoTests.hs deleted file mode 100644 index 5ac04c1d5..000000000 --- a/pkg/hs/urbit-king/test/ArvoTests.hs +++ /dev/null @@ -1,150 +0,0 @@ -module ArvoTests (tests) where - -import Data.Acquire -import Data.Conduit -import Data.Conduit.List -import Data.Ord.Unicode -import Network.HTTP.Types.Method -import Test.QuickCheck hiding ((.&.)) -import Test.Tasty -import Test.Tasty.QuickCheck -import Test.Tasty.TH -import Urbit.Arvo -import Urbit.EventLog.LMDB -import Urbit.Noun.Time -import Urbit.Prelude -import Urbit.Vere.Pier.Types - -import System.IO.Unsafe -import Data.Serialize - -import Control.Concurrent (runInBoundThread, threadDelay) -import Data.LargeWord (LargeKey(..)) -import GHC.Natural (Natural) -import Network.Socket (tupleToHostAddress) - -import qualified Urbit.EventLog.LMDB as Log - - --- Utils ----------------------------------------------------------------------- - -roundTrip :: forall a. (Eq a, ToNoun a, FromNoun a) => a -> Bool -roundTrip x = Just x == fromNoun (toNoun x) - -nounEq :: (ToNoun a, ToNoun b) => a -> b -> Bool -nounEq x y = toNoun x == toNoun y - --------------------------------------------------------------------------------- - -tests :: TestTree -tests = - testGroup "Arvo Events and Effects" - [ testProperty "Round Trip Effect" (roundTrip @Ef) - , testProperty "Round Trip Event" (roundTrip @Ev) - , testProperty "Round Trip AmesDest" (roundTrip @AmesDest) - ] - - --- Arbitrary Instances --------------------------------------------------------- - -instance Arbitrary Natural where - arbitrary = (fromIntegral . abs @Integer) <$> arb - -newtype DumbChar = Dumb { unDumb :: Char } - -instance Arbitrary DumbChar where - arbitrary = Dumb <$> choose ('a', 'z') - -instance Arbitrary Text where - arbitrary = pack . fmap unDumb <$> arbitrary - -instance (Arbitrary a, Arbitrary b) => Arbitrary (LargeKey a b) where - arbitrary = LargeKey <$> arb <*> arb - -instance Arbitrary ByteString where - arbitrary = encodeUtf8 <$> arbitrary - -instance Arbitrary EvilPath where arbitrary = EvilPath <$> arb -instance Arbitrary Path where arbitrary = Path <$> arb -instance Arbitrary Knot where arbitrary = MkKnot <$> arb -instance Arbitrary Tape where arbitrary = Tape <$> arb -instance Arbitrary BigTape where arbitrary = BigTape <$> arb -instance Arbitrary Bytes where arbitrary = MkBytes <$> arb -instance Arbitrary Octs where arbitrary = Octs <$> arb -instance Arbitrary File where arbitrary = File <$> arb -instance Arbitrary Cord where arbitrary = Cord <$> arb -instance Arbitrary Wen where arbitrary = Wen <$> arb -instance Arbitrary Gap where arbitrary = Gap . abs <$> arb -instance Arbitrary Port where arbitrary = Port <$> arb -instance Arbitrary Ship where arbitrary = Ship <$> arb -instance Arbitrary Address where arbitrary = AAmes <$> arb - -instance Arbitrary a => Arbitrary (Patp a) where - arbitrary = Patp <$> arb - -genIpv4 :: Gen Ipv4 -genIpv4 = do - x <- arbitrary - if (x == 0 || (x≥256 && x≤512)) - then genIpv4 - else pure (Ipv4 x) - -instance (Arbitrary a, Arbitrary b) => Arbitrary (Each a b) where - arbitrary = oneof [ EachNo <$> arb, EachYes <$> arb ] - -instance (Arbitrary a) => Arbitrary (Jammed a) where - arbitrary = Jammed <$> arbitrary - -instance Arbitrary Ef where - arbitrary = oneof [ EfVega <$> arb <*> arb - ] - -instance Arbitrary AmesEv where - arbitrary = oneof [ AmesEvHear () <$> arb <*> arb - , AmesEvHole () <$> arb <*> arb - ] - -instance Arbitrary HttpRequest where - arbitrary = HttpRequest <$> arb <*> arb <*> arb <*> arb - -instance Arbitrary HttpServerReq where - arbitrary = HttpServerReq <$> arb <*> arb <*> arb - -instance Arbitrary HttpServerEv where - arbitrary = oneof [ HttpServerEvRequest <$> arb <*> arb - , HttpServerEvLive <$> arb <*> arb <*> arb - ] - -instance Arbitrary BlipEv where - arbitrary = oneof [ BlipEvAmes <$> arb - , BlipEvHttpServer <$> arb - ] - -instance Arbitrary Ev where - arbitrary = oneof [ EvBlip <$> arb - ] - -instance Arbitrary StdMethod where - arbitrary = oneof $ pure <$> [ minBound .. maxBound ] - -instance Arbitrary Header where - arbitrary = Header <$> arb <*> arb - -instance Arbitrary BigCord where - arbitrary = BigCord <$> arb - - -instance Arbitrary ServId where arbitrary = ServId <$> arb - -instance Arbitrary UD where arbitrary = UD <$> arb -instance Arbitrary UV where arbitrary = UV <$> arb - -instance Arbitrary AmesAddress where - arbitrary = AAIpv4 <$> arb <*> arb - -instance Arbitrary Ipv4 where arbitrary = Ipv4 <$> arb - --- Generate Arbitrary Values --------------------------------------------------- - -arb :: Arbitrary a => Gen a -arb = arbitrary diff --git a/pkg/hs/urbit-king/test/BehnTests.hs b/pkg/hs/urbit-king/test/BehnTests.hs deleted file mode 100644 index d8b18cb94..000000000 --- a/pkg/hs/urbit-king/test/BehnTests.hs +++ /dev/null @@ -1,54 +0,0 @@ -module BehnTests (tests) where - -import Data.Acquire -import Data.Conduit -import Data.Conduit.List hiding (take) -import Data.Ord.Unicode -import Test.QuickCheck hiding ((.&.)) -import Test.Tasty -import Test.Tasty.QuickCheck -import Test.Tasty.TH -import Urbit.Arvo -import Urbit.EventLog.LMDB -import Urbit.Noun -import Urbit.Noun.Time -import Urbit.Prelude -import Urbit.Vere.Behn -import Urbit.Vere.Pier.Types - -import Control.Concurrent (runInBoundThread, threadDelay) -import Data.LargeWord (LargeKey(..)) -import GHC.Natural (Natural) -import Network.Socket (tupleToHostAddress) -import Urbit.King.App (runKingEnvNoLog, HasKingId(..)) - -import qualified Urbit.EventLog.LMDB as Log -import qualified Urbit.Noun.Time as Time - - --------------------------------------------------------------------------------- - --- TODO Timers always fire immediatly. Something is wrong! -timerFires :: Property -timerFires = forAll arbitrary (ioProperty . runKingEnvNoLog . runTest) - where - runTest :: HasKingId e => () -> RIO e Bool - runTest () = do - envr <- ask - king <- fromIntegral <$> view kingIdL - q <- newTQueueIO - rwith (liftAcquire $ behn envr (writeTQueue q)) $ \cb -> do - io $ cb (BehnEfDoze (king, ()) (Just (2^20))) - t <- atomically $ readTQueue q - pure True - - --- Utils ----------------------------------------------------------------------- - -tests :: TestTree -tests = - testGroup "Behn" - [ localOption (QuickCheckTests 10) $ - testProperty "Behn Timers Fire" $ - timerFires - ] diff --git a/pkg/hs/urbit-king/test/ClayTests.hs b/pkg/hs/urbit-king/test/ClayTests.hs deleted file mode 100644 index a6afc7f7e..000000000 --- a/pkg/hs/urbit-king/test/ClayTests.hs +++ /dev/null @@ -1,28 +0,0 @@ -module ClayTests (tests) where - -import Urbit.Noun.Conversions -import Urbit.Prelude - -import Test.QuickCheck hiding ((.&.)) -import Test.Tasty -import Test.Tasty.QuickCheck -import Test.Tasty.TH - -instance Arbitrary Knot where - arbitrary = (MkKnot . pack) <$> sublistOf ['a'..'z'] - -nonEmptyList :: (Arbitrary a) => Gen [a] -nonEmptyList = sized $ \n -> - do k <- choose (1, max 1 n) - vector k - -instance Arbitrary Path where - arbitrary = Path <$> nonEmptyList - -testPathRoundTrip :: Path -> Property -testPathRoundTrip p = - classify (1 == (length $ unPath p)) "singleton" $ - (filePathToPath (pathToFilePath p)) === p - -tests = testGroup "Clay" - [ testProperty "Path round trip" $ testPathRoundTrip ] diff --git a/pkg/hs/urbit-king/test/DawnTests.hs b/pkg/hs/urbit-king/test/DawnTests.hs deleted file mode 100644 index eb8d8e201..000000000 --- a/pkg/hs/urbit-king/test/DawnTests.hs +++ /dev/null @@ -1,88 +0,0 @@ -module DawnTests (tests) where - -import Urbit.Arvo.Event -import Urbit.Noun.Conversions -import Urbit.Prelude - -import Test.Tasty -import Test.Tasty.HUnit - -import qualified Urbit.Ob as Ob -import qualified Urbit.Vere.Dawn as Dawn - --------------------------------------------------------------------------------- - --- These golden cases generated in Urbit from entropy to make sure our +mix, --- +shas, +shaf, etc. were actually calculated correctly. - -cordToAtomBytes :: Text -> ByteString -cordToAtomBytes = atomBytes . cordToAtom - -cordToAtom :: Text -> Atom -cordToAtom t = case cordToUW (Cord t) of - Nothing -> error "Couldn't parse constant embedded in file." - Just (UW a) -> a - -testString = cordToAtomBytes $ concat - [ "0w1.XqnKc.onYJK.0zVOU.Uw142.jNx3C.oWV83.TYt6T.kmHUg.cnoq1.zla6B.bKeNa" - , ".8wUZu.6ZLHJ.c1TKV.KPcb3.9lU3~.p2G8D" - ] - -testSalt = cordToAtomBytes "0wc.~cOwa.Kb-DI.BrjVW.i0U37" - -mixByteStrings = (Dawn.mix testSalt testString) @?= expected - where - expected = cordToAtomBytes $ concat - [ "0w1.XqnKc.onYJK.0zVOU.Uw142.jNx3C.oWV83.TYt6T.kmHUg.cnoq1.zla6B.bKeNa" - , ".8wUZu.6ZLHx.Pd5eP.0UOIL.IeHW5.b2ibw" - ] - -shasByteStrings = (Dawn.shas testSalt testString) @?= expected - where - expected = cordToAtomBytes - "0wfKW.mXzrj.c~IBb.lKd6k.2njoG.bRLcD.9eszA.gSSs8.mHRah" - -shafByteStrings = (Dawn.shaf testSalt testString) @?= expected - where - expected = cordToAtomBytes "0w3h.Bg1Qh.ZZjoJ.23J~p.PHg-D" - --------------------------------------------------------------------------------- - -cometShip :: Ship -cometShip = case Ob.parsePatp cometStr of - Left x -> error "Invalid ship name" - Right p -> Ship $ fromIntegral $ Ob.fromPatp p - where - cometStr = "~radmes-dilsec-sovlup-lagwep--tonred-waldeb-tocseg-marzod" - -cometPass :: Pass -cometPass = case fromNoun (Atom cometPassAtom) of - Nothing -> error "Keyfile does not seem to contain a seed." - Just s -> s - where - cometPassAtom = cordToAtom $ concat - [ "0w99.P80w4.rL7Qt.0i5-h.8yta7.RhgHI.nrXjO.xBCix.Pxx5a.sJ6bv.a-Iwo.OeVBr" - , ".x8-Gs.1LLG~.FgDRk.GML3Y.X3qFZ.jtlpy" - ] - -cometRawBS = cordToAtomBytes "0w39.q35g-.hrd3f.q9UWK.Zxg40" - --- Verifies the internal usage of +shaf in comet derivation gets the right --- answer. -testCometFingerprintBS = (Dawn.cometFingerprintBS cometPass) @?= cometRawBS - --- Tests that the real public interface for fingerprint generation does the --- byte-munging correctly. -testCometFingerprint = (Dawn.cometFingerprint cometPass) @?= cometShip - --------------------------------------------------------------------------------- - -tests :: TestTree -tests = - testGroup "Dawn" - [ testCase "Mix bytestrings of different length" $ mixByteStrings - , testCase "Shas bytestrings" $ shasByteStrings - , testCase "Shaf bytestrings" $ shafByteStrings - , testCase "Fingerprint bytestring derivation" $ testCometFingerprintBS - , testCase "Fingerprint total derivation" $ testCometFingerprint - ] diff --git a/pkg/hs/urbit-king/test/DeriveNounTests.hs b/pkg/hs/urbit-king/test/DeriveNounTests.hs deleted file mode 100644 index d883d29fa..000000000 --- a/pkg/hs/urbit-king/test/DeriveNounTests.hs +++ /dev/null @@ -1,183 +0,0 @@ -module DeriveNounTests (tests) where - -import Data.Acquire -import Data.Conduit -import Data.Conduit.List -import Test.QuickCheck hiding ((.&.)) -import Test.Tasty -import Test.Tasty.QuickCheck -import Test.Tasty.TH -import Urbit.EventLog.LMDB -import Urbit.Prelude -import Urbit.Vere.Pier.Types - -import Control.Concurrent (runInBoundThread, threadDelay) -import Data.LargeWord (LargeKey(..)) -import GHC.Natural (Natural) - -import qualified Urbit.EventLog.LMDB as Log - - --- Sum Types ------------------------------------------------------------------- - -data Nums = One | Two | TwentyTwo | NineHundredNintyNine - deriving (Eq, Show, Enum, Bounded) - -data ThreeWords = ThreeWords Word Word Word - deriving (Eq, Show) - -data FooBar = FooBarQueenAlice Word Word - | FooBarBob Word - | FooBarCharlie - deriving (Eq, Show) - -data BarZaz = BZQueenAlice Word Word - | BZBob Word - | BZCharlie - deriving (Eq, Show) - -data ZazBaz = QueenAlice Word Word - | Bob Word - | Charlie - deriving (Eq, Show) - -data Empty - -data Poly a b = PLeft a - | PRite b - deriving (Eq, Show) - -deriveNoun ''Nums -deriveNoun ''ThreeWords -deriveNoun ''FooBar -deriveNoun ''BarZaz -deriveNoun ''ZazBaz -deriveNoun ''Empty -deriveNoun ''Poly - -instance Arbitrary ThreeWords where - arbitrary = ThreeWords <$> arbitrary <*> arbitrary <*> arbitrary - -instance Arbitrary Nums where - arbitrary = oneof (pure <$> [ minBound .. maxBound ]) - -instance Arbitrary FooBar where - arbitrary = oneof [ FooBarQueenAlice <$> arbitrary <*> arbitrary - , FooBarBob <$> arbitrary - , pure FooBarCharlie - ] - -instance Arbitrary BarZaz where - arbitrary = oneof [ BZQueenAlice <$> arbitrary <*> arbitrary - , BZBob <$> arbitrary - , pure BZCharlie - ] - -instance Arbitrary ZazBaz where - arbitrary = oneof [ QueenAlice <$> arbitrary <*> arbitrary - , Bob <$> arbitrary - , pure Charlie - ] - -instance (Arbitrary a, Arbitrary b) => Arbitrary (Poly a b) where - arbitrary = oneof [ PLeft <$> arbitrary - , PRite <$> arbitrary - ] - - --- Utils ----------------------------------------------------------------------- - -roundTrip :: forall a. (Eq a, ToNoun a, FromNoun a) => a -> Bool -roundTrip x = Just x == fromNoun (toNoun x) - -throughNoun :: (ToNoun a, FromNoun b) => a -> Maybe b -throughNoun = fromNoun . toNoun - -nounEquiv :: (Eq a, Eq b, ToNoun a, ToNoun b, FromNoun a, FromNoun b) - => (a -> b) -> a -> Bool -nounEquiv cvt x = - and [ Just x == throughNoun y - , Just y == throughNoun x - ] - where y = cvt x - - --- Sanity Checks --------------------------------------------------------------- - -enumSanity :: Nums -> Bool -enumSanity x = toNoun x == byHand x - where - byHand = \case - One -> toNoun (Cord "one") - Two -> toNoun (Cord "two") - TwentyTwo -> toNoun (Cord "twenty-two") - NineHundredNintyNine -> toNoun (Cord "nine-hundred-ninty-nine") - -recSanity :: ThreeWords -> Bool -recSanity x = toNoun x == byHand x - where - byHand (ThreeWords x y z) = toNoun (x, y, z) - -sumSanity :: ZazBaz -> Bool -sumSanity x = toNoun x == byHand x - where - byHand = \case - QueenAlice x y -> toNoun (Cord "queen-alice", x, y) - Bob x -> toNoun (Cord "bob", x) - Charlie -> toNoun (Cord "charlie") - -abbrPrefixSanity :: BarZaz -> Bool -abbrPrefixSanity x = toNoun x == byHand x - where - byHand = \case - BZQueenAlice x y -> toNoun (Cord "queen-alice", x, y) - BZBob x -> toNoun (Cord "bob", x) - BZCharlie -> toNoun (Cord "charlie") - -typePrefixSanity :: FooBar -> Bool -typePrefixSanity x = toNoun x == byHand x - where - byHand = \case - FooBarQueenAlice x y -> toNoun (Cord "queen-alice", x, y) - FooBarBob x -> toNoun (Cord "bob", x) - FooBarCharlie -> toNoun (Cord "charlie") - - --- Strip Sum Prefixes ---------------------------------------------------------- - -barZazBaz :: BarZaz -> Bool -barZazBaz = nounEquiv $ \case BZQueenAlice x y -> QueenAlice x y - BZBob x -> Bob x - BZCharlie -> Charlie - -fooBarBaz :: FooBar -> Bool -fooBarBaz = nounEquiv $ \case FooBarQueenAlice x y -> QueenAlice x y - FooBarBob x -> Bob x - FooBarCharlie -> Charlie - - --------------------------------------------------------------------------------- - -tests :: TestTree -tests = - testGroup "Log" - [ testProperty "Enum Sanity" $ enumSanity - , testProperty "Sum Sanity" $ sumSanity - , testProperty "Record Sanity" $ recSanity - , testProperty "Type-Prefix Sanity" $ abbrPrefixSanity - , testProperty "Abbrv-Prefix Sanity" $ typePrefixSanity - , testProperty "Round Trip Rec (Poly)" $ roundTrip @(Poly Bool Bool) - , testProperty "Round Trip Rec (ThreeWords)" $ roundTrip @ThreeWords - , testProperty "Round Trip Enum (Nums)" $ roundTrip @Nums - , testProperty "Round Trip Sum (FooBar)" $ roundTrip @FooBar - , testProperty "Round Trip Sum (BarZaz)" $ roundTrip @BarZaz - , testProperty "Round Trip Sum (ZazBaz)" $ roundTrip @ZazBaz - , testProperty "Prefix Test 1" $ barZazBaz - , testProperty "Prefix Test 2" $ fooBarBaz - ] - - --- Generate Arbitrary Values --------------------------------------------------- - -arb :: Arbitrary a => Gen a -arb = arbitrary diff --git a/pkg/hs/urbit-king/test/HoonMapSetTests.hs b/pkg/hs/urbit-king/test/HoonMapSetTests.hs deleted file mode 100644 index 13101ab01..000000000 --- a/pkg/hs/urbit-king/test/HoonMapSetTests.hs +++ /dev/null @@ -1,135 +0,0 @@ -module HoonMapSetTests (tests) where - -import RIO.Directory -import Urbit.Prelude - -import Data.ByteString.Lazy (ByteString) -import Numeric.Natural (Natural) -import Test.QuickCheck hiding ((.&.)) -import Test.Tasty -import Test.Tasty.QuickCheck -import Test.Tasty.TH - -import qualified Data.ByteString as ByteString -import qualified Data.ByteString.Lazy as ByteString.Lazy -import qualified Data.Text.Lazy as Text.Lazy -import qualified Data.Text.Lazy.Encoding as Text.Lazy.Encoding -import qualified Paths_urbit_king -import qualified Test.Tasty.Golden as Golden -import qualified Test.Tasty.Golden.Advanced as Golden.Advanced - --- Types ----------------------------------------------------------------------- - -newtype SmallNoun = SN Noun - deriving newtype (Eq, Ord, Show, ToNoun) - -instance Arbitrary SmallNoun where - arbitrary = SN <$> oneof [a, c, ac, ca, cc] - where - a = A . fromIntegral <$> arbitrary @Word8 - c = C <$> a <*> a - ac = C <$> a <*> c - ca = C <$> c <*> a - cc = C <$> c <*> c - -data TreeTest - = TTMap (HoonMap Noun Noun) - | TTSet (HoonSet Noun) - -deriveNoun ''TreeTest - -type TreeTests = [TreeTest] - - --- Utils ----------------------------------------------------------------------- - -roundTrip :: forall a. Eq a => (a -> a) -> a -> Bool -roundTrip f x = f x == x - - --- Props ----------------------------------------------------------------------- - -mapRoundtrip :: Map SmallNoun SmallNoun -> Bool -mapRoundtrip = roundTrip (mapFromHoonMap . mapToHoonMap) - -setRoundtrip :: Set SmallNoun -> Bool -setRoundtrip = roundTrip (setFromHoonSet . setToHoonSet) - --- Golden Tests ---------------------------------------------------------------- - -treeTestsIdentity :: TreeTests -> TreeTests -treeTestsIdentity = fmap go - where - go = \case - TTSet s -> (TTSet . setToHoonSet . setFromHoonSet) s - TTMap m -> (TTMap . mapToHoonMap . mapFromHoonMap) m - -treeRTMug :: FilePath -> IO ByteString.Lazy.ByteString -treeRTMug inp = do - byt <- readFile inp - non <- cueBSExn byt - tee <- fromNounExn non - mug <- evaluate $ mug $ toNoun $ treeTestsIdentity tee - pure $ Text.Lazy.Encoding.encodeUtf8 $ tlshow mug - -goldenPill - :: TestName - -> String - -> (FilePath -> IO ByteString.Lazy.ByteString) - -> TestTree -goldenPill test name action = - goldenVsString test gold (action pill) - where - gold = "test/gold" name <.> "gold" - pill = "test/gold" name <.> "pill" - --- | Compare a given string against the golden file's contents. -goldenVsString - :: TestName - -- ^ Test name - -> String - -- ^ The «golden» file that will be retrieved via 'getDataFileName'. - -> IO ByteString.Lazy.ByteString - -- ^ Action that returns the string for comparison. - -> TestTree - -- ^ Verifies the golden file contents is identical to the returned string. -goldenVsString test name action = - askOption $ \cutoff -> - Golden.Advanced.goldenTest name acquire action (comparator cutoff) update - where - acquire = do - path <- Paths_urbit_king.getDataFileName name - bytes <- ByteString.readFile path - - pure (ByteString.Lazy.fromStrict bytes) - - comparator cutoff x y = - pure $ - if x == y - then Nothing - else Just - ( printf "Test output was different from '%s'. It was:\n" name - <> unpackUTF8 (truncate cutoff y) - ) - - unpackUTF8 = Text.Lazy.unpack . Text.Lazy.Encoding.decodeUtf8 - - truncate (Golden.SizeCutoff cutoff) bytes = - if ByteString.Lazy.length bytes <= cutoff - then bytes - else ByteString.Lazy.take cutoff bytes - <> "" - <> "\nUse --accept or increase --size-cutoff to see full output." - - -- The update function is a noop as we don't have the golden file name. - update _ = pure () - --- Test Tree ------------------------------------------------------------------- - -tests :: TestTree -tests = - testGroup "Map/Set Conversions" - [ goldenPill "Golden Map Roundtrip" "hoontree" treeRTMug - , testProperty "Map Rountrip" mapRoundtrip - , testProperty "Set Rountrip" setRoundtrip - ] diff --git a/pkg/hs/urbit-king/test/JamTests.hs b/pkg/hs/urbit-king/test/JamTests.hs deleted file mode 100644 index fd6b688fd..000000000 --- a/pkg/hs/urbit-king/test/JamTests.hs +++ /dev/null @@ -1,28 +0,0 @@ -module JamTests (tests) where - -import Urbit.Arvo.Event -import Urbit.Noun.Conversions -import Urbit.Noun.Cue -import Urbit.Noun.Jam -import Urbit.Prelude - -import GHC.Natural (Natural(..)) -import Test.QuickCheck hiding ((.&.)) -import Test.QuickCheck.Gen -import Test.QuickCheck.Random -import Test.Tasty -import Test.Tasty.QuickCheck -import Test.Tasty.TH - -instance Arbitrary Natural where - arbitrary = arbitrarySizedNatural - -prop_cueJamAtom :: Atom -> Bool -prop_cueJamAtom a = Right (Atom a) == cue (jam (Atom a)) - -prop_cueJamNoun :: Noun -> Bool -prop_cueJamNoun n = Right n == cue (jam n) - -tests :: TestTree -tests = $(testGroupGenerator) - diff --git a/pkg/hs/urbit-king/test/LogTests.hs b/pkg/hs/urbit-king/test/LogTests.hs deleted file mode 100644 index ef34e2c95..000000000 --- a/pkg/hs/urbit-king/test/LogTests.hs +++ /dev/null @@ -1,199 +0,0 @@ -module LogTests (tests) where - -import Data.Acquire -import Data.Conduit -import Data.Conduit.List hiding (filter) -import Test.QuickCheck hiding ((.&.)) -import Test.Tasty -import Test.Tasty.QuickCheck -import Test.Tasty.TH -import Urbit.EventLog.LMDB -import Urbit.Prelude -import Urbit.Vere.Pier.Types - -import Control.Concurrent (runInBoundThread, threadDelay) -import Data.LargeWord (LargeKey(..)) -import GHC.Natural (Natural) -import Urbit.King.App (KingEnv, runKingEnvNoLog) - -import qualified Options -import qualified Urbit.EventLog.LMDB as Log - - --- Utils ----------------------------------------------------------------------- - -withTestDir :: (FilePath -> RIO e a) -> RIO e a -withTestDir = withTempDirectory "./" ".testlog." - -data NotEqual = NotEqual String String - deriving (Eq, Ord, Show) - -instance Exception NotEqual where - -assertEqual :: MonadIO m => (Show a, Eq a) => a -> a -> m () -assertEqual x y = do - unless (x == y) $ io $ throwIO $ NotEqual (show x) (show y) - - --- Database Operations --------------------------------------------------------- - -data Db = Db LogIdentity [ByteString] (Map Word64 ByteString) - deriving (Eq, Ord, Show) - -addEvents :: Db -> [ByteString] -> Db -addEvents (Db id evs efs) new = Db id (evs <> new) efs - -readDb :: EventLog -> RIO KingEnv Db -readDb log = do - events <- runConduit (streamEvents log 1 .| consume) - effects <- runConduit (streamEffectsRows log 0 .| consume) - pure $ Db (Log.identity log) events (mapFromList effects) - -withDb :: FilePath -> Db -> (EventLog -> RIO KingEnv a) -> RIO KingEnv a -withDb dir (Db dId dEvs dFx) act = do - rwith (Log.new dir dId) $ \log -> do - Log.appendEvents log (fromList dEvs) - for_ (mapToList dFx) $ \(k,v) -> - Log.writeEffectsRow log k v - act log - --------------------------------------------------------------------------------- - -runApp :: RIO KingEnv a -> IO a -runApp = runKingEnvNoLog - -tryReadIdentity :: Property -tryReadIdentity = forAll arbitrary (ioProperty . runApp . runTest) - where - runTest :: LogIdentity -> RIO KingEnv Bool - runTest ident = do - env <- ask - io $ runInBoundThread $ runRIO env $ - withTestDir $ \dir -> do - rwith (Log.new dir ident) $ \log -> - assertEqual ident (Log.identity log) - rwith (Log.existing dir) $ \log -> - assertEqual ident (Log.identity log) - rwith (Log.existing dir) $ \log -> - assertEqual ident (Log.identity log) - pure True - -tryReadDatabase :: Property -tryReadDatabase = forAll arbitrary (ioProperty . runApp . runTest) - where - runTest :: Db -> RIO KingEnv Bool - runTest db = do - env <- ask - io $ runInBoundThread $ runRIO env $ - withTestDir $ \dir -> do - withDb dir db $ \log -> do - readDb log >>= assertEqual db - pure True - -tryReadDatabaseFuzz :: Property -tryReadDatabaseFuzz = forAll arbitrary (ioProperty . runApp . runTest) - where - runTest :: Db -> RIO KingEnv Bool - runTest db = do - env <- ask - io $ runInBoundThread $ runRIO env $ - withTestDir $ \dir -> do - withDb dir db $ \log -> do - readDb log >>= assertEqual db - rwith (Log.existing dir) $ \log -> do - readDb log >>= assertEqual db - rwith (Log.existing dir) $ \log -> do - readDb log >>= assertEqual db - readDb log >>= assertEqual db - pure True - -tryAppend :: Property -tryAppend = forAll arbitrary (ioProperty . runApp . runTest) - where - runTest :: ([ByteString], Db) -> RIO KingEnv Bool - runTest (extra, db) = do - env <- ask - io $ runInBoundThread $ runRIO env $ - withTestDir $ \dir -> do - db' <- pure (addEvents db extra) - withDb dir db $ \log -> do - readDb log >>= assertEqual db - Log.appendEvents log (fromList extra) - readDb log >>= assertEqual db' - rwith (Log.existing dir) $ \log -> do - readDb log >>= assertEqual db' - pure True - -tryAppendHuge :: Options.Brass -> Property -tryAppendHuge brass = - forAll arbitrary (ioProperty . runApp . runTest) - where - runTest :: ([ByteString], Db) -> RIO KingEnv Bool - runTest (extra, db) = do - env <- ask - io $ runInBoundThread $ runRIO env $ do - extra <- do - b <- readFile =<< Options.getPillPath brass - pure (extra <> [b] <> extra) - withTestDir $ \dir -> do - db' <- pure (addEvents db extra) - withDb dir db $ \log -> do - readDb log >>= assertEqual db - Log.appendEvents log (fromList extra) - readDb log >>= assertEqual db' - rwith (Log.existing dir) $ \log -> do - readDb log >>= assertEqual db' - pure True - - -tests :: TestTree -tests = - testGroup "Log" - [ localOption (QuickCheckTests 10) $ - testProperty "Read/Write Log Identity" $ - tryReadIdentity - , localOption (QuickCheckTests 15) $ - testProperty "Read/Write Database" $ - tryReadDatabase - , localOption (QuickCheckTests 5) $ - testProperty "Read/Write Database Multiple Times" $ - tryReadDatabaseFuzz - , localOption (QuickCheckTests 10) $ - testProperty "Append Random Events" $ - tryAppend - , localOption (QuickCheckTests 1) $ - askOption $ \path -> - testProperty "Append Huge Events" $ - tryAppendHuge path - ] - - --- Generate Arbitrary Values --------------------------------------------------- - -arb :: Arbitrary a => Gen a -arb = arbitrary - -instance Arbitrary ByteString where - arbitrary = pack <$> arbitrary - -instance (Arbitrary a, Arbitrary b) => Arbitrary (LargeKey a b) where - arbitrary = LargeKey <$> arb <*> arb - -instance Arbitrary Ship where - arbitrary = Ship <$> arb - -arbEffects :: [ByteString] -> Gen (Map Word64 ByteString) -arbEffects evs = do - hax <- for (zip [1..] evs) $ \(i, bs) -> do keep :: Bool <- arbitrary - pure (keep, (i, bs)) - pure $ mapFromList $ snd <$> filter fst hax - -instance Arbitrary Db where - arbitrary = do - ident <- arbitrary - evs <- arbitrary - efs <- arbEffects evs - pure (Db ident evs efs) - -instance Arbitrary LogIdentity where - arbitrary = LogIdentity <$> arb <*> arb <*> arb diff --git a/pkg/hs/urbit-king/test/Main.hs b/pkg/hs/urbit-king/test/Main.hs deleted file mode 100644 index f58e2bb4e..000000000 --- a/pkg/hs/urbit-king/test/Main.hs +++ /dev/null @@ -1,48 +0,0 @@ -module Main (main) where - -import ClassyPrelude - -import Control.Concurrent (runInBoundThread) -import Data.Proxy (Proxy (Proxy)) -import RIO.Directory -import Test.QuickCheck hiding ((.&.)) -import Test.Tasty -import Test.Tasty.QuickCheck -import Test.Tasty.TH -import Test.Tasty.Options (OptionDescription (Option)) - -import qualified AmesTests -import qualified ArvoTests -import qualified BehnTests -import qualified ClayTests -import qualified DawnTests -import qualified DeriveNounTests -import qualified HoonMapSetTests -import qualified JamTests -import qualified LogTests -import qualified NounConversionTests -import qualified Options -import qualified Test.Tasty.Runners as Runners - -main :: IO () -main = do - let ingredients = - includingOptions - [ Option (Proxy @Options.Brass) - ] : defaultIngredients - - runInBoundThread $ - defaultMainWithIngredients ingredients $ - localOption (Runners.NumThreads 1) $ - testGroup "Urbit" - [ AmesTests.tests - , ArvoTests.tests - , BehnTests.tests - , ClayTests.tests - , DawnTests.tests - , DeriveNounTests.tests - , HoonMapSetTests.tests - , JamTests.tests - , LogTests.tests - , NounConversionTests.tests - ] diff --git a/pkg/hs/urbit-king/test/NounConversionTests.hs b/pkg/hs/urbit-king/test/NounConversionTests.hs deleted file mode 100644 index 901afbcb9..000000000 --- a/pkg/hs/urbit-king/test/NounConversionTests.hs +++ /dev/null @@ -1,70 +0,0 @@ -module NounConversionTests (tests) where - -import Urbit.Arvo.Event -import Urbit.Noun.Conversions -import Urbit.Prelude - -import Data.Maybe -import Test.QuickCheck hiding ((.&.)) -import Test.QuickCheck.Gen -import Test.QuickCheck.Random -import Test.Tasty -import Test.Tasty.QuickCheck -import Test.Tasty.TH - -import qualified Crypto.Sign.Ed25519 as Ed - --- String Representations of Atoms --------------------------------------------- - -instance Arbitrary UV where - arbitrary = UV <$> arbitrarySizedNatural - -instance Arbitrary UW where - arbitrary = UW <$> arbitrarySizedNatural - -vRoundTrip :: UV -> Bool -vRoundTrip uv = Just uv == (fromNoun $ toNoun $ uv) - -wRoundTrip :: UW -> Bool -wRoundTrip uw = Just uw == (fromNoun $ toNoun uw) - --- Cryptographic Point Representations ----------------------------------------- - -data ThirtyTwoByteString = ThirtyTwoByteString ByteString - deriving (Show) - -data KeyPair = KeyPair (Ed.PublicKey, Ed.SecretKey) - deriving (Show) - -instance Arbitrary ThirtyTwoByteString where - arbitrary = (ThirtyTwoByteString . pack) <$> (vector 32) - -instance Arbitrary KeyPair where - arbitrary = - (KeyPair . fromJust . Ed.createKeypairFromSeed_ . pack) <$> (vector 32) - - -passRoundTrip :: KeyPair -> KeyPair -> Bool -passRoundTrip (KeyPair (signPubkey, _)) (KeyPair (cryptPubkey, _)) = - (Just p) == (fromNoun $ toNoun p) - where - p = Pass signPubkey cryptPubkey - - -ringRoundTrip :: ThirtyTwoByteString -> ThirtyTwoByteString -> Bool -ringRoundTrip (ThirtyTwoByteString signSeed) (ThirtyTwoByteString cryptSeed) = - (Just r) == (fromNoun $ toNoun r) - where - r = Ring signSeed cryptSeed - - --------------------------------------------------------------------------------- - -tests :: TestTree -tests = - testGroup "Noun" - [ testProperty "0v0 printing/parsing round trip" $ vRoundTrip - , testProperty "0w0 printing/parsing round trip" $ wRoundTrip - , testProperty "Pass round trip" $ passRoundTrip - , testProperty "Ring round trip" $ ringRoundTrip - ] diff --git a/pkg/hs/urbit-king/test/Options.hs b/pkg/hs/urbit-king/test/Options.hs deleted file mode 100644 index 3b9aa7456..000000000 --- a/pkg/hs/urbit-king/test/Options.hs +++ /dev/null @@ -1,48 +0,0 @@ -module Options - ( Brass - , Pill - , getPillPath - ) where - -import Control.Monad.IO.Class (MonadIO) -import Data.Proxy (Proxy (Proxy)) -import Data.String (IsString) -import GHC.TypeLits (KnownSymbol, Symbol) -import Prelude - -import qualified GHC.TypeLits as TypeLits -import qualified RIO.Directory as Directory -import qualified Test.Tasty as Tasty -import qualified Test.Tasty.Options as Options - -type Brass = Pill "brass" - --- | A file-system path tagged by the pill name. -newtype Pill (name :: Symbol) = Pill FilePath - deriving stock (Eq, Show) - deriving newtype (IsString) - -instance KnownSymbol name => Options.IsOption (Pill name) where - optionName = - pure ( TypeLits.symbolVal (Proxy @name) - ++ "-pill" - ) - - optionHelp = - pure ( "The file path to the " - ++ TypeLits.symbolVal (Proxy @name) - ++ " pill" - ) - - defaultValue = - Pill ( "../../../bin/" - ++ TypeLits.symbolVal (Proxy @name) - ++ ".pill" - ) - - parseValue = \case - "" -> Nothing - path -> Just (Pill path) - -getPillPath :: MonadIO m => Pill name -> m FilePath -getPillPath (Pill path) = Directory.canonicalizePath path diff --git a/pkg/hs/urbit-king/test/gold/hoontree.gold b/pkg/hs/urbit-king/test/gold/hoontree.gold deleted file mode 100644 index 0b4589065..000000000 --- a/pkg/hs/urbit-king/test/gold/hoontree.gold +++ /dev/null @@ -1 +0,0 @@ -233234490 \ No newline at end of file diff --git a/pkg/hs/urbit-king/test/gold/hoontree.pill b/pkg/hs/urbit-king/test/gold/hoontree.pill deleted file mode 100644 index 26f4933c7..000000000 --- a/pkg/hs/urbit-king/test/gold/hoontree.pill +++ /dev/null @@ -1 +0,0 @@ -Ľ¶0xi…!Yá†nˇ‘Łhˇ1GQ \ No newline at end of file diff --git a/pkg/hs/urbit-noun-core/.gitignore b/pkg/hs/urbit-noun-core/.gitignore deleted file mode 100644 index 65e7ea818..000000000 --- a/pkg/hs/urbit-noun-core/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.stack-work -*.cabal -test/gold/*.writ diff --git a/pkg/hs/urbit-noun-core/LICENSE b/pkg/hs/urbit-noun-core/LICENSE deleted file mode 100644 index bf9294e05..000000000 --- a/pkg/hs/urbit-noun-core/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 urbit - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Convert.hs b/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Convert.hs deleted file mode 100644 index d9cd3bad4..000000000 --- a/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Convert.hs +++ /dev/null @@ -1,126 +0,0 @@ -{-| - Framework for writing conversions between types and nouns. --} -module Urbit.Noun.Convert - ( ToNoun(toNoun) - , FromNoun(parseNoun), fromNoun, fromNounErr, fromNounExn - , Parser(..) - , ParseStack - , parseNounUtf8Atom - , named - ) where - -import ClassyPrelude hiding (hash) - -import Control.Monad.Fail (MonadFail (fail)) -import Urbit.Noun.Core - - --- Types ----------------------------------------------------------------------- - -type ParseStack = [Text] - - --- "Parser" -------------------------------------------------------------------- - -type Failure a = ParseStack -> String -> a -type Success a b = a -> b - -newtype Parser a = Parser { - runParser :: forall r. ParseStack -> Failure r -> Success a r -> r -} - -{-# INLINE named #-} -- keep out of the cost centers -named :: Text -> Parser a -> Parser a -named nm (Parser cb) = - Parser $ \path kf ks -> cb (nm:path) kf ks - -instance Monad Parser where - m >>= g = Parser $ \path kf ks -> let ks' a = runParser (g a) path kf ks - in runParser m path kf ks' - return = pure - -instance MonadFail Parser where - fail msg = Parser $ \path kf _ks -> kf (reverse path) msg - -instance Functor Parser where - fmap f m = Parser $ \path kf ks -> let ks' a = ks (f a) - in runParser m path kf ks' - -apP :: Parser (a -> b) -> Parser a -> Parser b -apP d e = do - b <- d - b <$> e - -instance Applicative Parser where - pure a = Parser $ \_path _kf ks -> ks a - (<*>) = apP - -instance Alternative Parser where - empty = fail "empty" - (<|>) = mplus - -instance MonadPlus Parser where - mzero = fail "mzero" - mplus a b = Parser $ \path kf ks -> let kf' _ _ = runParser b path kf ks - in runParser a path kf' ks - -instance Semigroup (Parser a) where - (<>) = mplus - -instance Monoid (Parser a) where - mempty = fail "mempty" - mappend = (<>) - - --- Conversion ------------------------------------------------------------------ - -class FromNoun a where - parseNoun :: Noun -> Parser a - -class ToNoun a where - toNoun :: a -> Noun - --------------------------------------------------------------------------------- - -fromNoun :: FromNoun a => Noun -> Maybe a -fromNoun n = runParser (parseNoun n) [] onFail onSuccess - where - onFail p m = Nothing - onSuccess !x = Just x - -fromNounErr :: FromNoun a => Noun -> Either ([Text], Text) a -fromNounErr n = runParser (parseNoun n) [] onFail onSuccess - where - onFail p m = Left (p, pack m) - onSuccess !x = Right x - -data BadNoun = BadNoun [Text] String - deriving (Eq, Ord) - -instance Show BadNoun where - show (BadNoun pax msg) = - mconcat [ "(BadNoun " - , show (intercalate "." pax) - , " " - , show msg - , ")" - ] - -instance Exception BadNoun where - -fromNounExn :: MonadIO m => FromNoun a => Noun -> m a -fromNounExn n = runParser (parseNoun n) [] onFail onSuccess - where - onFail p m = throwIO (BadNoun p m) - onSuccess !x = pure x - - --- Cord Conversions ------------------------------------------------------------ - -parseNounUtf8Atom :: Noun -> Parser Text -parseNounUtf8Atom n = - named "utf8-atom" $ do - case utf8AtomToText n of - Left err -> fail (unpack err) - Right tx -> pure tx diff --git a/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Core.hs b/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Core.hs deleted file mode 100644 index 0feffcadd..000000000 --- a/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Core.hs +++ /dev/null @@ -1,176 +0,0 @@ -{-# OPTIONS_GHC -funbox-strict-fields #-} -{-# LANGUAGE Strict #-} -{-# LANGUAGE StrictData #-} - -{-| - Core Noun Implementation - - Each cell has a pre-calculated hash and a `size` field. The size is - the total number of nodes under the tree of the cell. This is used - as a heuristic to choose a hash-table size for `jam` and `cue`. --} -module Urbit.Noun.Core - ( Noun, nounSize - , pattern Cell, pattern Atom - , pattern C, pattern A - , textToUtf8Atom, utf8AtomToText - , mug - ) where - -import ClassyPrelude hiding (hash) - -import Urbit.Atom -import Urbit.Noun.Mug - -import Data.Bits (xor) -import Data.Function ((&)) -import Data.Hashable (hash) -import GHC.Natural (Natural) -import GHC.Prim (reallyUnsafePtrEquality#) -import Test.QuickCheck.Arbitrary (Arbitrary(arbitrary)) -import Test.QuickCheck.Gen (Gen, getSize, resize, scale) - -import qualified Data.Char as C - - --- Types ----------------------------------------------------------------------- - -data Noun - = NCell ~Mug Word Noun Noun - | NAtom ~Mug Atom - -pattern Cell :: Noun -> Noun -> Noun -pattern Atom :: Atom -> Noun - -pattern Cell x y <- NCell _ _ x y where Cell = mkCell -pattern Atom a <- NAtom _ a where Atom = mkAtom - -{-# COMPLETE Cell, Atom #-} - -pattern C :: Noun -> Noun -> Noun -pattern A :: Atom -> Noun - -pattern C x y <- NCell _ _ x y where C = mkCell -pattern A a <- NAtom _ a where A = mkAtom - -{-# COMPLETE C, A #-} - - --------------------------------------------------------------------------------- - -instance Hashable Noun where - hash = fromIntegral . mug - {-# INLINE hash #-} - hashWithSalt salt x = salt `combine` hash x - {-# INLINE hashWithSalt #-} - -textToUtf8Atom :: Text -> Noun -textToUtf8Atom = Atom . utf8Atom - -utf8AtomToText :: Noun -> Either Text Text -utf8AtomToText = \case - Cell _ _ -> Left "Expected @t, but got ^" - Atom atm -> atomUtf8 atm & \case - Left err -> Left (tshow err) - Right tx -> pure tx - -instance Show Noun where - show = \case Atom a -> showAtom a - Cell x y -> fmtCell (show <$> (x : toTuple y)) - where - fmtCell :: [String] -> String - fmtCell xs = "(" <> intercalate ", " xs <> ")" - - toTuple :: Noun -> [Noun] - toTuple (Cell x xs) = x : toTuple xs - toTuple atom = [atom] - - showAtom :: Atom -> String - showAtom 0 = "0" - showAtom a | a >= 2^1024 = "\"...\"" - showAtom a = - let mTerm = do - t <- utf8AtomToText (Atom a) - let ok = \x -> (C.isPrint x) - if (all ok (t :: Text)) - then pure ("\"" <> unpack t <> "\"") - else Left "Don't show as text." - - in case mTerm of - Left _ -> show a - Right st -> st - -instance Eq Noun where - (==) x y = - case reallyUnsafePtrEquality# x y of - 1# -> True - _ -> case (x, y) of - (NAtom x1 a1, NAtom x2 a2) -> - x1 == x2 && a1 == a2 - (NCell x1 s1 h1 t1, NCell x2 s2 h2 t2) -> - s1==s2 && x1==x2 && h1==h2 && t1==t2 - _ -> - False - {-# INLINE (==) #-} - -instance Ord Noun where - compare x y = - case reallyUnsafePtrEquality# x y of - 1# -> EQ - _ -> case (x, y) of - (Atom _, Cell _ _) -> LT - (Cell _ _, Atom _) -> GT - (Atom a1, Atom a2) -> compare a1 a2 - (Cell h1 t1, Cell h2 t2) -> compare h1 h2 <> compare t1 t2 - {-# INLINE compare #-} - - -instance Arbitrary Noun where - arbitrary = resize 1000 go - where - dub x = Cell x x - go = do - sz <- getSize - (bit, bat :: Bool) <- arbitrary - case (sz, bit, bat) of - ( 0, _, _ ) -> Atom <$> genAtom - ( _, False, _ ) -> Atom <$> genAtom - ( _, True, True ) -> dub <$> arbitrary - ( _, True, _ ) -> scale (\x -> x-10) (Cell <$> go <*> go) - -genNatural :: Gen Natural -genNatural = fromInteger . abs <$> arbitrary - -genAtom :: Gen Atom -genAtom = do - arbitrary >>= \case - False -> genNatural - True -> (`mod` 16) <$> genNatural - --- From http://hackage.haskell.org/package/hashable-1.2.7.0/docs/src/Data-Hashable-Class.html -combine :: Int -> Int -> Int -combine h1 h2 = (h1 * 16777619) `xor` h2 - --------------------------------------------------------------------------------- - -{-# INLINE nounSize #-} -nounSize :: Noun -> Word -nounSize = \case - NCell _ s _ _ -> s - NAtom _ _ -> 1 - -{-# INLINE mug #-} -mug :: Noun -> Mug -mug = \case NCell h _ _ _ -> h - NAtom h _ -> h - -{-# INLINE mkAtom #-} -mkAtom :: Atom -> Noun -mkAtom a = NAtom (mugAtom a) a - -{-# INLINE mkCell #-} -mkCell :: Noun -> Noun -> Noun -mkCell h t = NCell has siz h t - where - siz = nounSize h + nounSize t - has = mugBoth (mug h) (mug t) diff --git a/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Cue.hs b/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Cue.hs deleted file mode 100644 index 7fcc79ff4..000000000 --- a/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Cue.hs +++ /dev/null @@ -1,394 +0,0 @@ -{-# OPTIONS_GHC -O2 #-} - -{-| - Fast implementation of `cue :: Atom -> Maybe Noun`. - - Implementation is based on the approach used in `flat`. --} -module Urbit.Noun.Cue (cue, cueExn, cueBS, cueBSExn, DecodeErr) where - -import ClassyPrelude - -import Urbit.Atom -import Urbit.Noun.Core - -import Control.Monad.Fail (MonadFail (fail)) -import Data.Bits (shiftL, shiftR, (.&.), (.|.)) -import Data.Function ((&)) -import Foreign.Ptr (Ptr, castPtr, plusPtr, ptrToWordPtr) -import Foreign.Storable (peek) -import GHC.Prim (ctz#) -import GHC.Word (Word(..)) -import System.IO.Unsafe (unsafePerformIO) -import Text.Printf (printf) - -import qualified Data.ByteString.Unsafe as BS -import qualified Data.HashTable.IO as H -import qualified Data.Vector.Primitive as VP - - --------------------------------------------------------------------------------- - -cueBS :: ByteString -> Either DecodeErr Noun -cueBS = doGet dNoun - -cueBSExn :: MonadIO m => ByteString -> m Noun -cueBSExn bs = - cueBS bs & \case - Left e -> throwIO e - Right x -> pure x - -cue :: Atom -> Either DecodeErr Noun -cue = cueBS . atomBytes - -cueExn :: MonadIO m => Atom -> m Noun -cueExn = cueBSExn . atomBytes - - --- Debugging ------------------------------------------------------------------- - -{-# INLINE debugM #-} -debugM :: Monad m => String -> m () -debugM _ = pure () - -{-# INLINE debugMId #-} -debugMId :: (Monad m, Show a) => String -> m a -> m a -debugMId _ a = a - - --- Types ----------------------------------------------------------------------- - -{-| - The decoder state. - - - An array of words (internal structure of our atoms). - - A pointer to the word *after* the last word in the array. - - A pointer into the current word of that array. - - A bit-offset into that word. --} -data S = S - { currPtr :: {-# UNPACK #-} !(Ptr Word) - , usedBits :: {-# UNPACK #-} !Word - , pos :: {-# UNPACK #-} !Word - } deriving (Show,Eq,Ord) - -type Env = (Ptr Word, S) - -data DecodeErr - = InfiniteCue Env - | BadEncoding Env String - deriving (Show, Eq, Ord) - -data GetResult a = GetResult {-# UNPACK #-} !S !a - deriving (Show, Functor) - -newtype Get a = Get - { runGet :: Ptr Word - -> H.BasicHashTable Word Noun - -> S - -> IO (GetResult a) - } - -doGet :: Get a -> ByteString -> Either DecodeErr a -doGet m bs = - unsafePerformIO $ try $ BS.unsafeUseAsCStringLen bs $ \(ptr, len) -> do - let endPtr = ptr `plusPtr` len - let sz = max 50 - $ min 10_000_000 - $ length bs `div` 6 - tbl <- H.newSized sz - GetResult _ r <- runGet m endPtr tbl (S (castPtr ptr) 0 0) - pure r - --------------------------------------------------------------------------------- - -instance Exception DecodeErr - -instance Functor Get where - fmap f g = Get $ \end tbl s -> do - GetResult s' a <- runGet g end tbl s - return $ GetResult s' (f a) - {-# INLINE fmap #-} - -instance Applicative Get where - pure x = Get (\_ _ s -> return $ GetResult s x) - {-# INLINE pure #-} - - Get f <*> Get g = Get $ \end tbl s1 -> do - GetResult s2 f' <- f end tbl s1 - GetResult s3 g' <- g end tbl s2 - return $ GetResult s3 (f' g') - {-# INLINE (<*>) #-} - - Get f *> Get g = Get $ \end tbl s1 -> do - GetResult s2 _ <- f end tbl s1 - g end tbl s2 - {-# INLINE (*>) #-} - -instance Monad Get where - return = pure - {-# INLINE return #-} - - (>>) = (*>) - {-# INLINE (>>) #-} - - Get x >>= f = Get $ \end tbl s -> do - GetResult s' x' <- x end tbl s - runGet (f x') end tbl s' - {-# INLINE (>>=) #-} - -instance MonadFail Get where - fail msg = Get $ \end tbl s -> do - badEncoding end s msg - {-# INLINE fail #-} - -instance MonadIO Get where - liftIO io = Get $ \end tbl s -> GetResult s <$> io - {-# INLINE liftIO #-} - --------------------------------------------------------------------------------- - -{-# INLINE badEncoding #-} -badEncoding :: Ptr Word -> S -> String -> IO a -badEncoding !endPtr s msg = throwIO $ BadEncoding (endPtr,s) msg - --------------------------------------------------------------------------------- - -{-# INLINE getPos #-} -getPos :: Get Word -getPos = Get $ \_ _ s -> - pure (GetResult s (pos s)) - -{-# INLINE insRef #-} -insRef :: Word -> Noun -> Get () -insRef !pos !now = Get $ \_ tbl s -> do - H.insert tbl pos now - pure $ GetResult s () - -{-# INLINE getRef #-} -getRef :: Word -> Get Noun -getRef !ref = Get $ \x tbl s -> do - H.lookup tbl ref >>= \case - Nothing -> runGet (fail ("Invalid Reference: " <> show ref)) x tbl s - Just no -> pure (GetResult s no) - -{-# INLINE advance #-} -advance :: Word -> Get () -advance 0 = debugM "advance: 0" >> pure () -advance !n = Get $ \_ _ s -> do - debugM ("advance: " <> show n) - let newUsed = n + usedBits s - newS = s { pos = pos s + n - , usedBits = newUsed `mod` 64 - , currPtr = plusPtr (currPtr s) - (8 * (fromIntegral (newUsed `div` 64))) - } - - pure (GetResult newS ()) - --------------------------------------------------------------------------------- - -{-# INLINE guardInfinite #-} -guardInfinite :: Ptr Word -> Ptr Word -> S -> IO () -guardInfinite end cur s = - when (cur >= (end `plusPtr` 16)) $ do - throwIO (InfiniteCue (end, s)) - --- TODO Should this be (>= end) or (> end)? -{-# INLINE peekCurWord #-} -peekCurWord :: Get Word -peekCurWord = Get $ \end _ s -> do - debugMId "peekCurWord" $ do - guardInfinite end (currPtr s) s - if ptrToWordPtr (currPtr s) >= ptrToWordPtr end - then pure (GetResult s 0) - else GetResult s <$> peek (currPtr s) - --- TODO Same question as above. -{-# INLINE peekNextWord #-} -peekNextWord :: Get Word -peekNextWord = Get $ \end _ s -> do - debugMId "peekNextWord" $ do - let pTarget = currPtr s `plusPtr` 8 - guardInfinite end pTarget s - if ptrToWordPtr pTarget >= ptrToWordPtr end - then pure (GetResult s 0) - else GetResult s <$> peek pTarget - -{-# INLINE peekUsedBits #-} -peekUsedBits :: Get Word -peekUsedBits = - debugMId "peekUsedBits" $ do - Get $ \_ _ s -> pure (GetResult s (usedBits s)) - -{-| - Get a bit. - - - Peek the current word. - - Right-shift by the bit-offset. - - Mask the high bits. --} -{-# INLINE dBit #-} -dBit :: Get Bool -dBit = do - debugMId "dBit" $ do - wor <- peekCurWord - use <- fromIntegral <$> peekUsedBits - advance 1 - pure (0 /= shiftR wor use .&. 1) - -{-# INLINE dWord #-} -dWord :: Get Word -dWord = do - debugMId "dWord" $ do - res <- peekWord - advance 64 - pure res - -{-| - Get n bits, where n > 64: - - - Get (n/64) words. - - Advance by n bits. - - Calculate an offset (equal to the current bit-offset) - - Calculate the length (equal to n) - - Construct a bit-vector using the buffer*length*offset. --} -{-# INLINE dAtomBits #-} -dAtomBits :: Word -> Get Atom -dAtomBits !(fromIntegral -> bits) = do - debugMId ("dAtomBits(" <> show bits <> ")") $ do - fmap wordsAtom $ - VP.generateM bufSize $ \i -> do - debugM (show i) - if (i == lastIdx && numExtraBits /= 0) - then dWordBits (fromIntegral numExtraBits) - else dWord - where - bufSize = numFullWords + min 1 numExtraBits - lastIdx = bufSize - 1 - numFullWords = bits `div` 64 - numExtraBits = bits `mod` 64 - -{-| - In order to peek at the next Word64: - - - If we are past the end of the buffer: - - Return zero. - - If the bit-offset is zero: - - Just peek. - - If we are pointing to the last word: - - Peek and right-shift by the bit offset. - - Otherwise, - - Peek the current word *and* the next word. - - Right-shift the current word by the bit-offset. - - Left-shift the next word by the bit-offset. - - Binary or the resulting two words. --} -{-# INLINE peekWord #-} -peekWord :: Get Word -peekWord = do - debugMId "peekWord" $ do - off <- peekUsedBits - cur <- peekCurWord - nex <- peekNextWord - let res = swiz off (cur, nex) - debugM ("\t" <> (take 10 $ reverse $ printf "%b" (fromIntegral res :: Integer)) <> "..") - pure res - -{-# INLINE swiz #-} -swiz :: Word -> (Word, Word) -> Word -swiz !(fromIntegral -> off) (!low, !hig) = - (.|.) (shiftR low off) (shiftL hig (64-off)) - -{-# INLINE takeLowBits #-} -takeLowBits :: Word -> Word -> Word -takeLowBits 64 !wor = wor -takeLowBits !wid !wor = (2^wid - 1) .&. wor - -{-| - Make a word from the next n bits (where n <= 64). - - - Peek at the next word. - - Mask the n lowest bits from the word. - - Advance by that number of bits. - - Return the word. --} -{-# INLINE dWordBits #-} -dWordBits :: Word -> Get Word -dWordBits !n = do - debugMId ("dWordBits(" <> show n <> ")") $ do - w <- peekWord - advance n - debugM ("dWordBits: " <> show (takeLowBits n w)) - pure (takeLowBits n w) - - --- Fast Cue -------------------------------------------------------------------- - -{-| - Get the exponent-prefix of an atom: - - - Peek at the next word. - - Calculate the number of least-significant bits in that word (there's - a primitive for this). - - Advance by that number of bits. - - Return the number of bits --} -{-# INLINE dExp #-} -dExp :: Get Word -dExp = do - debugMId "dExp" $ do - W# w <- peekWord - let res = W# (ctz# w) - advance (res+1) - pure res - -{-# INLINE dAtomLen #-} -dAtomLen :: Get Word -dAtomLen = do - debugMId "dAtomLen" $ do - dExp >>= \case - 0 -> pure 0 - e -> do p <- dWordBits (e-1) - pure (2^(e-1) .|. p) - -{-# INLINE dRef #-} -dRef :: Get Word -dRef = debugMId "dRef" (dAtomLen >>= dWordBits) - -{-# INLINE dAtom #-} -dAtom :: Get Atom -dAtom = do - debugMId "dAtom" $ do - dAtomLen >>= \case - 0 -> pure 0 - n -> dAtomBits n - -{-# INLINE dCell #-} -dCell :: Get Noun -dCell = Cell <$> dNoun <*> dNoun - -{-| - Get a Noun. - - - Get a bit - - If it's zero, get an atom. - - Otherwise, get another bit. - - If it's zero, get a cell. - - If it's one, get an atom. --} -dNoun :: Get Noun -dNoun = do - p <- getPos - - let yield r = insRef p r >> pure r - - dBit >>= \case - False -> do debugM "It's an atom" - (Atom <$> dAtom) >>= yield - True -> dBit >>= \case - False -> do debugM "It's a cell" - dCell >>= yield - True -> do debugM "It's a backref" - dRef >>= getRef diff --git a/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Jam.hs b/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Jam.hs deleted file mode 100644 index 325bb4cd1..000000000 --- a/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Jam.hs +++ /dev/null @@ -1,368 +0,0 @@ -{-# OPTIONS_GHC -O2 #-} - -{-| - Fast implementation of Jam (Noun -> Atom). - - This is based on the implementation of `flat`. --} -module Urbit.Noun.Jam (jam, jamBS) where - -import ClassyPrelude hiding (hash) - -import Urbit.Atom -import Urbit.Noun.Core - -import Data.Bits (clearBit, setBit, shiftL, shiftR, (.|.)) -import Data.Vector.Primitive ((!)) -import Foreign.Marshal.Alloc (callocBytes, free) -import Foreign.Ptr (Ptr, castPtr, plusPtr) -import Foreign.Storable (poke) -import GHC.Int (Int(I#)) -import GHC.Integer.GMP.Internals (BigNat) -import GHC.Natural (Natural(NatJ#, NatS#)) -import GHC.Prim (Word#, plusWord#, word2Int#) -import GHC.Word (Word(W#)) -import System.IO.Unsafe (unsafePerformIO) - -import qualified Urbit.Atom.Fast as Atom -import qualified Data.ByteString.Unsafe as BS -import qualified Data.HashTable.IO as H -import qualified Data.Vector.Primitive as VP - - --- Exports --------------------------------------------------------------------- - -jamBS :: Noun -> ByteString -jamBS n = doPut bt sz (writeNoun n) - where - (sz, bt) = unsafePerformIO (compress n) - -jam :: Noun -> Atom -jam = bytesAtom . jamBS - - --- Types ----------------------------------------------------------------------- - -{-| - The encoder state. - - - ptr: Pointer into the output buffer. - - reg: Next 64 bits of output, partially written. - - off: Number of bits already written into `reg` - - pos: Total number of bits written. --} -data S = S - { ptr :: {-# UNPACK #-} !(Ptr Word) - , reg :: {-# UNPACK #-} !Word - , off :: {-# UNPACK #-} !Int - , pos :: {-# UNPACK #-} !Word - } deriving (Show,Eq,Ord) - -data PutResult a = PutResult {-# UNPACK #-} !S !a - deriving Functor - -newtype Put a = Put - { runPut :: H.CuckooHashTable Word Word - -> S - -> IO (PutResult a) - } - --------------------------------------------------------------------------------- - -{-# INLINE getRef #-} -getRef :: Put (Maybe Word) -getRef = Put $ \tbl s -> PutResult s <$> H.lookup tbl (pos s) - -{-| - 1. Write the register to the output, and increment the output pointer. --} -{-# INLINE flush #-} -flush :: Put () -flush = Put $ \tbl s@S{..} -> do - poke ptr reg - pure $ PutResult (s { ptr = ptr `plusPtr` 8 }) () - -{-# INLINE update #-} -update :: (S -> S) -> Put () -update f = Put $ \tbl s@S{} -> pure (PutResult (f s) ()) - -{-# INLINE setRegOff #-} -setRegOff :: Word -> Int -> Put () -setRegOff r o = update $ \s@S{} -> (s {reg=r, off=o}) - -{-# INLINE setReg #-} -setReg :: Word -> Put () -setReg r = update $ \s@S{} -> (s { reg=r }) - -{-# INLINE getS #-} -getS :: Put S -getS = Put $ \tbl s -> pure (PutResult s s) - -{-# INLINE putS #-} -putS :: S -> Put () -putS s = Put $ \tbl _ -> pure (PutResult s ()) - -{-| - To write a bit: - - | reg |= 1 << off - | off <- (off + 1) % 64 - | if (!off): - | buf[w++] <- reg - | reg <- 0 --} -{-# INLINE writeBit #-} -writeBit :: Bool -> Put () -writeBit b = Put $ \tbl s@S{..} -> do - let s' = s { reg = (if b then setBit else clearBit) reg off - , off = (off + 1) `mod` 64 - , pos = pos + 1 - } - - if off == 63 - then runPut (flush >> setRegOff 0 0) tbl s' - else pure $ PutResult s' () - -{-| - To write a 64bit word: - - | reg |= w << off - | buf[bufI++] = reg - | reg = w >> (64 - off) --} -{-# INLINE writeWord #-} -writeWord :: Word -> Put () -writeWord wor = do - S{..} <- getS - setReg (reg .|. shiftL wor off) - flush - update $ \s -> s { pos = 64 + pos - , reg = shiftR wor (64 - off) - } - -{-| - To write some bits (< 64) from a word: - - | wor = takeBits(wid, wor) - | reg = reg .|. (wor << off) - | off = (off + wid) % 64 - | - | if (off + wid >= 64) - | buf[w] = x - | reg = wor >> (wid - off) --} -{-# INLINE writeBitsFromWord #-} -writeBitsFromWord :: Int -> Word -> Put () -writeBitsFromWord wid wor = do - wor <- pure (Atom.takeBitsWord wid wor) - - oldSt <- getS - - let newSt = oldSt { reg = reg oldSt .|. shiftL wor (off oldSt) - , off = (off oldSt + wid) `mod` 64 - , pos = fromIntegral wid + pos oldSt - } - - putS newSt - - when (wid + off oldSt >= 64) $ do - flush - setReg (shiftR wor (wid - off newSt)) - -{-| - Write all of the the signficant bits of a direct atom. --} -{-# INLINE writeAtomWord# #-} -writeAtomWord# :: Word# -> Put () -writeAtomWord# w = do - writeBitsFromWord (I# (word2Int# (Atom.wordBitWidth# w))) (W# w) - -{-# INLINE writeAtomWord #-} -writeAtomWord :: Word -> Put () -writeAtomWord (W# w) = writeAtomWord# w - -{-| - Write all of the the signficant bits of an indirect atom. - - TODO Use memcpy when the bit-offset of the output is divisible by 8. --} -{-# INLINE writeAtomBigNat #-} -writeAtomBigNat :: BigNat -> Put () -writeAtomBigNat !(Atom.bigNatWords -> words) = do - let lastIdx = VP.length words - 1 - for_ [0..(lastIdx-1)] $ \i -> - writeWord (words ! i) - writeAtomWord (words ! lastIdx) - -{-# INLINE writeAtomBits #-} -writeAtomBits :: Atom -> Put () -writeAtomBits = \case NatS# wd -> writeAtomWord# wd - NatJ# bn -> writeAtomBigNat bn - - --- Put Instances --------------------------------------------------------------- - -instance Functor Put where - fmap f g = Put $ \tbl s -> do - PutResult s' a <- runPut g tbl s - pure $ PutResult s' (f a) - {-# INLINE fmap #-} - -instance Applicative Put where - pure x = Put (\_ s -> return $ PutResult s x) - {-# INLINE pure #-} - - Put f <*> Put g = Put $ \tbl s1 -> do - PutResult s2 f' <- f tbl s1 - PutResult s3 g' <- g tbl s2 - return $ PutResult s3 (f' g') - {-# INLINE (<*>) #-} - - Put f *> Put g = Put $ \tbl s1 -> do - PutResult s2 _ <- f tbl s1 - g tbl s2 - {-# INLINE (*>) #-} - -instance Monad Put where - return = pure - {-# INLINE return #-} - - (>>) = (*>) - {-# INLINE (>>) #-} - - Put x >>= f = Put $ \tbl s -> do - PutResult s' x' <- x tbl s - runPut (f x') tbl s' - {-# INLINE (>>=) #-} - - --------------------------------------------------------------------------------- - -doPut :: H.CuckooHashTable Word Word -> Word -> Put () -> ByteString -doPut !tbl !sz m = - unsafePerformIO $ do - -- traceM "doPut" - buf <- callocBytes (fromIntegral (wordSz*8)) - _ <- runPut (m >> mbFlush) tbl (S buf 0 0 0) - BS.unsafePackCStringFinalizer (castPtr buf) byteSz (free buf) - where - !wordSz = fromIntegral (sz `divUp` 64) - !byteSz = fromIntegral (sz `divUp` 8) - !divUp = \x y -> (x `div` y) + (if x `mod` y == 0 then 0 else 1) - - mbFlush :: Put () - mbFlush = do - shouldFlush <- (/= 0) . off <$> getS - when shouldFlush flush - - --------------------------------------------------------------------------------- - -{-| - TODO Handle back references --} -writeNoun :: Noun -> Put () -writeNoun !n = - getRef >>= \case - Just bk -> writeBackRef bk - Nothing -> case n of Atom a -> writeAtom a - Cell h t -> writeCell h t - -{-# INLINE writeMat #-} -writeMat :: Atom -> Put () -writeMat 0 = writeBit True -writeMat atm = do - writeBitsFromWord (preWid+1) (shiftL 1 preWid) - writeBitsFromWord (preWid-1) atmWid - writeAtomBits atm - where - atmWid = Atom.atomBitWidth atm - preWid = fromIntegral (Atom.wordBitWidth atmWid) - -{-# INLINE writeCell #-} -writeCell :: Noun -> Noun -> Put () -writeCell !h !t = do - writeBit True - writeBit False - writeNoun h - writeNoun t - -{-# INLINE writeAtom #-} -writeAtom :: Atom -> Put () -writeAtom !a = do - writeBit False - writeMat a - -{-# INLINE writeBackRef #-} -writeBackRef :: Word -> Put () -writeBackRef !a = do - p <- pos <$> getS - writeBit True - writeBit True - writeMat (fromIntegral a) - - --- Calculate Jam Size and Backrefs --------------------------------------------- - -{-# INLINE matSz #-} -matSz :: Atom -> Word -matSz !a = W# (matSz# a) - -{-# INLINE matSz# #-} -matSz# :: Atom -> Word# -matSz# 0 = 1## -matSz# a = preW `plusWord#` preW `plusWord#` atmW - where - atmW = Atom.atomBitWidth# a - preW = Atom.wordBitWidth# atmW - -{-# INLINE atomSz #-} -atomSz :: Atom -> Word -atomSz !w = 1 + matSz w - -{-# INLINE refSz #-} -refSz :: Word -> Word -refSz !w = 1 + jamWordSz w - -{-# INLINE jamWordSz #-} -jamWordSz :: Word -> Word -jamWordSz 0 = 2 -jamWordSz (W# w) = 1 + 2*(W# preW) + (W# atmW) - where - atmW = Atom.wordBitWidth# w - preW = Atom.wordBitWidth# atmW - -compress :: Noun -> IO (Word, H.CuckooHashTable Word Word) -compress !top = do - let sz = max 50 - $ min 10_000_000 - $ (2*) $ (10^) $ floor $ logBase 600 $ fromIntegral $ nounSize top - - nodes :: H.BasicHashTable Noun Word <- H.newSized sz - backs :: H.CuckooHashTable Word Word <- H.newSized sz - - let proc :: Word -> Noun -> IO Word - proc !pos = \case - Atom a -> pure (atomSz a) - Cell h t -> do !hSz <- go (pos+2) h - !tSz <- go (pos+2+hSz) t - pure (2+hSz+tSz) - - go :: Word -> Noun -> IO Word - go !p !inp = do - H.lookup nodes inp >>= \case - Nothing -> do - H.insert nodes inp p - proc p inp - Just bak -> do - let rs = refSz bak - doRef = H.insert backs p bak $> rs - noRef = proc p inp - case inp of - Cell _ _ -> doRef - Atom a | rs < atomSz (fromIntegral a) -> doRef - _ -> noRef - - res <- go 0 top - - pure (res, backs) diff --git a/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Mug.hs b/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Mug.hs deleted file mode 100644 index 005f82232..000000000 --- a/pkg/hs/urbit-noun-core/lib/Urbit/Noun/Mug.hs +++ /dev/null @@ -1,38 +0,0 @@ -{-# OPTIONS_GHC -O2 #-} - -module Urbit.Noun.Mug where - -import ClassyPrelude - -import Data.Bits -import Data.ByteString.Builder -import Urbit.Atom - -import Data.Hash.Murmur (murmur3) - -type Mug = Word32 - -{-# INLINE mugBS #-} -mugBS :: ByteString -> Word32 -mugBS = mum 0xcafe_babe 0x7fff - --- XX is there a way to do this without copy? -{-# INLINE mugAtom #-} -mugAtom :: Atom -> Word32 -mugAtom = mugBS . atomBytes - -{-# INLINE mugBoth #-} -mugBoth :: Word32 -> Word32 -> Word32 -mugBoth m n = mum 0xdead_beef 0xfffe - $ toStrict $ toLazyByteString (word32LE m <> word32LE n) - -mum :: Word32 -> Word32 -> ByteString -> Word32 -mum syd fal key = go syd 0 - where - go syd 8 = fal - go syd i = - let haz = murmur3 syd key - ham = shiftR haz 31 `xor` (haz .&. 0x7fff_ffff) - in if ham /= 0 - then ham - else go (syd + 1) (i + 1) diff --git a/pkg/hs/urbit-noun-core/lib/Urbit/Noun/TH.hs b/pkg/hs/urbit-noun-core/lib/Urbit/Noun/TH.hs deleted file mode 100644 index c619ab655..000000000 --- a/pkg/hs/urbit-noun-core/lib/Urbit/Noun/TH.hs +++ /dev/null @@ -1,300 +0,0 @@ -{-| - Template Haskell Code to Generate FromNoun and ToNoun Instances --} -module Urbit.Noun.TH (deriveNoun, deriveToNoun, deriveFromNoun, deriveToNounFunc, deriveFromNounFunc) where - -import ClassyPrelude hiding (fromList) -import Control.Monad.Fail (fail) -import Language.Haskell.TH -import Language.Haskell.TH.Syntax -import Urbit.Noun.Convert - -import Urbit.Noun.Core (textToUtf8Atom) - -import qualified Data.Char as C - - --------------------------------------------------------------------------------- - -type ConInfo = (Name, [Type]) - -data Shape - = Vod - | Tup ConInfo - | Sum [(String, Name)] [(String, ConInfo)] - deriving (Eq, Ord, Show) - -typeShape :: Name -> Q ([TyVarBndr], Shape) -typeShape tyName = do - (vars, cs) <- - reify tyName >>= \case - TyConI (DataD _ nm vars _ cs _) -> pure (vars, unpackCon <$> cs) - TyConI (NewtypeD _ nm vars _ c _) -> pure (vars, [unpackCon c]) - TyConI _ -> fail badSynonym - _ -> fail "not type" - - let prefix = getPrefix (nameStr . fst <$> cs) - splits = splitFn ([], []) cs - splitFn (l, r) = \case - [] -> (l, r) - (n,[]) : cs -> splitFn (tagName prefix n:l, r) cs - conInf : cs -> splitFn (l, tagConInfo prefix conInf:r) cs - - pure $ (vars,) $ case cs of - [] -> Vod - [c] -> Tup c - cs -> uncurry Sum splits - - where - badSynonym = "deriveFunctor: tyCon may not be a type synonym." - - tagConInfo :: Int -> ConInfo -> (String, ConInfo) - tagConInfo pre ci@(nm, _) = (tagString pre nm, ci) - - tagName :: Int -> Name -> (String, Name) - tagName pre n = (tagString pre n, n) - - tyStr = nameStr tyName - tyAbbrv = filter C.isUpper tyStr - - typePrefixed = (tyStr `isPrefixOf`) - abbrvPrefixed = (tyAbbrv `isPrefixOf`) - - getPrefix :: [String] -> Int - getPrefix cs | all typePrefixed cs = length tyStr - getPrefix cs | all abbrvPrefixed cs = length tyAbbrv - getPrefix _ = 0 - - unpackCon :: Con -> ConInfo - unpackCon = \case - NormalC nm bangTypes -> (nm, snd <$> bangTypes) - RecC nm varBangTypes -> (nm, varBangTypes <&> (\(_, _, t) -> t)) - InfixC bangType1 nm bangType2 -> error "Infix Cnstrs are not supported" - ForallC tyVarBndrs ctx con -> error "Polymorphic tys are not supported" - GadtC nm bangTypes ty -> error "GADTs are not supported" - RecGadtC nm varBangTypes ty -> error "GADTs are not supported" - --------------------------------------------------------------------------------- - -deriveNoun :: Name -> Q [Dec] -deriveNoun n = (<>) <$> deriveToNoun n <*> deriveFromNoun n - --------------------------------------------------------------------------------- - -deriveToNoun :: Name -> Q [Dec] -deriveToNoun tyName = do - (params, _) <- typeShape tyName - - exp <- deriveToNounFunc tyName - params <- pure $ zip ['a' ..] params <&> \(n,_) -> mkName (singleton n) - - let ty = foldl' (\acc v -> AppT acc (VarT v)) (ConT tyName) params - - let overlap = Nothing - body = NormalB exp - ctx = params <&> \t -> AppT (ConT ''ToNoun) (VarT t) - inst = AppT (ConT ''ToNoun) ty - - pure [InstanceD overlap ctx inst [ValD (VarP 'toNoun) body []]] - -deriveToNounFunc :: Name -> Q Exp -deriveToNounFunc tyName = do - (_, shape) <- typeShape tyName - pure case shape of - Vod -> vodToNoun - Tup con -> tupToNoun con - -- Enu cons -> enumToAtom cons - Sum atoms cells -> sumToNoun atoms cells - --------------------------------------------------------------------------------- - -addErrTag :: String -> Exp -> Exp -addErrTag tag exp = - -- This spurious let is inserted so we can get better cost center data - -- during heap profiling. - LetE [ValD (VarP nom) (NormalB nam) []] - $ InfixE (Just $ VarE nom) (VarE (mkName ".")) (Just exp) - where - -- XX arguably we should use newName rather than mkName here - nom = mkName $ "named_" ++ filter C.isAlphaNum tag - str = LitE $ StringL tag - nam = LamE [VarP $ mkName "x"] $ AppE (AppE (VarE 'named) str) - $ VarE (mkName "x") - -addCostCenter :: String -> Exp -> Exp -addCostCenter tag exp = - LetE [ValD (VarP nom) (NormalB exp) []] (VarE nom) - where - nom = mkName $ "scc_" ++ filter C.isAlphaNum tag - -deriveFromNoun :: Name -> Q [Dec] -deriveFromNoun tyName = do - (params, _) <- typeShape tyName - - exp <- deriveFromNounFunc tyName - params <- pure $ zip ['a' ..] params <&> \(n,_) -> mkName (singleton n) - - let ty = foldl' (\acc v -> AppT acc (VarT v)) (ConT tyName) params - - let overlap = Nothing - body = NormalB (addCostCenter nom $ addErrTag nom exp) - nom = nameStr tyName - ctx = params <&> \t -> AppT (ConT ''FromNoun) (VarT t) - inst = AppT (ConT ''FromNoun) ty - - pure [InstanceD overlap ctx inst [ValD (VarP 'parseNoun) body []]] - -deriveFromNounFunc :: Name -> Q Exp -deriveFromNounFunc tyName = do - (_, shape) <- typeShape tyName - pure case shape of - Vod -> vodFromNoun - Tup con -> tupFromNoun con - -- Enu cons -> enumFromAtom cons - Sum atoms cells -> sumFromNoun atoms cells - -sumFromNoun :: [(String, Name)] -> [(String, ConInfo)] -> Exp -sumFromNoun [] cl = taggedFromNoun cl -sumFromNoun at [] = enumFromAtom at -sumFromNoun at cl = eitherParser (taggedFromNoun cl) (enumFromAtom at) - where - eitherParser :: Exp -> Exp -> Exp - eitherParser x y = - LamE [VarP n] $ - InfixE (Just xCase) (VarE (mkName "<|>")) (Just yCase) - where - xCase = AppE x (VarE n) - yCase = AppE y (VarE n) - n = mkName "atomOrCell" - -enumFromAtom :: [(String, Name)] -> Exp -enumFromAtom cons = LamE [VarP x] body - where - (x, c) = (mkName "x", mkName "c") - getTag = BindS (VarP c) - $ AppE (AppE (VarE 'named) matchFail) - $ AppE (VarE 'parseNounUtf8Atom) (VarE x) - examine = NoBindS $ CaseE (VarE c) (matches ++ [fallback]) - matches = mkMatch <$> cons - fallback = Match WildP (NormalB $ AppE (VarE 'fail) matchFail) [] - body = DoE [getTag, examine] - matchFail = LitE $ StringL ("Expected one of: " <> possible) - possible = intercalate " " (('%':) . fst <$> cons) - mkMatch = \(tag, nm) -> - Match (SigP (LitP $ StringL tag) (ConT ''Text)) - (NormalB $ AppE (VarE 'pure) (ConE nm)) - [] - -applyE :: Exp -> [Exp] -> Exp -applyE e [] = e -applyE e (a:as) = applyE (AppE e a) as - -vodFromNoun :: Exp -vodFromNoun = LamE [WildP] body - where - body = AppE (VarE 'fail) - $ LitE $ StringL "Can't FromNoun on uninhabited data type" - -tupFromNoun :: ConInfo -> Exp -tupFromNoun (n, tys) = LamE [VarP x] body - where - x = mkName "x" - vars = mkName . singleton . fst <$> zip ['a'..] tys - body = DoE [getTup, convert] - convert = NoBindS $ AppE (VarE 'pure) $ applyE (ConE n) (VarE <$> vars) - getTup = BindS (TupP $ VarP <$> vars) $ AppE (VarE 'parseNoun) (VarE x) - -unexpectedTag :: [String] -> Exp -> Exp -unexpectedTag expected got = - applyE (VarE 'mappend) [LitE (StringL prefix), AppE (VarE 'unpack) got] - where - possible = intercalate " " (('%':) <$> expected) - prefix = "Expected one of: " <> possible <> " but got %" - -taggedFromNoun :: [(String, ConInfo)] -> Exp -taggedFromNoun cons = LamE [VarP n] (DoE [getHead, getTag, examine]) - where - (n, h, t, c) = (mkName "noun", mkName "hed", mkName "tel", mkName "tag") - - getHead = BindS (TupP [VarP h, VarP t]) - $ AppE (VarE 'parseNoun) (VarE n) - - getTag = BindS (SigP (VarP c) (ConT ''Text)) - $ AppE (AppE (VarE 'named) tagFail) - $ AppE (VarE 'parseNounUtf8Atom) (VarE h) - - examine = NoBindS - $ CaseE (VarE c) (matches ++ [fallback]) - - matches = mkMatch <$> cons - mkMatch = \(tag, (n, tys)) -> - let body = addCostCenter tag - $ AppE (addErrTag ('%':tag) (tupFromNoun (n, tys))) - (VarE t) - in Match (LitP $ StringL tag) (NormalB body) [] - - fallback = Match WildP (NormalB $ AppE (VarE 'fail) matchFail) [] - matchFail = addCostCenter "matchFail" $ unexpectedTag (fst <$> cons) (VarE c) - - tagFail = LitE $ StringL (intercalate " " (('%':) <$> (fst <$> cons))) - --------------------------------------------------------------------------------- - -tagString :: Int -> Name -> String -tagString prefix = hsToHoon . drop prefix . nameStr - -nameStr :: Name -> String -nameStr (Name (OccName n) _) = n - -tagNoun :: String -> Exp -tagNoun = AppE (VarE 'textToUtf8Atom) - . LitE - . StringL - -tagTup :: String -> [Name] -> Exp -tagTup tag args = AppE (VarE 'toNoun) $ TupE (tagNoun tag : fmap VarE args) - -tup :: [Name] -> Exp -tup = AppE (VarE 'toNoun) . TupE . fmap VarE - --------------------------------------------------------------------------------- - -vodToNoun :: Exp -vodToNoun = LamCaseE [] - -tupToNoun :: ConInfo -> Exp -tupToNoun cons = LamCaseE [mkMatch cons] - where - mkMatch :: ConInfo -> Match - mkMatch (nm, tys) = Match (ConP nm params) (NormalB body) [] - where vars = (zip tys ['a'..]) <&> (mkName . singleton . snd) - params = VarP <$> vars - body = tup vars - -sumToNoun :: [(String, Name)] -> [(String, ConInfo)] -> Exp -sumToNoun a c = - LamCaseE (mixed <&> uncurry mkMatch) - where - mixed = mconcat [ a <&> \(x,y) -> (x, Left y) - , c <&> \(x,y) -> (x, Right y) - ] - - mkMatch :: String -> Either Name ConInfo -> Match - mkMatch tag = \case - Left nm -> Match (ConP nm []) (NormalB $ tagNoun tag) [] - Right (nm, tys) -> Match (ConP nm params) (NormalB body) [] - where vars = (zip tys ['a'..]) <&> (mkName . singleton . snd) - params = VarP <$> vars - body = tagTup tag vars - --------------------------------------------------------------------------------- - -hsToHoon :: String -> String -hsToHoon = go [] - where - go acc [] = intercalate "-" $ reverse acc - go acc (c:cs) = go (elem:acc) remain - where - head = C.toLower c - (tail, remain) = break C.isUpper cs - elem = head:tail diff --git a/pkg/hs/urbit-noun-core/package.yaml b/pkg/hs/urbit-noun-core/package.yaml deleted file mode 100644 index 2d5dfb8a9..000000000 --- a/pkg/hs/urbit-noun-core/package.yaml +++ /dev/null @@ -1,73 +0,0 @@ -name: urbit-noun-core -version: 0.10.4 -license: MIT -license-file: LICENSE - -library: - source-dirs: lib - ghc-options: - - -Wall - - -Werror - - -Wno-type-defaults - - -Wno-unused-matches - - -Wno-name-shadowing - - -O2 - -dependencies: - - base - - QuickCheck - - ghc-prim - - hashable - - urbit-atom - - classy-prelude - - bytestring - - hashtables - - vector - - integer-gmp - - template-haskell - - murmur3 - -default-extensions: - - ApplicativeDo - - BangPatterns - - BlockArguments - - ConstraintKinds - - DataKinds - - DefaultSignatures - - DeriveAnyClass - - DeriveDataTypeable - - DeriveFoldable - - DeriveGeneric - - DeriveTraversable - - DerivingStrategies - - EmptyCase - - EmptyDataDecls - - FlexibleContexts - - FlexibleInstances - - FunctionalDependencies - - GADTs - - GeneralizedNewtypeDeriving - - LambdaCase - - MagicHash - - MultiParamTypeClasses - - NamedFieldPuns - - NoImplicitPrelude - - NumericUnderscores - - OverloadedStrings - - PackageImports - - PartialTypeSignatures - - PatternSynonyms - - QuasiQuotes - - Rank2Types - - RankNTypes - - RecordWildCards - - ScopedTypeVariables - - StandaloneDeriving - - TemplateHaskell - - TupleSections - - TypeApplications - - TypeFamilies - - TypeOperators - - UnboxedTuples - - UnicodeSyntax - - ViewPatterns diff --git a/pkg/hs/urbit-noun/.gitignore b/pkg/hs/urbit-noun/.gitignore deleted file mode 100644 index 65e7ea818..000000000 --- a/pkg/hs/urbit-noun/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.stack-work -*.cabal -test/gold/*.writ diff --git a/pkg/hs/urbit-noun/LICENSE b/pkg/hs/urbit-noun/LICENSE deleted file mode 100644 index bf9294e05..000000000 --- a/pkg/hs/urbit-noun/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 urbit - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/pkg/hs/urbit-noun/lib/Urbit/Noun.hs b/pkg/hs/urbit-noun/lib/Urbit/Noun.hs deleted file mode 100644 index 3357e91d9..000000000 --- a/pkg/hs/urbit-noun/lib/Urbit/Noun.hs +++ /dev/null @@ -1,59 +0,0 @@ -{-| - Noun Library - - This module just re-exports things from submodules. --} -module Urbit.Noun - ( module Urbit.Atom - , module Data.Word - , module Urbit.Noun.Conversions - , module Urbit.Noun.Convert - , module Urbit.Noun.Core - , module Urbit.Noun.Cue - , module Urbit.Noun.Jam - , module Urbit.Noun.Mug - , module Urbit.Noun.Tank - , module Urbit.Noun.TH - , module Urbit.Noun.Tree - , _Cue - , LoadErr(..) - , loadFile - ) where - -import ClassyPrelude -import Control.Lens - -import Data.Word -import Urbit.Atom -import Urbit.Noun.Conversions -import Urbit.Noun.Convert -import Urbit.Noun.Core -import Urbit.Noun.Cue -import Urbit.Noun.Jam -import Urbit.Noun.Mug -import Urbit.Noun.Tank -import Urbit.Noun.TH -import Urbit.Noun.Tree - --------------------------------------------------------------------------------- - -_Cue :: Prism' ByteString Noun -_Cue = prism' jamBS (eitherToMaybe . cueBS) - where - eitherToMaybe (Left _) = Nothing - eitherToMaybe (Right x) = Just x - -data LoadErr - = FileErr IOException - | CueErr DecodeErr - | ParseErr [Text] Text - deriving (Show) - -instance Exception LoadErr - -loadFile :: forall a. FromNoun a => FilePath -> IO (Either LoadErr a) -loadFile pax = try $ do - byt <- try (readFile pax) >>= either (throwIO . FileErr) pure - non <- cueBS byt & either (throwIO . CueErr) pure - res <- fromNounErr non & either (throwIO . uncurry ParseErr) pure - pure res diff --git a/pkg/hs/urbit-noun/lib/Urbit/Noun/Conversions.hs b/pkg/hs/urbit-noun/lib/Urbit/Noun/Conversions.hs deleted file mode 100644 index c8be6d0cd..000000000 --- a/pkg/hs/urbit-noun/lib/Urbit/Noun/Conversions.hs +++ /dev/null @@ -1,902 +0,0 @@ -{-# LANGUAGE StrictData #-} - -{-| - Large Library of conversion between various types and Nouns. --} - -module Urbit.Noun.Conversions - ( Nullable(..), Jammed(..), AtomCell(..) - , Word128, Word256, Word512 - , Bytes(..), Octs(..), File(..) - , Cord(..), Knot(..), Term(..), Tape(..), Tour(..) - , BigTape(..), BigCord(..) - , Wain(..), Wall, Each(..) - , UD(..), UV(..), UW(..), cordToUW - , Path(..), EvilPath(..), Ship(..) - , Lenient(..), pathToFilePath, filePathToPath - , showUD, tshowUD - , textAsT - ) where - -import ClassyPrelude hiding (hash) - -import Control.Lens hiding (Each, Index, (<.>)) -import Control.Monad.Fail (fail) -import Data.Void -import Data.Word -import Text.Regex.TDFA -import Text.Regex.TDFA.Text () -import Urbit.Atom -import Urbit.Noun.Convert -import Urbit.Noun.Core -import Urbit.Noun.TH - -import Data.LargeWord (LargeKey(..), Word128, Word256) -import GHC.Exts (chr#, isTrue#, leWord#, word2Int#) -import GHC.Natural (Natural) -import GHC.Types (Char(C#)) -import GHC.Word (Word32(W32#)) -import Prelude ((!!)) -import RIO.FilePath (joinPath, splitDirectories, takeBaseName, - takeDirectory, takeExtension) -import Urbit.Noun.Cue (cue) -import Urbit.Noun.Jam (jam) -import Urbit.Ob (patp) - -import qualified Data.Char as C -import qualified Data.Text as T -import qualified Data.Text.Encoding as T -import qualified Numeric as N - - --- Noun ------------------------------------------------------------------------ - -instance ToNoun Noun where - toNoun = id - -instance FromNoun Noun where - parseNoun = pure - - ---- Atom ----------------------------------------------------------------------- - -instance ToNoun Atom where - toNoun = Atom - -instance FromNoun Atom where - parseNoun = named "Atom" . \case - Atom a -> pure a - Cell _ _ -> fail "Expecting an atom, but got a cell" - - --- Void ------------------------------------------------------------------------ - -instance ToNoun Void where - toNoun = absurd - -instance FromNoun Void where - parseNoun _ = named "Void" $ fail "Can't produce void" - - --- Cord ------------------------------------------------------------------------ - -newtype Cord = Cord { unCord :: Text } - deriving newtype (Eq, Ord, Show, IsString, NFData) - -instance ToNoun Cord where - toNoun = textToUtf8Atom . unCord - -instance FromNoun Cord where - parseNoun = named "Cord" . fmap Cord . parseNounUtf8Atom - - --- Decimal Cords --------------------------------------------------------------- - -newtype UD = UD { unUD :: Word } - deriving newtype (Eq, Ord, Show, Enum, Real, Integral, Num) - -instance ToNoun UD where - toNoun = toNoun . Cord . tshow . unUD - -instance FromNoun UD where - parseNoun n = named "UD" do - Cord t <- parseNoun n - readMay t & \case - Nothing -> fail ("invalid decimal atom: " <> unpack (filter (/= '.') t)) - Just vl -> pure (UD vl) - -showUD :: (Show i, Integral i) => i -> String -showUD = uTypeAddDots 3 . show - -tshowUD :: (Show i, Integral i) => i -> Text -tshowUD = pack . uTypeAddDots 3 . show - - --------------------------------------------------------------------------------- - -uTypeAddDots :: Int -> String -> String -uTypeAddDots n = reverse . go . reverse - where - go s = if null tel then hed - else hed <> "." <> go tel - where - hed = take n s - tel = drop n s - -convertToU :: [Char] -> [Char] -> Atom -> String -convertToU baseMap prefix = go [] - where - go acc 0 = "0" <> prefix <> uTypeAddDots 5 acc - go acc n = go (char n : acc) (n `div` len) - - char n = baseMap !! (fromIntegral (n `mod` len)) - - len = fromIntegral (length baseMap) - -convertFromU :: (Char -> Maybe Atom) -> Char -> Atom -> String -> Maybe Atom -convertFromU fetch prefix length = \case - ('0':prefix:cs) -> go (0, 0) (reverse cs) - _ -> Nothing - where - go (i, acc) [] = pure acc - go (i, acc) ('.' : cs) = go (i, acc) cs - go (i, acc) (c : cs) = do - n <- fetch c - go (i+1, acc+(length^i)*n) cs - - --- @uv -newtype UV = UV { unUV :: Atom } - deriving newtype (Eq, Ord, Show, Num, Enum, Real, Integral) - -instance ToNoun UV where - toNoun = toNoun . Cord . pack . toUV . fromIntegral . unUV - -instance FromNoun UV where - parseNoun n = do - Cord c <- parseNoun n - case fromUV $ unpack c of - Nothing -> fail ("Invalid @uv: " <> unpack c) - Just uv -> pure (UV uv) - -fromUV :: String -> Maybe Atom -fromUV = convertFromU uvCharNum 'v' (fromIntegral $ length base32Chars) - -toUV :: Atom -> String -toUV = convertToU base32Chars "v" - -base32Chars :: [Char] -base32Chars = (['0'..'9'] <> ['a'..'v']) - -uvCharNum :: Char -> Maybe Atom -uvCharNum = \case - '0' -> pure 0 - '1' -> pure 1 - '2' -> pure 2 - '3' -> pure 3 - '4' -> pure 4 - '5' -> pure 5 - '6' -> pure 6 - '7' -> pure 7 - '8' -> pure 8 - '9' -> pure 9 - 'a' -> pure 10 - 'b' -> pure 11 - 'c' -> pure 12 - 'd' -> pure 13 - 'e' -> pure 14 - 'f' -> pure 15 - 'g' -> pure 16 - 'h' -> pure 17 - 'i' -> pure 18 - 'j' -> pure 19 - 'k' -> pure 20 - 'l' -> pure 21 - 'm' -> pure 22 - 'n' -> pure 23 - 'o' -> pure 24 - 'p' -> pure 25 - 'q' -> pure 26 - 'r' -> pure 27 - 's' -> pure 28 - 't' -> pure 29 - 'u' -> pure 30 - 'v' -> pure 31 - _ -> Nothing - --------------------------------------------------------------------------------- - --- @uw -newtype UW = UW { unUW :: Atom } - deriving newtype (Eq, Ord, Show, Num, Enum, Real, Integral) - -instance ToNoun UW where - toNoun = toNoun . Cord . pack . toUW . fromIntegral . unUW - -instance FromNoun UW where - parseNoun n = do - Cord c <- parseNoun n - case fromUW $ unpack c of - Nothing -> fail ("Invalid @uw: " <> unpack c) - Just uw -> pure (UW uw) - -fromUW :: String -> Maybe Atom -fromUW = convertFromU uwCharNum 'w' (fromIntegral $ length base64Chars) - -toUW :: Atom -> String -toUW = convertToU base64Chars "w" - -base64Chars :: [Char] -base64Chars = (['0'..'9'] <> ['a'..'z'] <> ['A'..'Z'] <> ['-', '~']) - -uwCharNum :: Char -> Maybe Atom -uwCharNum = \case - '0' -> pure 0 - '1' -> pure 1 - '2' -> pure 2 - '3' -> pure 3 - '4' -> pure 4 - '5' -> pure 5 - '6' -> pure 6 - '7' -> pure 7 - '8' -> pure 8 - '9' -> pure 9 - 'a' -> pure 10 - 'b' -> pure 11 - 'c' -> pure 12 - 'd' -> pure 13 - 'e' -> pure 14 - 'f' -> pure 15 - 'g' -> pure 16 - 'h' -> pure 17 - 'i' -> pure 18 - 'j' -> pure 19 - 'k' -> pure 20 - 'l' -> pure 21 - 'm' -> pure 22 - 'n' -> pure 23 - 'o' -> pure 24 - 'p' -> pure 25 - 'q' -> pure 26 - 'r' -> pure 27 - 's' -> pure 28 - 't' -> pure 29 - 'u' -> pure 30 - 'v' -> pure 31 - 'w' -> pure 32 - 'x' -> pure 33 - 'y' -> pure 34 - 'z' -> pure 35 - 'A' -> pure 36 - 'B' -> pure 37 - 'C' -> pure 38 - 'D' -> pure 39 - 'E' -> pure 40 - 'F' -> pure 41 - 'G' -> pure 42 - 'H' -> pure 43 - 'I' -> pure 44 - 'J' -> pure 45 - 'K' -> pure 46 - 'L' -> pure 47 - 'M' -> pure 48 - 'N' -> pure 49 - 'O' -> pure 50 - 'P' -> pure 51 - 'Q' -> pure 52 - 'R' -> pure 53 - 'S' -> pure 54 - 'T' -> pure 55 - 'U' -> pure 56 - 'V' -> pure 57 - 'W' -> pure 58 - 'X' -> pure 59 - 'Y' -> pure 60 - 'Z' -> pure 61 - '-' -> pure 62 - '~' -> pure 63 - _ -> Nothing - --- Maybe parses the underlying atom value from a text printed in UW format. -cordToUW :: Cord -> Maybe UW -cordToUW = fromNoun . toNoun - --- Char ------------------------------------------------------------------------ - -instance ToNoun Char where - toNoun = Atom . fromIntegral . C.ord - -{- - Hack: pulled this logic from Data.Char impl. --} -instance FromNoun Char where - parseNoun n = named "Char" $ do - W32# w :: Word32 <- parseNoun n - if isTrue# (w `leWord#` 0x10FFFF##) - then pure (C# (chr# (word2Int# w))) - else fail "Word is not a valid character." - - --- Tour ------------------------------------------------------------------------ - -newtype Tour = Tour [Char] - deriving newtype (Eq, Ord, Show, ToNoun, FromNoun) - - --- Double Jammed --------------------------------------------------------------- - -newtype Jammed a = Jammed a - deriving (Eq, Ord, Show) - -instance ToNoun a => ToNoun (Jammed a) where - toNoun (Jammed a) = Atom $ jam $ toNoun a - -instance FromNoun a => FromNoun (Jammed a) where - parseNoun n = named "Jammed" $ do - a <- parseNoun n - cue a & \case - Left err -> fail (show err) - Right res -> do - Jammed <$> parseNoun res - - --- Atom or Cell ---------------------------------------------------------------- - -type Word512 = LargeKey Word256 Word256 - -data AtomCell a c - = ACAtom a - | ACCell c - deriving (Eq, Ord, Show) - -instance (ToNoun a, ToNoun c) => ToNoun (AtomCell a c) where - toNoun (ACAtom a) = toNoun a - toNoun (ACCell c) = toNoun c - -instance (FromNoun a, FromNoun c) => FromNoun (AtomCell a c) where - parseNoun n = named "(,)" $ case n of - Atom _ -> ACAtom <$> parseNoun n - Cell _ _ -> ACCell <$> parseNoun n - - --- Lenient --------------------------------------------------------------------- - -data Lenient a - = FailParse Noun - | GoodParse a - deriving (Eq, Ord, Show) - -instance FromNoun a => FromNoun (Lenient a) where - parseNoun n = - (GoodParse <$> parseNoun n) <|> fallback - where - fallback = - fromNounErr n & \case - Right x -> pure (GoodParse x) - Left err -> do - -- traceM ("LENIENT.FromNoun: " <> show err) - -- traceM (ppShow n) - pure (FailParse n) - -instance ToNoun a => ToNoun (Lenient a) where - toNoun (FailParse n) = n -- trace ("LENIENT.ToNoun: " <> show n) - toNoun (GoodParse x) = toNoun x - - --- Todo -- Debugging Hack ------------------------------------------------------ - -newtype Todo a = Todo a - deriving newtype (Eq, Ord, ToNoun) - -instance Show (Todo a) where - show (Todo _) = "TODO" - -instance FromNoun a => FromNoun (Todo a) where - parseNoun n = do - fromNounErr n & \case - Right x -> pure (Todo x) - Left er -> fail (show er) - -- traceM ("[TODO]: " <> show er <> "\n" <> ppShow n <> "\n") - - --- Nullable -------------------------------------------------------------------- - -{-| - `Nullable a <-> ?@(~ a)` - - This is distinct from `unit`, since there is no tag on the non-atom - case, therefore `a` must always be cell type. --} -data Nullable a = None | Some a - deriving (Eq, Ord, Show) - -instance ToNoun a => ToNoun (Nullable a) where - toNoun = toNoun . \case None -> ACAtom () - Some x -> ACCell x - -instance FromNoun a => FromNoun (Nullable a) where - parseNoun n = named "Nullable" $ do - parseNoun n >>= \case - (ACAtom ()) -> pure None - (ACCell x) -> pure (Some x) - - --- List ------------------------------------------------------------------------ - -instance ToNoun a => ToNoun [a] where - toNoun xs = nounFromList (toNoun <$> xs) - where - nounFromList :: [Noun] -> Noun - nounFromList [] = Atom 0 - nounFromList (x:xs) = Cell x (nounFromList xs) - -instance FromNoun a => FromNoun [a] where - parseNoun = named "[]" . \case - Atom 0 -> pure [] - Atom _ -> fail "list terminated with non-null atom" - Cell l r -> (:) <$> parseNoun l <*> parseNoun r - - --- Tape ------------------------------------------------------------------------ - -{- - A `tape` is a list of utf8 bytes. --} -newtype Tape = Tape { unTape :: Text } - deriving newtype (Eq, Ord, Show, Semigroup, Monoid, IsString) - -instance ToNoun Tape where - toNoun = toNoun . (unpack :: ByteString -> [Word8]) . encodeUtf8 . unTape - -instance FromNoun Tape where - parseNoun n = named "Tape" $ do - as :: [Word8] <- parseNoun n - T.decodeUtf8' (pack as) & \case - Left err -> fail (show err) - Right tx -> pure (Tape tx) - - --- Wain -- List of Lines ------------------------------------------------------- - -newtype Wain = Wain { unWain :: Text } - deriving newtype (Eq, Ord, Show, IsString, NFData) - -instance ToNoun Wain where - toNoun (Wain t) = toNoun (Cord <$> lines t) - -instance FromNoun Wain where - parseNoun n = named "Wain" $ do - tx :: [Cord] <- parseNoun n - pure $ Wain $ unlines (unCord <$> tx) - - --- Wall -- Text Lines ---------------------------------------------------------- - -type Wall = [Tape] - - --- Big Cord -- Don't Print ----------------------------------------------------- - -newtype BigCord = BigCord Cord - deriving newtype (Eq, Ord, ToNoun, FromNoun, IsString) - -instance Show BigCord where - show (BigCord (Cord t)) = show (take 32 t <> "...") - - --- Big Tape -- Don't Print ----------------------------------------------------- - -newtype BigTape = BigTape Tape - deriving newtype (Eq, Ord, ToNoun, FromNoun, IsString) - -instance Show BigTape where - show (BigTape (Tape t)) = show (take 32 t <> "...") - - --- Bytes ----------------------------------------------------------------------- - -newtype Bytes = MkBytes { unBytes :: ByteString } - deriving newtype (Eq, Ord, Show, IsString) - -instance ToNoun Bytes where - toNoun = Atom . bytesAtom . unBytes - -instance FromNoun Bytes where - parseNoun = named "Bytes" . fmap (MkBytes . atomBytes) . parseNoun - - --- Octs ------------------------------------------------------------------------ - -newtype Octs = Octs { unOcts :: ByteString } - deriving newtype (Eq, Ord, Show, IsString) - -instance ToNoun Octs where - toNoun (Octs bs) = - toNoun (int2Word (length bs), bytesAtom bs) - where - int2Word :: Int -> Word - int2Word = fromIntegral - -instance FromNoun Octs where - parseNoun x = named "Octs" $ do - (word2Int -> len, atom) <- parseNoun x - let bs = atomBytes atom - pure $ Octs $ case compare (length bs) len of - EQ -> bs - LT -> bs <> replicate (len - length bs) 0 - GT -> take len bs - where - word2Int :: Word -> Int - word2Int = fromIntegral - - --- File Contents -- Don't Print ------------------------------------------------ - -newtype File = File { unFile :: Octs } - deriving newtype (Eq, Ord, IsString, ToNoun, FromNoun) - -instance Show File where - show (File (Octs bs)) = show (take 32 bs <> "...") - - --- Knot ------------------------------------------------------------------------ - -{- - Knot (@ta) is an array of Word8 encoding an ASCII string. --} -newtype Knot = MkKnot { unKnot :: Text } - deriving newtype (Eq, Ord, Show, Semigroup, Monoid, IsString) - -instance ToNoun Knot where - toNoun = textToUtf8Atom . unKnot - -instance FromNoun Knot where - parseNoun n = named "Knot" $ do - txt <- parseNounUtf8Atom n - if all C.isAscii txt - then pure (MkKnot txt) - else fail ("Non-ASCII chars in knot: " <> unpack txt) - --- equivalent of (cury scot %t) -textAsT :: Text -> Text -textAsT = ("~~" <>) . concatMap \case - ' ' -> "." - '.' -> "~." - '~' -> "~~" - c -> - if (C.isAlphaNum c && not (C.isUpper c)) || (c == '-') then - T.singleton c - else - if C.ord c < 0x10 then "~0" else "~" - <> (pack $ N.showHex (C.ord c) ".") - --- Term ------------------------------------------------------------------------ - -{- - A Term (@tas) is a Knot satisfying the regular expression: - - ([a-z][a-z0-9]*(-[a-z0-9]+)*)? --} -newtype Term = MkTerm { unTerm :: Text } - deriving newtype (Eq, Ord, Show, Semigroup, Monoid, IsString) - -instance ToNoun Term where -- XX TODO - toNoun = textToUtf8Atom . unTerm - -knotRegex :: Text -knotRegex = "([a-z][a-z0-9]*(-[a-z0-9]+)*)?" - -instance FromNoun Term where -- XX TODO - parseNoun n = named "Term" $ do - MkKnot t <- parseNoun n - if t =~ knotRegex - then pure (MkTerm t) - else fail ("Term not valid symbol: " <> unpack t) - - --- Ship ------------------------------------------------------------------------ - -newtype Ship = Ship Word128 -- @p - deriving newtype (Eq, Ord, Enum, Real, Integral, Num, ToNoun, FromNoun) - -instance Show Ship where - show = show . patp . fromIntegral - -instance Hashable Ship where - hashWithSalt s (Ship (LargeKey a b)) = s `hashWithSalt` a `hashWithSalt` b - - --- Path ------------------------------------------------------------------------ - -newtype Path = Path { unPath :: [Knot] } - deriving newtype (Eq, Ord, Semigroup, Monoid) - -instance Show Path where - show = show . intercalate "/" . ("":) . unPath - -newtype EvilPath = EvilPath { unEvilPath :: [Atom] } - deriving newtype (Eq, Ord, Semigroup, Monoid) - -instance Show EvilPath where - show = show . unEvilPath - -pathToFilePath :: Path -> FilePath -pathToFilePath p = joinPath components - where - elements :: [String] = map (unpack . unKnot) (unPath p) - components = case reverse elements of - [] -> [] - [p] -> [p] - (ext : fname : dirs) -> (reverse dirs) <> [(fname <.> ext)] - --- Takes a filepath and converts it to a clay path, changing the '.' to a '/' --- and removing any prefixed '/'. -filePathToPath :: FilePath -> Path -filePathToPath fp = Path path - where - path = map (MkKnot . pack) (dir ++ file) - dir = case (splitDirectories $ (takeDirectory fp)) of - ["."] -> [] - ("/":xs) -> xs - x -> x - file = if ext /= "" then [takeBaseName fp, ext] else [takeBaseName fp] - ext = case takeExtension fp of - ('.':xs) -> xs - x -> x - - --- Bool ------------------------------------------------------------------------ - -instance ToNoun Bool where - toNoun True = Atom 0 - toNoun False = Atom 1 - -instance FromNoun Bool where - parseNoun = named "Bool" . parse - where - parse n = - parseNoun n >>= \case - (0::Atom) -> pure True - 1 -> pure False - _ -> fail "Atom is not a valid loobean" - - --- Integer --------------------------------------------------------------------- - -instance ToNoun Integer where - toNoun = toNoun . (fromIntegral :: Integer -> Natural) - -instance FromNoun Integer where - parseNoun = named "Integer" . fmap natInt . parseNoun - where - natInt :: Natural -> Integer - natInt = fromIntegral - - --- Words ----------------------------------------------------------------------- - -atomToWord :: forall a. (Bounded a, Integral a) => Atom -> Parser a -atomToWord atom = do - if atom > fromIntegral (maxBound :: a) - then fail "Atom doesn't fit in fixed-size word" - else pure (fromIntegral atom) - -wordToNoun :: Integral a => a -> Noun -wordToNoun = Atom . fromIntegral - -nounToWord :: forall a. (Bounded a, Integral a) => Noun -> Parser a -nounToWord = parseNoun >=> atomToWord - -instance ToNoun Word where toNoun = wordToNoun -instance ToNoun Word8 where toNoun = wordToNoun -instance ToNoun Word16 where toNoun = wordToNoun -instance ToNoun Word32 where toNoun = wordToNoun -instance ToNoun Word64 where toNoun = wordToNoun -instance ToNoun Word128 where toNoun = wordToNoun -instance ToNoun Word256 where toNoun = wordToNoun -instance ToNoun Word512 where toNoun = wordToNoun - -instance FromNoun Word where parseNoun = named "Word" . nounToWord -instance FromNoun Word8 where parseNoun = named "Word8" . nounToWord -instance FromNoun Word16 where parseNoun = named "Word16" . nounToWord -instance FromNoun Word32 where parseNoun = named "Word32" . nounToWord -instance FromNoun Word64 where parseNoun = named "Word64" . nounToWord -instance FromNoun Word128 where parseNoun = named "Word128" . nounToWord -instance FromNoun Word256 where parseNoun = named "Word256" . nounToWord -instance FromNoun Word512 where parseNoun = named "Word512" . nounToWord - - --- Maybe is `unit` ------------------------------------------------------------- - --- TODO Consider enforcing that `a` must be a cell. -instance ToNoun a => ToNoun (Maybe a) where - toNoun Nothing = Atom 0 - toNoun (Just x) = Cell (Atom 0) (toNoun x) - -instance FromNoun a => FromNoun (Maybe a) where - parseNoun = named "Maybe" . \case - Atom 0 -> pure Nothing - Atom n -> unexpected ("atom " <> show n) - Cell (Atom 0) t -> Just <$> parseNoun t - Cell n _ -> unexpected ("cell with head-atom " <> show n) - where - unexpected s = fail ("Expected unit value, but got " <> s) - --- Each is a direct translation of Hoon +each, preserving order -data Each a b - = EachYes a - | EachNo b - deriving (Eq, Ord, Show) - -instance (ToNoun a, ToNoun b) => ToNoun (Each a b) where - toNoun (EachYes x) = C (A 0) (toNoun x) - toNoun (EachNo x) = C (A 1) (toNoun x) - -instance (FromNoun a, FromNoun b) => FromNoun (Each a b) where - parseNoun n = named "Each" $ do - (Atom tag, v) <- parseNoun n - case tag of - 0 -> named "&" (EachYes <$> parseNoun v) - 1 -> named "|" (EachNo <$> parseNoun v) - n -> fail ("Each has invalid head-atom: " <> show n) - - --- Tuple Conversions ----------------------------------------------------------- - -instance ToNoun () where - toNoun () = Atom 0 - -instance FromNoun () where - parseNoun = named "()" . \case - Atom 0 -> pure () - x -> fail ("expecting `~`, but got " <> show x) - -instance (ToNoun a, ToNoun b) => ToNoun (a, b) where - toNoun (x, y) = Cell (toNoun x) (toNoun y) - - -shortRec :: Word -> Parser a -shortRec 0 = fail "expected a record, but got an atom" -shortRec 1 = fail ("record too short, only one cell") -shortRec n = fail ("record too short, only " <> show n <> " cells") - -instance (FromNoun a, FromNoun b) => FromNoun (a, b) where - parseNoun n = named ("(,)") $ do - case n of - A _ -> shortRec 0 - C x y -> do - (,) <$> named "1" (parseNoun x) - <*> named "2" (parseNoun y) - -instance (ToNoun a, ToNoun b, ToNoun c) => ToNoun (a, b, c) where - toNoun (x, y, z) = toNoun (x, (y, z)) - -instance (FromNoun a, FromNoun b, FromNoun c) => FromNoun (a, b, c) where - parseNoun n = named "(,,)" $ do - case n of - A _ -> shortRec 0 - C x (A _) -> shortRec 1 - C x (C y z) -> - (,,) <$> named "1" (parseNoun x) - <*> named "2" (parseNoun y) - <*> named "3" (parseNoun z) - -instance (ToNoun a, ToNoun b, ToNoun c, ToNoun d) => ToNoun (a, b, c, d) where - toNoun (p, q, r, s) = toNoun (p, (q, r, s)) - -instance (FromNoun a, FromNoun b, FromNoun c, FromNoun d) - => FromNoun (a, b, c, d) - where - parseNoun n = named "(,,,)" $ do - case n of - A _ -> shortRec 0 - C _ (A _) -> shortRec 1 - C _ (C _ (A _)) -> shortRec 2 - C p (C q (C r s)) -> - (,,,) <$> named "1" (parseNoun p) - <*> named "2" (parseNoun q) - <*> named "3" (parseNoun r) - <*> named "4" (parseNoun s) - -instance (ToNoun a, ToNoun b, ToNoun c, ToNoun d, ToNoun e) - => ToNoun (a, b, c, d, e) where - toNoun (p, q, r, s, t) = toNoun (p, (q, r, s, t)) - -instance (FromNoun a, FromNoun b, FromNoun c, FromNoun d, FromNoun e) - => FromNoun (a, b, c, d, e) - where - parseNoun n = named "(,,,,)" $ do - case n of - A _ -> shortRec 0 - C _ (A _) -> shortRec 1 - C _ (C _ (A _)) -> shortRec 2 - C _ (C _ (C _ (A _))) -> shortRec 3 - C p (C q (C r (C s t))) -> - (,,,,) <$> named "1" (parseNoun p) - <*> named "2" (parseNoun q) - <*> named "3" (parseNoun r) - <*> named "4" (parseNoun s) - <*> named "5" (parseNoun t) - -instance (ToNoun a, ToNoun b, ToNoun c, ToNoun d, ToNoun e, ToNoun f) - => ToNoun (a, b, c, d, e, f) where - toNoun (p, q, r, s, t, u) = toNoun (p, (q, r, s, t, u)) - -instance ( FromNoun a, FromNoun b, FromNoun c, FromNoun d, FromNoun e - , FromNoun f - ) - => FromNoun (a, b, c, d, e, f) - where - parseNoun n = named "(,,,,,)" $ do - (p, tail) <- parseNoun n - (q, r, s, t, u) <- parseNoun tail - pure (p, q, r, s, t, u) - -instance (ToNoun a, ToNoun b, ToNoun c, ToNoun d, ToNoun e, ToNoun f, ToNoun g) - => ToNoun (a, b, c, d, e, f, g) where - toNoun (p, q, r, s, t, u, v) = toNoun (p, (q, r, s, t, u, v)) - -instance ( FromNoun a, FromNoun b, FromNoun c, FromNoun d, FromNoun e - , FromNoun f, FromNoun g - ) - => FromNoun (a, b, c, d, e, f, g) - where - parseNoun n = named "(,,,,,,)" $ do - (p, tail) <- parseNoun n - (q, r, s, t, u, v) <- parseNoun tail - pure (p, q, r, s, t, u, v) - -instance ( ToNoun a, ToNoun b, ToNoun c, ToNoun d, ToNoun e, ToNoun f, ToNoun g - , ToNoun h - ) - => ToNoun (a, b, c, d, e, f, g, h) where - toNoun (p, q, r, s, t, u, v, w) = toNoun (p, (q, r, s, t, u, v, w)) - -instance ( FromNoun a, FromNoun b, FromNoun c, FromNoun d, FromNoun e - , FromNoun f, FromNoun g, FromNoun h - ) - => FromNoun (a, b, c, d, e, f, g, h) - where - parseNoun n = named "(,,,,,,,)" $ do - (p, tail) <- parseNoun n - (q, r, s, t, u, v, w) <- parseNoun tail - pure (p, q, r, s, t, u, v, w) - -instance ( ToNoun a, ToNoun b, ToNoun c, ToNoun d, ToNoun e, ToNoun f, ToNoun g - , ToNoun h, ToNoun i - ) - => ToNoun (a, b, c, d, e, f, g, h, i) where - toNoun (p, q, r, s, t, u, v, w, x) = toNoun (p, (q, r, s, t, u, v, w, x)) - -instance ( FromNoun a, FromNoun b, FromNoun c, FromNoun d, FromNoun e - , FromNoun f, FromNoun g, FromNoun h, FromNoun i - ) - => FromNoun (a, b, c, d, e, f, g, h, i) - where - parseNoun n = named "(,,,,,,,,)" $ do - (p, tail) <- parseNoun n - (q, r, s, t, u, v, w, x) <- parseNoun tail - pure (p, q, r, s, t, u, v, w, x) - -instance ( ToNoun a, ToNoun b, ToNoun c, ToNoun d, ToNoun e, ToNoun f, ToNoun g - , ToNoun h, ToNoun i, ToNoun j - ) - => ToNoun (a, b, c, d, e, f, g, h, i, j) where - toNoun (p, q, r, s, t, u, v, w, x, y) = - toNoun (p, (q, r, s, t, u, v, w, x, y)) - -instance ( FromNoun a, FromNoun b, FromNoun c, FromNoun d, FromNoun e - , FromNoun f, FromNoun g, FromNoun h, FromNoun i, FromNoun j - ) - => FromNoun (a, b, c, d, e, f, g, h, i, j) - where - parseNoun n = named "(,,,,,,,,,)" $ do - (p, tail) <- parseNoun n - (q, r, s, t, u, v, w, x, y) <- parseNoun tail - pure (p, q, r, s, t, u, v, w, x, y) - - --- Ugg ------------------------------------------------------------------------- - -deriveNoun ''Path -deriveNoun ''EvilPath diff --git a/pkg/hs/urbit-noun/lib/Urbit/Noun/Tank.hs b/pkg/hs/urbit-noun/lib/Urbit/Noun/Tank.hs deleted file mode 100644 index 9dbbdf2f9..000000000 --- a/pkg/hs/urbit-noun/lib/Urbit/Noun/Tank.hs +++ /dev/null @@ -1,303 +0,0 @@ -{-| - Pretty Printer Types --} - -module Urbit.Noun.Tank where - -import ClassyPrelude -import Urbit.Noun.Conversions -import Urbit.Noun.TH -import Urbit.Noun.Convert -import Urbit.Noun.Core - --------------------------------------------------------------------------------- - -type Tang = [Tank] - -data TankTree - = Leaf Tape - | Plum Plum - | Palm (Tape, Tape, Tape, Tape) [TankTree] - | Rose (Tape, Tape, Tape) [TankTree] - deriving (Eq, Ord, Show) - -newtype Tank = Tank { tankTree :: TankTree } - deriving newtype (Eq, Ord, Show) - -instance ToNoun Tank where - toNoun (Tank t) = toNoun t - -instance FromNoun Tank where - parseNoun n@(Atom _) = do - Cord txt <- parseNoun n - pure $ Tank $ Leaf $ Tape txt - parseNoun n = Tank <$> parseNoun n - -data WideFmt = WideFmt { delimit :: Cord, enclose :: Maybe (Cord, Cord) } - deriving (Eq, Ord, Show) - -data TallFmt = TallFmt { intro :: Cord, indef :: Maybe (Cord, Cord) } - deriving (Eq, Ord, Show) - -data PlumFmt = PlumFmt (Maybe WideFmt) (Maybe TallFmt) - deriving (Eq, Ord, Show) - -type Plum = AtomCell Cord PlumTree - -data PlumTree - = Para Cord [Cord] - | Tree PlumFmt [Plum] - | Sbrk Plum - deriving (Eq, Ord, Show) - -deriveNoun ''WideFmt -deriveNoun ''TallFmt -deriveNoun ''PlumFmt -deriveNoun ''TankTree -deriveNoun ''PlumTree - --------------------------------------------------------------------------------- - -data WashCfg = WashCfg - { wcIndent :: Word - , wcWidth :: Word - } - --------------------------------------------------------------------------------- - -wash :: WashCfg -> TankTree -> Wall -wash _cfg t = [ram t] - --- win :: WashCfg -> Tank -> Wall --- win = undefined - -flat :: Plum -> Tape -flat = Tape . tshow - -ram :: TankTree -> Tape -ram = \case - Leaf tape -> tape - Plum plum -> flat plum - Palm (p,q,r,s) kids -> ram (Rose (p, q<>r, s) kids) - Rose (p,q,r) kids -> q <> loop kids - where - loop [] = r - loop [x] = ram x <> r - loop (x:xs) = ram x <> p <> loop xs - -tankToText :: Tank -> Text -tankToText (Tank t) = unlines $ fmap unTape $ wash (WashCfg 0 80) t - -textToTank :: Text -> Tank -textToTank = Tank . Leaf . Tape - -{- - ++ win - |= {tab/@ edg/@} - =. tac (act:ug tac) - %- fix:ug - =+ lug=`wall`~ - |^ |- ^- wall - ?- -.tac - $leaf (rig p.tac) - $plum (turn ~(tall plume p.tac) |=(=cord (trip cord))) - $palm - ?: fit - (rig ram) - ?~ q.tac - (rig q.p.tac) - ?~ t.q.tac - (rig(tab (add 2 tab), lug $(tac i.q.tac)) q.p.tac) - => .(q.tac `(list tank)`q.tac) - =+ lyn=(mul 2 (lent q.tac)) - =+ ^= qyr - |- ^- wall - ?~ q.tac - lug - %= ^$ - tac i.q.tac - tab (add tab (sub lyn 2)) - lug $(q.tac t.q.tac, lyn (sub lyn 2)) - == - (wig(lug qyr) q.p.tac) - :: - $rose - ?: fit - (rig ram) - =. lug - |- ^- wall - ?~ q.tac - ?:(=(~ r.p.tac) lug (rig r.p.tac)) - ^$(tac i.q.tac, lug $(q.tac t.q.tac), tab din) - ?: =(~ q.p.tac) - lug - (wig q.p.tac) - == - :: - ++ din (mod (add 2 tab) (mul 2 (div edg 3))) - ++ fit (lte (lent ram) (sub edg tab)) - ++ rig - |= hom/tape - ^- wall - ?: (lte (lent hom) (sub edg tab)) - [(runt [tab ' '] hom) lug] - => .(tab (add tab 2), edg (sub edg 2)) - =+ mut=(trim (sub edg tab) hom) - :- (runt [(sub tab 2) ' '] ['\\' '/' (weld p.mut `_hom`['\\' '/' ~])]) - => .(hom q.mut) - |- - ?~ hom - :- %+ runt - [(sub tab 2) ' '] - ['\\' '/' (runt [(sub edg tab) ' '] ['\\' '/' ~])] - lug - => .(mut (trim (sub edg tab) hom)) - [(runt [tab ' '] p.mut) $(hom q.mut)] - :: - ++ wig - |= hom/tape - ^- wall - ?~ lug - (rig hom) - =+ lin=(lent hom) - =+ wug=:(add 1 tab lin) - ?. =+ mir=i.lug - |- ?~ mir - | - ?|(=(0 wug) ?&(=(' ' i.mir) $(mir t.mir, wug (dec wug)))) - (rig hom) :: ^ XX regular form? - [(runt [tab ' '] (weld hom `tape`[' ' (slag wug i.lug)])) t.lug] - -- - -- --} - -{- -++ re - |_ tac/tank - ++ ram - ^- tape - ?- -.tac - $leaf p.tac - $plum ~(flat plume p.tac) - $palm ram(tac [%rose [p.p.tac (weld q.p.tac r.p.tac) s.p.tac] q.tac]) - $rose - %+ weld - q.p.tac - |- ^- tape - ?~ q.tac - r.p.tac - =+ voz=$(q.tac t.q.tac) - (weld ram(tac i.q.tac) ?~(t.q.tac voz (weld p.p.tac voz))) - == - :: - ++ ug :: horrible hack - |% - ++ ace :: strip ctrl chars - |= a=tape - ^- tape - ?~ a ~ - ?: |((lth i.a 32) =(127 `@`i.a)) - $(a t.a) - [i.a $(a t.a)] - :: - ++ act :: pretend tapes - |= tac=tank - ^- tank - ?- -.tac - %leaf [%leaf (hew p.tac)] - %plum tac :: XX consider - %palm :+ %palm - [(hew p.p.tac) (hew q.p.tac) (hew r.p.tac) (hew s.p.tac)] - (turn q.tac act) - %rose :+ %rose - [(hew p.p.tac) (hew q.p.tac) (hew r.p.tac)] - (turn q.tac act) - == - :: - ++ fix :: restore tapes - |= wol=wall - %+ turn wol - |=(a=tape (tufa `(list @c)``(list @)`a)) - :: - ++ hew :: pretend tape - |=(a=tape `tape``(list @)`(tuba (ace a))) - -- - :: - ++ win - |= {tab/@ edg/@} - =. tac (act:ug tac) - %- fix:ug - =+ lug=`wall`~ - |^ |- ^- wall - ?- -.tac - $leaf (rig p.tac) - $plum (turn ~(tall plume p.tac) |=(=cord (trip cord))) - $palm - ?: fit - (rig ram) - ?~ q.tac - (rig q.p.tac) - ?~ t.q.tac - (rig(tab (add 2 tab), lug $(tac i.q.tac)) q.p.tac) - => .(q.tac `(list tank)`q.tac) - =+ lyn=(mul 2 (lent q.tac)) - =+ ^= qyr - |- ^- wall - ?~ q.tac - lug - %= ^$ - tac i.q.tac - tab (add tab (sub lyn 2)) - lug $(q.tac t.q.tac, lyn (sub lyn 2)) - == - (wig(lug qyr) q.p.tac) - :: - $rose - ?: fit - (rig ram) - =. lug - |- ^- wall - ?~ q.tac - ?:(=(~ r.p.tac) lug (rig r.p.tac)) - ^$(tac i.q.tac, lug $(q.tac t.q.tac), tab din) - ?: =(~ q.p.tac) - lug - (wig q.p.tac) - == - :: - ++ din (mod (add 2 tab) (mul 2 (div edg 3))) - ++ fit (lte (lent ram) (sub edg tab)) - ++ rig - |= hom/tape - ^- wall - ?: (lte (lent hom) (sub edg tab)) - [(runt [tab ' '] hom) lug] - => .(tab (add tab 2), edg (sub edg 2)) - =+ mut=(trim (sub edg tab) hom) - :- (runt [(sub tab 2) ' '] ['\\' '/' (weld p.mut `_hom`['\\' '/' ~])]) - => .(hom q.mut) - |- - ?~ hom - :- %+ runt - [(sub tab 2) ' '] - ['\\' '/' (runt [(sub edg tab) ' '] ['\\' '/' ~])] - lug - => .(mut (trim (sub edg tab) hom)) - [(runt [tab ' '] p.mut) $(hom q.mut)] - :: - ++ wig - |= hom/tape - ^- wall - ?~ lug - (rig hom) - =+ lin=(lent hom) - =+ wug=:(add 1 tab lin) - ?. =+ mir=i.lug - |- ?~ mir - | - ?|(=(0 wug) ?&(=(' ' i.mir) $(mir t.mir, wug (dec wug)))) - (rig hom) :: ^ XX regular form? - [(runt [tab ' '] (weld hom `tape`[' ' (slag wug i.lug)])) t.lug] - -- - -- --} diff --git a/pkg/hs/urbit-noun/lib/Urbit/Noun/Time.hs b/pkg/hs/urbit-noun/lib/Urbit/Noun/Time.hs deleted file mode 100644 index 1976c11a5..000000000 --- a/pkg/hs/urbit-noun/lib/Urbit/Noun/Time.hs +++ /dev/null @@ -1,165 +0,0 @@ -{-| - TODO This is slow. --} - -module Urbit.Noun.Time where - -import Control.Lens -import Prelude - -import Data.Bits (shiftL, shiftR, (.&.)) -import Data.List (intercalate) -import Data.Time.Calendar (toGregorian) -import Data.Time.Clock (DiffTime, UTCTime(..)) -import Data.Time.Clock (diffTimeToPicoseconds, picosecondsToDiffTime) -import Data.Time.Clock.System (SystemTime(..), getSystemTime) -import Data.Time.Clock.System (systemToUTCTime, utcToSystemTime) -import Data.Time.LocalTime (TimeOfDay(..), timeToTimeOfDay) -import Data.Word (Word64) -import Text.Printf (printf) -import Urbit.Noun (deriveToNoun, FromNoun, ToNoun(..)) - - --- Types ----------------------------------------------------------------------- - -newtype Gap = Gap { _fractoSecs :: Integer } - deriving newtype (Eq, Ord, Show, Num, FromNoun) - -newtype Unix = Unix { _sinceUnixEpoch :: Gap } - deriving newtype (Eq, Ord, Show, FromNoun) - -newtype Wen = Wen { _sinceUrbitEpoch :: Gap } - deriving newtype (Eq, Ord, Show, Num, FromNoun) - -newtype Date = MkDate { _dateWen :: Wen } - deriving newtype (Eq, Ord, Num, FromNoun) - - --- Record Lenses --------------------------------------------------------------- - -makeLenses ''Gap -makeLenses ''Unix -makeLenses ''Wen -makeLenses ''Date - - --- Instances ------------------------------------------------------------------- - -instance ToNoun Gap where - toNoun (reducePrecision -> Gap fs) = toNoun fs - --- | Produce a Gap with fewer digits after the binary point, more --- appropriately capturing the precision our clock gives us. -reducePrecision :: Gap -> Gap -reducePrecision (Gap fs) = Gap (chop fs) - where - chop fs = shiftL (shiftR fs 32) 32 - -deriveToNoun ''Unix -deriveToNoun ''Wen -deriveToNoun ''Date - -instance Show Date where - show (MkDate wen) = if fs == 0 - then printf "~%i.%u.%u..%02u.%02u.%02u" y m d h min s - else printf "~%i.%u.%u..%02u.%02u.%02u..%s" y m d h min s (showGap fs) - where - utc = wen ^. systemTime . to systemToUTCTime - (y, m, d) = toGregorian (utctDay utc) - TimeOfDay h min (floor -> s::Int) = timeToTimeOfDay (utctDayTime utc) - fs = (wen ^. wenFracto . to (fromIntegral @Integer @Word64)) - - wenFracto :: Lens' Wen Integer - wenFracto = sinceUrbitEpoch . fractoSecs - - showGap :: Word64 -> String - showGap gap = intercalate "." (printf "%04x" <$> bs) - where - bs = reverse $ dropWhile (== 0) [b4, b3, b2, b1] - b4 = takeBits 16 gap - b3 = takeBits 16 (shiftR gap 16) - b2 = takeBits 16 (shiftR gap 32) - b1 = takeBits 16 (shiftR gap 48) - - takeBits :: Int -> Word64 -> Word64 - takeBits wid wor = wor .&. (shiftL 1 wid - 1) - - --- Conversion Lenses ----------------------------------------------------------- - -diffTime :: Iso' Gap DiffTime -diffTime = iso fromGap toGap - where - fromGap = picosecondsToDiffTime . view picoSecs - toGap = view (from picoSecs) . diffTimeToPicoseconds - -sysUTC :: Iso' SystemTime UTCTime -sysUTC = iso systemToUTCTime utcToSystemTime - -utcTime :: Iso' Wen UTCTime -utcTime = systemTime . sysUTC - -unixEpoch :: Wen -unixEpoch = Wen (Gap 0x8000_000c_ce9e_0d80_0000_0000_0000_0000) - -unixSystemTime :: Iso' Unix SystemTime -unixSystemTime = iso toSys fromSys - where - toSys (Unix gap) = MkSystemTime (fromInteger sec) (fromInteger ns) - where (sec, ns) = quotRem (gap ^. nanoSecs) 1_000_000_000 - fromSys (MkSystemTime sec ns) = - Unix $ (toInteger sec ^. from secs) - + (toInteger ns ^. from nanoSecs) - -unix :: Iso' Wen Unix -unix = iso toUnix fromUnix - where - toUnix (Wen g) = Unix (g - unWen unixEpoch) - fromUnix (Unix g) = Wen (unWen unixEpoch + g) - unWen (Wen x) = x - -systemTime :: Iso' Wen SystemTime -systemTime = unix . unixSystemTime - - --------------------------------------------------------------------------------- - -toDenomSecs :: Integer -> Gap -> Integer -toDenomSecs denom (Gap g) = shiftR (g * denom) 64 - -fromDenomSecs :: Integer -> Integer -> Gap -fromDenomSecs denom ds = - Gap $ (shiftL ds 64) `div` denom - -picoSecs :: Iso' Gap Integer -picoSecs = iso (toDenomSecs denom) (fromDenomSecs denom) - where denom = 1_000_000_000_000 - -nanoSecs :: Iso' Gap Integer -nanoSecs = iso (toDenomSecs denom) (fromDenomSecs denom) - where denom = 1_000_000_000 - -microSecs :: Iso' Gap Integer -microSecs = iso (toDenomSecs denom) (fromDenomSecs denom) - where denom = 1_000_000 - -milliSecs :: Iso' Gap Integer -milliSecs = iso (toDenomSecs denom) (fromDenomSecs denom) - where denom = 1_000 - -secs :: Iso' Gap Integer -secs = iso (toDenomSecs denom) (fromDenomSecs denom) - where denom = 1 - - --------------------------------------------------------------------------------- - -now :: IO Wen -now = view (from systemTime) <$> getSystemTime - -gap :: Wen -> Wen -> Gap -gap (Wen x) (Wen y) | x > y = x - y - | otherwise = y - x - -addGap :: Wen -> Gap -> Wen -addGap (Wen x) y = Wen (x+y) diff --git a/pkg/hs/urbit-noun/lib/Urbit/Noun/Tree.hs b/pkg/hs/urbit-noun/lib/Urbit/Noun/Tree.hs deleted file mode 100644 index 61a731675..000000000 --- a/pkg/hs/urbit-noun/lib/Urbit/Noun/Tree.hs +++ /dev/null @@ -1,179 +0,0 @@ -{-# LANGUAGE DisambiguateRecordFields #-} -{-# LANGUAGE DuplicateRecordFields #-} - -{-| - Hoon's `map` and `set` types and conversions to/from Nouns. --} -module Urbit.Noun.Tree - ( HoonSet, setToHoonSet, setFromHoonSet - , HoonMap, mapToHoonMap, mapFromHoonMap - ) where - -import ClassyPrelude -import Control.Lens hiding (non) - -import Urbit.Noun.Conversions () -import Urbit.Noun.Convert -import Urbit.Noun.Core -import Urbit.Noun.TH - - --- Types ----------------------------------------------------------------------- - -data NounVal a = NounVal - { non :: !Noun - , val :: !a - } - -data HoonTreeNode a = NTN - { n :: !(NounVal a) - , l :: !(HoonTree a) - , r :: !(HoonTree a) - } - deriving (Eq, Ord, Show) - -data HoonTree a = E | Node (HoonTreeNode a) - deriving (Eq, Ord, Show) - -pattern N :: NounVal a -> HoonTree a -> HoonTree a -> HoonTree a -pattern N n l r = Node (NTN n l r) - -newtype HoonSet a = HoonSet { unHoonSet :: HoonTree a } - deriving newtype (Eq, Ord, Show, FromNoun, ToNoun) - -newtype HoonMap k v = HoonMap { unHoonMap :: HoonTree (k, v) } - deriving newtype (Eq, Ord, Show, FromNoun, ToNoun) - - --- Instances ------------------------------------------------------------------- - -instance Eq (NounVal a) where - (==) = on (==) non - -instance Ord (NounVal a) where - compare = comparing non - -instance ToNoun (NounVal a) where - toNoun = non - -instance Show a => Show (NounVal a) where - show = show . val - -instance FromNoun a => FromNoun (NounVal a) where - parseNoun x = NounVal x <$> parseNoun x - -instance ToNoun a => ToNoun (HoonTree a) where - toNoun E = A 0 - toNoun (Node n) = toNoun n - -instance FromNoun a => FromNoun (HoonTree a) where - parseNoun (A 0) = pure E - parseNoun n = Node <$> parseNoun n - -deriveNoun ''HoonTreeNode - - --- Order ----------------------------------------------------------------------- - -{- - Orders in ascending double mug hash order, collisions fall back to dor. --} -mor :: Noun -> Noun -> Bool -mor a b = if c == d then dor a b else c < d - where - c = mug $ A $ fromIntegral $ mug a - d = mug $ A $ fromIntegral $ mug b - -{- - Orders in ascending tree depth. --} -dor :: Noun -> Noun -> Bool -dor a b | a == b = True -dor (A a) (C _ _) = True -dor (C x y) (A b) = False -dor (A a) (A b) = a < b -dor (C x y) (C p q) | x == p = dor y q -dor (C x y) (C p q) = dor x p - -{- - Orders in ascending +mug hash order. - - Collisions fall back to dor. --} -gor :: Noun -> Noun -> Bool -gor a b = if c==d then dor a b else c NounVal a -> Bool -morVal = on mor non -gorVal = on gor non - - --------------------------------------------------------------------------------- - -nounVal :: ToNoun a => Iso' a (NounVal a) -nounVal = iso to val - where - to x = NounVal (toNoun x) x - -treeToList :: forall a. HoonTree a -> [a] -treeToList = go [] - where - go :: [a] -> HoonTree a -> [a] - go acc = \case - E -> acc - Node (NTN v l r) -> go (go (val v : acc) l) r - -setFromHoonSet :: Ord a => HoonSet a -> Set a -setFromHoonSet = setFromList . treeToList . unHoonSet - -mapFromHoonMap :: Ord k => HoonMap k v -> Map k v -mapFromHoonMap = mapFromList . treeToList . unHoonMap - -setToHoonSet :: forall a. (Ord a, ToNoun a) => Set a -> HoonSet a -setToHoonSet = HoonSet . foldr put E . fmap (view nounVal) . setToList - where - put x = \case - E -> N x E E - Node a | x == n a -> Node a - Node a | gorVal x (n a) -> lef x a - Node a -> rit x a - - rit x a = put x (r a) & \case - E -> error "bad-put-set" - Node c | morVal (n a) (n c) -> N (n a) (l a) (Node c) - Node c -> N (n c) (N (n a) (l a) (l c)) (r c) - - lef x a = put x (l a) & \case - E -> error "bad-put-set" - Node c | morVal (n a) (n c) -> N (n a) (Node c) (r a) - Node c -> N (n c) (l c) (N (n a) (r c) (r a)) - -p :: (ToNoun a, ToNoun b) => NounVal (a,b) -> NounVal a -p = view (from nounVal . to fst . nounVal) - -pq :: (ToNoun a, ToNoun b) => NounVal (a,b) -> (NounVal a, NounVal b) -pq = boof . view (from nounVal) - where - boof (x, y) = (x ^. nounVal, y ^. nounVal) - -mapToHoonMap :: forall k v. (ToNoun k, ToNoun v, Ord k, Ord v) => Map k v -> HoonMap k v -mapToHoonMap = HoonMap . foldr put E . fmap (view nounVal) . mapToList - where - put :: NounVal (k, v) -> HoonTree (k, v) -> HoonTree (k, v) - put kv@(pq -> (b, c)) = \case - E -> N kv E E - Node a | kv == n a -> Node a - Node a | b == p (n a) -> N kv (l a) (r a) - Node a | gorVal b (p $ n a) -> lef kv a - Node a -> rit kv a - - lef kv@(pq -> (b, c)) a = put kv (l a) & \case - E -> error "bad-put-map" - Node d | morVal (p $ n a) (p $ n d) -> N (n a) (Node d) (r a) - Node d -> N (n d) (l d) (N (n a) (r d) (r a)) - - rit kv@(pq -> (b, c)) a = put kv (r a) & \case - E -> error "bad-put-map" - Node d | morVal (p $ n a) (p $ n d) -> N (n a) (l a) (Node d) - Node d -> N (n d) (N (n a) (l a) (l d)) (r d) diff --git a/pkg/hs/urbit-noun/package.yaml b/pkg/hs/urbit-noun/package.yaml deleted file mode 100644 index 2ba714abb..000000000 --- a/pkg/hs/urbit-noun/package.yaml +++ /dev/null @@ -1,75 +0,0 @@ -name: urbit-noun -version: 0.10.4 -license: MIT -license-file: LICENSE - -library: - source-dirs: lib - ghc-options: - - -Wall - - -Werror - - -Wno-type-defaults - - -Wno-unused-matches - - -Wno-name-shadowing - - -Wno-orphans - - -O2 - -dependencies: - - base - - classy-prelude - - ghc-prim - - largeword - - lens - - murmur3 - - regex-tdfa - - rio - - text - - time - - urbit-atom - - urbit-hob - - urbit-noun-core - -default-extensions: - - ApplicativeDo - - BangPatterns - - BlockArguments - - ConstraintKinds - - DataKinds - - DefaultSignatures - - DeriveAnyClass - - DeriveDataTypeable - - DeriveFoldable - - DeriveGeneric - - DeriveTraversable - - DerivingStrategies - - EmptyCase - - EmptyDataDecls - - FlexibleContexts - - FlexibleInstances - - FunctionalDependencies - - GADTs - - GeneralizedNewtypeDeriving - - LambdaCase - - MagicHash - - MultiParamTypeClasses - - NamedFieldPuns - - NoImplicitPrelude - - NumericUnderscores - - OverloadedStrings - - PackageImports - - PartialTypeSignatures - - PatternSynonyms - - QuasiQuotes - - Rank2Types - - RankNTypes - - RecordWildCards - - ScopedTypeVariables - - StandaloneDeriving - - TemplateHaskell - - TupleSections - - TypeApplications - - TypeFamilies - - TypeOperators - - UnboxedTuples - - UnicodeSyntax - - ViewPatterns diff --git a/pkg/hs/urbit-termsize/.gitignore b/pkg/hs/urbit-termsize/.gitignore deleted file mode 100644 index e5904eabe..000000000 --- a/pkg/hs/urbit-termsize/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.stack-work/ -urbit-termsize.cabal -*~ diff --git a/pkg/hs/urbit-termsize/LICENSE b/pkg/hs/urbit-termsize/LICENSE deleted file mode 100644 index bf9294e05..000000000 --- a/pkg/hs/urbit-termsize/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 urbit - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/pkg/hs/urbit-termsize/app/Main.hs b/pkg/hs/urbit-termsize/app/Main.hs deleted file mode 100644 index aed583c74..000000000 --- a/pkg/hs/urbit-termsize/app/Main.hs +++ /dev/null @@ -1,12 +0,0 @@ -module Main where - -import Prelude - -import Urbit.TermSize (liveTermSize) - -main :: IO () -main = do - init <- liveTermSize (putStrLn . ("New Size: " <>) . show) - putStrLn ("Initial Size: " <> show init) - _ <- getLine - pure () diff --git a/pkg/hs/urbit-termsize/lib/Urbit/TermSize.hs b/pkg/hs/urbit-termsize/lib/Urbit/TermSize.hs deleted file mode 100644 index af4e1f0b0..000000000 --- a/pkg/hs/urbit-termsize/lib/Urbit/TermSize.hs +++ /dev/null @@ -1,42 +0,0 @@ -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE RecordWildCards #-} - -module Urbit.TermSize - ( TermSize(..) - , termSize - , liveTermSize - ) -where - -import Prelude - -import Data.Functor ((<&>)) -import System.Console.Terminal.Size (Window(..), size) - -import qualified System.Posix.Signals as Sys -import qualified System.Posix.Signals.Exts as Sys - - --- Types ----------------------------------------------------------------------- - -data TermSize = TermSize - { tsWide :: !Word - , tsTall :: !Word - } - deriving (Eq, Ord, Show) - - --- Utilities ------------------------------------------------------------------- - -termSize :: IO TermSize -termSize = size <&> \case - Nothing -> TermSize 80 24 - Just (Window {..}) -> TermSize width height - -liveTermSize :: (TermSize -> IO ()) -> IO TermSize -liveTermSize cb = do - Sys.installHandler Sys.sigWINCH (Sys.Catch (termSize >>= cb)) Nothing - ts <- termSize - cb ts - pure ts diff --git a/pkg/hs/urbit-termsize/package.yaml b/pkg/hs/urbit-termsize/package.yaml deleted file mode 100644 index d63d312f7..000000000 --- a/pkg/hs/urbit-termsize/package.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: urbit-termsize -version: 0.1.0 -license: MIT -license-file: LICENSE - -dependencies: - - base - - terminal-size - - unix - -ghc-options: - - -Wall - - -Werror - - -Wno-type-defaults - - -Wno-unused-matches - - -Wno-name-shadowing - - -Wno-unused-do-bind - - -O2 - -library: - source-dirs: lib - -executables: - urbit-test-termsize-updates: - main: Main.hs - source-dirs: app - dependencies: - - urbit-termsize diff --git a/pkg/landscape/lib/docket.hoon b/pkg/landscape/lib/docket.hoon deleted file mode 120000 index e0f69ee1e..000000000 --- a/pkg/landscape/lib/docket.hoon +++ /dev/null @@ -1 +0,0 @@ -../../garden-dev/lib/docket.hoon \ No newline at end of file diff --git a/pkg/landscape/lib/docket.hoon b/pkg/landscape/lib/docket.hoon new file mode 100644 index 000000000..ef39b7fbb --- /dev/null +++ b/pkg/landscape/lib/docket.hoon @@ -0,0 +1,223 @@ +/- *docket +|% +:: +++ mime + |% + +$ draft + $: title=(unit @t) + info=(unit @t) + color=(unit @ux) + glob-http=(unit [=url hash=@uvH]) + glob-ames=(unit [=ship hash=@uvH]) + base=(unit term) + site=(unit path) + image=(unit url) + version=(unit version) + website=(unit url) + license=(unit cord) + == + :: + ++ finalize + |= =draft + ^- (unit docket) + ?~ title.draft ~ + ?~ info.draft ~ + ?~ color.draft ~ + ?~ version.draft ~ + ?~ website.draft ~ + ?~ license.draft ~ + =/ href=(unit href) + ?^ site.draft `[%site u.site.draft] + ?~ base.draft ~ + ?^ glob-http.draft + `[%glob u.base hash.u.glob-http %http url.u.glob-http]:draft + ?~ glob-ames.draft + ~ + `[%glob u.base hash.u.glob-ames %ames ship.u.glob-ames]:draft + ?~ href ~ + =, draft + :- ~ + :* %1 + u.title + u.info + u.color + u.href + image + u.version + u.website + u.license + == + :: + ++ from-clauses + =| =draft + |= cls=(list clause) + ^- (unit docket) + =* loop $ + ?~ cls (finalize draft) + =* clause i.cls + =. draft + ?- -.clause + %title draft(title `title.clause) + %info draft(info `info.clause) + %color draft(color `color.clause) + %glob-http draft(glob-http `[url hash]:clause) + %glob-ames draft(glob-ames `[ship hash]:clause) + %base draft(base `base.clause) + %site draft(site `path.clause) + %image draft(image `url.clause) + %version draft(version `version.clause) + %website draft(website `website.clause) + %license draft(license `license.clause) + == + loop(cls t.cls) + :: + ++ to-clauses + |= d=docket + ^- (list clause) + %- zing + :~ :~ title+title.d + info+info.d + color+color.d + version+version.d + website+website.d + license+license.d + == + ?~ image.d ~ ~[image+u.image.d] + ?: ?=(%site -.href.d) ~[site+path.href.d] + =/ ref=glob-reference glob-reference.href.d + :~ base+base.href.d + ?- -.location.ref + %http [%glob-http url.location.ref hash.ref] + %ames [%glob-ames ship.location.ref hash.ref] + == == == + :: + ++ spit-clause + |= =clause + ^- tape + %+ weld " {(trip -.clause)}+" + ?+ -.clause "'{(trip +.clause)}'" + %color (scow %ux color.clause) + %site (spud path.clause) + :: + %glob-http + "['{(trip url.clause)}' {(scow %uv hash.clause)}]" + :: + %glob-ames + "[{(scow %p ship.clause)} {(scow %uv hash.clause)}]" + :: + %version + =, version.clause + "[{(scow %ud major)} {(scow %ud minor)} {(scow %ud patch)}]" + == + :: + ++ spit-docket + |= dock=docket + ^- tape + ;: welp + ":~\0a" + `tape`(zing (join "\0a" (turn (to-clauses dock) spit-clause))) + "\0a==" + == + -- +:: +++ enjs + =, enjs:format + |% + :: + ++ charge-update + |= u=^charge-update + ^- json + %+ frond -.u + ^- json + ?- -.u + %del-charge s+desk.u + :: + %initial + %- pairs + %+ turn ~(tap by initial.u) + |=([=desk c=^charge] [desk (charge c)]) + :: + %add-charge + %- pairs + :~ desk+s+desk.u + charge+(charge charge.u) + == + == + :: + ++ num + |= a=@u + ^- ^tape + =/ p=json (numb a) + ?> ?=(%n -.p) + (trip p.p) + :: + ++ version + |= v=^version + ^- json + :- %s + %- crip + "{(num major.v)}.{(num minor.v)}.{(num patch.v)}" + :: + ++ merge + |= [a=json b=json] + ^- json + ?> &(?=(%o -.a) ?=(%o -.b)) + [%o (~(uni by p.a) p.b)] + :: + ++ href + |= h=^href + %+ frond -.h + ?- -.h + %site s+(spat path.h) + %glob + %- pairs + :~ base+s+base.h + glob-reference+(glob-reference glob-reference.h) + == + == + :: + ++ glob-reference + |= ref=^glob-reference + %- pairs + :~ hash+s+(scot %uv hash.ref) + location+(glob-location location.ref) + == + :: + ++ glob-location + |= loc=^glob-location + ^- json + %+ frond -.loc + ?- -.loc + %http s+url.loc + %ames s+(scot %p ship.loc) + == + :: + ++ charge + |= c=^charge + %+ merge (docket docket.c) + %- pairs + :~ chad+(chad chad.c) + == + :: + ++ docket + |= d=^docket + ^- json + %- pairs + :~ title+s+title.d + info+s+info.d + color+s+(scot %ux color.d) + href+(href href.d) + image+?~(image.d ~ s+u.image.d) + version+(version version.d) + license+s+license.d + website+s+website.d + == + :: + ++ chad + |= c=^chad + %+ frond -.c + ?+ -.c ~ + %hung s+err.c + == + -- +-- diff --git a/pkg/landscape/lib/hark-store.hoon b/pkg/landscape/lib/hark-store.hoon deleted file mode 120000 index 9e9e81ee2..000000000 --- a/pkg/landscape/lib/hark-store.hoon +++ /dev/null @@ -1 +0,0 @@ -../../garden-dev/lib/hark-store.hoon \ No newline at end of file diff --git a/pkg/landscape/lib/hark-store.hoon b/pkg/landscape/lib/hark-store.hoon new file mode 100644 index 000000000..23af6a64d --- /dev/null +++ b/pkg/landscape/lib/hark-store.hoon @@ -0,0 +1,255 @@ +/- sur=hark-store +^? +=, sur +=< [. sur] +|% + +++ enjs + =, enjs:format + |% + ++ update + |= upd=^update + ^- json + %+ frond -.upd + ?+ -.upd a+~ + %added (notification +.upd) + %add-note (add-note +.upd) + %timebox (timebox +.upd) + %more (more +.upd) + %read-each (read-each +.upd) + %read-count (place +.upd) + %unread-each (read-each +.upd) + %unread-count (unread-count +.upd) + %saw-place (saw-place +.upd) + %all-stats (all-stats +.upd) + %del-place (place +.upd) + ::%read-note (index +.upd) + ::%note-read (note-read +.upd) + %archived (archived +.upd) + == + :: + ++ add-note + |= [bi=^bin bo=^body] + %- pairs + :~ bin+(bin bi) + body+(body bo) + == + :: + ++ saw-place + |= [p=^place t=(unit ^time)] + %- pairs + :~ place+(place p) + time+?~(t ~ (time u.t)) + == + :: + ++ archived + |= [t=^time l=^lid n=^notification] + %- pairs + :~ lid+(lid l) + time+s+(scot %ud t) + notification+(notification n) + == + :: + ++ note-read + |= * + (pairs ~) + :: + ++ all-stats + |= places=(map ^place ^stats) + ^- json + :- %a + ^- (list json) + %+ turn ~(tap by places) + |= [p=^place s=^stats] + %- pairs + :~ stats+(stats s) + place+(place p) + + == + :: + ++ stats + |= s=^stats + ^- json + %- pairs + :~ each+a+(turn ~(tap in each.s) (cork spat (lead %s))) + last+(time last.s) + count+(numb count.s) + == + ++ more + |= upds=(list ^update) + ^- json + a+(turn upds update) + :: + ++ place + |= =^place + %- pairs + :~ desk+s+desk.place + path+s+(spat path.place) + == + :: + ++ bin + |= =^bin + %- pairs + :~ place+(place place.bin) + path+s+(spat path.bin) + == + ++ notification + |= ^notification + ^- json + %- pairs + :~ time+(time date) + bin+(^bin bin) + body+(bodies body) + == + ++ bodies + |= bs=(list ^body) + ^- json + a+(turn bs body) + :: + ++ contents + |= cs=(list ^content) + ^- json + a+(turn cs content) + :: + ++ content + |= c=^content + ^- json + %+ frond -.c + ?- -.c + %ship s+(scot %p ship.c) + %text s+cord.c + == + :: + ++ body + |= ^body + ^- json + %- pairs + :~ title+(contents title) + content+(contents content) + time+(^time time) + link+s+(spat link) + == + :: + ++ binned-notification + |= [=^bin =^notification] + %- pairs + :~ bin+(^bin bin) + notification+(^notification notification) + == + ++ lid + |= l=^lid + ^- json + %+ frond -.l + ?- -.l + ?(%seen %unseen) ~ + %archive s+(scot %ud time.l) + == + :: + ++ timebox + |= [li=^lid l=(list ^notification)] + ^- json + %- pairs + :~ lid+(lid li) + notifications+a+(turn l notification) + == + :: + ++ read-each + |= [p=^place pax=^path] + %- pairs + :~ place+(place p) + path+(path pax) + == + :: + ++ unread-count + |= [p=^place inc=? count=@ud] + %- pairs + :~ place+(place p) + inc+b+inc + count+(numb count) + == + -- +++ dejs + =, dejs:format + |% + ++ ship (su ;~(pfix sig fed:ag)) + :: TODO: fix +stab + :: + ++ pa + |= j=json + ^- path + ?> ?=(%s -.j) + ?: =('/' p.j) / + (stab p.j) + :: + ++ place + %- ot + :~ desk+so + path+pa + == + :: + ++ bin + %- ot + :~ path+pa + place+place + == + :: + ++ read-each + %- ot + :~ place+place + path+pa + == + :: + :: parse date as @ud + :: TODO: move to zuse + ++ sd + |= jon=json + ^- @da + ?> ?=(%s -.jon) + `@da`(rash p.jon dem:ag) + :: + ++ lid + %- of + :~ archive+sd + unseen+ul + seen+ul + == + :: + ++ archive + %- ot + :~ lid+lid + bin+bin + == + ++ content + %- of + :~ text+so + ship+ship + == + :: + ++ body + %- ot + :~ title+(ar content) + content+(ar content) + time+di + binned+pa + link+pa + == + :: + ++ add-note + %- ot + :~ bin+bin + body+body + == + :: + ++ action + ^- $-(json ^action) + %- of + :~ archive-all+ul + archive+archive + opened+ul + read-count+place + read-each+read-each + read-note+bin + add-note+add-note + == + -- +-- diff --git a/pkg/landscape/lib/mip.hoon b/pkg/landscape/lib/mip.hoon deleted file mode 120000 index 47b46482a..000000000 --- a/pkg/landscape/lib/mip.hoon +++ /dev/null @@ -1 +0,0 @@ -../../garden-dev/lib/mip.hoon \ No newline at end of file diff --git a/pkg/landscape/lib/mip.hoon b/pkg/landscape/lib/mip.hoon new file mode 100644 index 000000000..322a4c85f --- /dev/null +++ b/pkg/landscape/lib/mip.hoon @@ -0,0 +1,55 @@ +|% +++ mip :: map of maps + |$ [kex key value] + (map kex (map key value)) +:: +++ bi :: mip engine + =| a=(map * (map)) + |@ + ++ del + |* [b=* c=*] + =+ d=(~(gut by a) b ~) + =+ e=(~(del by d) c) + ?~ e + (~(del by a) b) + (~(put by a) b e) + :: + ++ get + |* [b=* c=*] + => .(b `_?>(?=(^ a) p.n.a)`b, c `_?>(?=(^ a) ?>(?=(^ q.n.a) p.n.q.n.a))`c) + ^- (unit _?>(?=(^ a) ?>(?=(^ q.n.a) q.n.q.n.a))) + (~(get by (~(gut by a) b ~)) c) + :: + ++ got + |* [b=* c=*] + (need (get b c)) + :: + ++ gut + |* [b=* c=* d=*] + (~(gut by (~(gut by a) b ~)) c d) + :: + ++ has + |* [b=* c=*] + !=(~ (get b c)) + :: + ++ key + |* b=* + ~(key by (~(gut by a) b ~)) + :: + ++ put + |* [b=* c=* d=*] + %+ ~(put by a) b + %. [c d] + %~ put by + (~(gut by a) b ~) + :: + ++ tap + ::NOTE naive turn-based implementation find-errors ): + =< $ + =+ b=`_?>(?=(^ a) *(list [x=_p.n.a _?>(?=(^ q.n.a) [y=p v=q]:n.q.n.a)]))`~ + |. ^+ b + ?~ a + b + $(a r.a, b (welp (turn ~(tap by q.n.a) (lead p.n.a)) $(a l.a))) + -- +-- diff --git a/pkg/landscape/mar/docket-0.hoon b/pkg/landscape/mar/docket-0.hoon deleted file mode 120000 index 2bb549dd9..000000000 --- a/pkg/landscape/mar/docket-0.hoon +++ /dev/null @@ -1 +0,0 @@ -../../garden-dev/mar/docket-0.hoon \ No newline at end of file diff --git a/pkg/landscape/mar/docket-0.hoon b/pkg/landscape/mar/docket-0.hoon new file mode 100644 index 000000000..911d34c0d --- /dev/null +++ b/pkg/landscape/mar/docket-0.hoon @@ -0,0 +1,25 @@ +/+ dock=docket +|_ =docket:dock +++ grow + |% + ++ mime + ^- ^mime + [/text/x-docket (as-octt:mimes:html (spit-docket:mime:dock docket))] + ++ noun docket + ++ json (docket:enjs:dock docket) + -- +++ grab + |% + :: + ++ mime + |= [=mite len=@ud tex=@] + ^- docket:dock + %- need + %- from-clauses:mime:dock + !<((list clause:dock) (slap !>(~) (ream tex))) + + :: + ++ noun docket:dock + -- +++ grad %noun +-- diff --git a/pkg/landscape/sur/docket.hoon b/pkg/landscape/sur/docket.hoon deleted file mode 120000 index e13676adb..000000000 --- a/pkg/landscape/sur/docket.hoon +++ /dev/null @@ -1 +0,0 @@ -../../garden-dev/sur/docket.hoon \ No newline at end of file diff --git a/pkg/landscape/sur/docket.hoon b/pkg/landscape/sur/docket.hoon new file mode 100644 index 000000000..091c8c9f9 --- /dev/null +++ b/pkg/landscape/sur/docket.hoon @@ -0,0 +1,82 @@ +|% +:: ++$ version + [major=@ud minor=@ud patch=@ud] +:: ++$ glob (map path mime) +:: ++$ url cord +:: $glob-location: How to retrieve a glob +:: ++$ glob-reference + [hash=@uvH location=glob-location] +:: ++$ glob-location + $% [%http =url] + [%ames =ship] + == +:: $href: Where a tile links to +:: ++$ href + $% [%glob base=term =glob-reference] + [%site =path] + == +:: $chad: State of a docket +:: ++$ chad + $~ [%install ~] + $% :: Done + [%glob =glob] + [%site ~] + :: Waiting + [%install ~] + [%suspend glob=(unit glob)] + :: Error + [%hung err=cord] + == +:: +:: $charge: A realized $docket +:: ++$ charge + $: =docket + =chad + == +:: +:: $clause: A key and value, as part of a docket +:: +:: Only used to parse $docket +:: ++$ clause + $% [%title title=@t] + [%info info=@t] + [%color color=@ux] + [%glob-http url=cord hash=@uvH] + [%glob-ames =ship hash=@uvH] + [%image =url] + [%site =path] + [%base base=term] + [%version =version] + [%website website=url] + [%license license=cord] + == +:: +:: $docket: A description of JS bundles for a desk +:: ++$ docket + $: %1 + title=@t + info=@t + color=@ux + =href + image=(unit url) + =version + website=url + license=cord + == +:: ++$ charge-update + $% [%initial initial=(map desk charge)] + [%add-charge =desk =charge] + [%del-charge =desk] + == +-- diff --git a/pkg/landscape/sur/hark-store.hoon b/pkg/landscape/sur/hark-store.hoon deleted file mode 120000 index 5d606e793..000000000 --- a/pkg/landscape/sur/hark-store.hoon +++ /dev/null @@ -1 +0,0 @@ -../../garden-dev/sur/hark-store.hoon \ No newline at end of file diff --git a/pkg/landscape/sur/hark-store.hoon b/pkg/landscape/sur/hark-store.hoon new file mode 100644 index 000000000..457839309 --- /dev/null +++ b/pkg/landscape/sur/hark-store.hoon @@ -0,0 +1,159 @@ +^? +:: +:: %hark-store: Notification, unreads store +:: +:: Timeboxing & binning: +:: +:: Unread notifications accumulate in $unreads. They are grouped by +:: their $bin. A notification may become read by either: +:: a) being read by a %read-count or %read-each or %read-note +:: b) being read by a %seen +:: +:: If a) then we insert the corresponding bin into $reads at the +:: current timestamp +:: If b) then we empty $unreads and move all bins to $reads at the +:: current timestamp +:: +:: Unread tracking: +:: Unread tracking has two 'modes' which may be used concurrently, +:: if necessary. +:: +:: count: +:: This stores the unreads as a simple atom, describing the number +:: of unread items. May be increased with %unread-count and +:: set to zero with %read-count. Ideal for high-frequency linear +:: datastructures, e.g. chat +:: each: +:: This stores the unreads as a set of paths, describing the set of +:: unread items. Unreads may be added to the set with %unread-each +:: and removed with %read-each. Ideal for non-linear, low-frequency +:: datastructures, e.g. blogs +:: +|% +:: $place: A location, under which landscape stores stats +:: +:: .desk must match q.byk.bowl +:: Examples: +:: A chat: +:: [%landscape /~dopzod/urbit-help] +:: A note in a notebook: +:: [%landscape /~darrux-landes/feature-requests/12374893234232] +:: A group: +:: [%hark-group-hook /~bitbet-bolbel/urbit-community] +:: Comments on a link +:: [%landscape /~dabben-larbet/urbit-in-the-news/17014118450499614194868/2] +:: ++$ place [=desk =path] +:: +:: $bin: Identifier for grouping notifications +:: +:: Examples +:: A mention in a chat: +:: [/mention %landscape /~dopzod/urbit-help] +:: New messages in a chat +:: [/message %landscape /~dopzod/urbit-help] +:: A new comment in a notebook: +:: [/comment %landscape /~darrux-landes/feature-requests/12374893234232/2] +:: ++$ bin [=path =place] +:: +:: $lid: Reference to a timebox +:: ++$ lid + $% [%archive =time] + [%seen ~] + [%unseen ~] + == +:: $content: Notification content ++$ content + $% [%ship =ship] + [%text =cord] + == +:: +:: $body: A notification body +:: ++$ body + $: title=(list content) + content=(list content) + =time + binned=path + link=path + == +:: ++$ notification + [date=@da =bin body=(list body)] +:: $timebox: Group of notificatons ++$ timebox + (map bin notification) +:: $archive: Archived notifications, ordered by time ++$ archive + ((mop @da timebox) gth) +:: ++$ action + $% :: hook actions + :: + :: %add-note: add a notification + [%add-note =bin =body] + :: + :: %del-place: Underlying resource disappeared, remove all + :: associated notifications + [%del-place =place] + :: %unread-count: Change unread count by .count + [%unread-count =place inc=? count=@ud] + :: %unread-each: Add .path to list of unreads for .place + [%unread-each =place =path] + :: %saw-place: Update last-updated for .place to now.bowl + [%saw-place =place time=(unit time)] + :: store actions + :: + :: %archive: archive single notification + :: if .time is ~, then archiving unread notification + :: else, archiving read notification + [%archive =lid =bin] + :: %read-count: set unread count to zero + [%read-count =place] + :: %read-each: remove path from unreads for .place + [%read-each =place =path] + :: %read-note: Read note at .bin + [%read-note =bin] + :: %archive-all: Archive all notifications + [%archive-all ~] + :: %opened: User opened notifications, reset timeboxing logic. + :: + [%opened ~] + :: + :: XX: previously in hark-store, now deprecated + :: the hooks responsible for creating notifications may offer pokes + :: similar to this + :: [%read-graph =resource] + :: [%read-group =resource] + :: [%remove-graph =resource] + :: + == +:: .stats: Statistics for a .place +:: ++$ stats + $: count=@ud + each=(set path) + last=@da + timebox=(unit @da) + == +:: ++$ update + $% action + :: %more: more updates + [%archived =time =lid =notification] + [%more more=(list update)] + :: %note-read: note has been read with timestamp + [%note-read =time =bin] + [%added =notification] + :: %timebox: description of timebox. + :: + [%timebox =lid =(list notification)] + :: %place-stats: description of .stats for a .place + [%place-stats =place =stats] + :: %place-stats: stats for all .places + [%all-stats places=(map place stats)] + == +-- + diff --git a/pkg/landscape/sur/settings.hoon b/pkg/landscape/sur/settings.hoon deleted file mode 120000 index c2c70beef..000000000 --- a/pkg/landscape/sur/settings.hoon +++ /dev/null @@ -1 +0,0 @@ -../../garden-dev/sur/settings.hoon \ No newline at end of file diff --git a/pkg/landscape/sur/settings.hoon b/pkg/landscape/sur/settings.hoon new file mode 100644 index 000000000..53e8691db --- /dev/null +++ b/pkg/landscape/sur/settings.hoon @@ -0,0 +1,44 @@ +/+ *mip +|% +:: +++ settings-0 + =< settings + |% + +$ settings (map key bucket) + +$ bucket (map key val) + +$ val + $% [%s p=@t] + [%b p=?] + [%n p=@] + == + -- +:: +++ settings-1 + =< settings + |% + +$ settings (map key bucket) + -- ++$ bucket (map key val) ++$ key term ++$ val + $~ [%n 0] + $% [%s p=@t] + [%b p=?] + [%n p=@] + [%a p=(list val)] + == +:: ++$ settings (mip desk key bucket) ++$ event + $% [%put-bucket =desk =key =bucket] + [%del-bucket =desk =key] + [%put-entry =desk buc=key =key =val] + [%del-entry =desk buc=key =key] + == ++$ data + $% [%all =settings] + [%bucket =bucket] + [%desk desk=(map key bucket)] + [%entry =val] + == +-- diff --git a/pkg/urbit/.gitattributes b/pkg/urbit/.gitattributes deleted file mode 100644 index def025cbf..000000000 --- a/pkg/urbit/.gitattributes +++ /dev/null @@ -1,6 +0,0 @@ -.gitignore export-ignore -.gitattributes export-ignore -tests export-ignore -hashtable_tests export-ignore -shell.nix export-ignore -*.patch -text diff --git a/pkg/urbit/.gitignore b/pkg/urbit/.gitignore deleted file mode 100644 index 3a9050b38..000000000 --- a/pkg/urbit/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Configuration Result -/config.mk -/include/config.h -/include/ca-bundle.h -/include/ivory.h - -# indexing -/.cache/ -compile_commands.json -tags diff --git a/pkg/urbit/LICENSE.txt b/pkg/urbit/LICENSE.txt deleted file mode 100644 index 6404c00fb..000000000 --- a/pkg/urbit/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Urbit - -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. \ No newline at end of file diff --git a/pkg/urbit/Makefile b/pkg/urbit/Makefile deleted file mode 100644 index 6b934bc79..000000000 --- a/pkg/urbit/Makefile +++ /dev/null @@ -1,95 +0,0 @@ -include config.mk -compat_mks := $(foreach dir,$(compat),$(wildcard compat/$(dir)/*.mk)) -include $(compat_mks) - -jets = jets/tree.c $(wildcard jets/*/*.c) -noun = $(wildcard noun/*.c) -ur = $(wildcard ur/*.c) -vere = $(wildcard vere/*.c) $(wildcard vere/*/*.c) -daemon = $(wildcard daemon/*.c) -worker = $(wildcard worker/*.c) -tests = $(wildcard tests/*.c) -bench = $(wildcard bench/*.c) - -compat := $(foreach dir,$(compat),$(wildcard compat/$(dir)/*.c)) - -common = $(jets) $(noun) $(ur) $(vere) $(compat) -headers = $(shell find include -type f) - -common_objs = $(shell echo $(common) | sed 's/\.c/.o/g') -daemon_objs = $(shell echo $(daemon) | sed 's/\.c/.o/g') -worker_objs = $(shell echo $(worker) | sed 's/\.c/.o/g') - -all_objs = $(common_objs) $(daemon_objs) $(worker_objs) -all_srcs = $(common) $(daemon) $(worker) - -test_exes = $(shell echo $(tests) | sed 's/tests\//.\/build\//g' | sed 's/\.c//g') -bench_exes = $(shell echo $(bench) | sed 's/bench\//.\/build\//g' | sed 's/\.c//g') -all_exes = $(test_exes) $(bench_exes) ./build/urbit - -# -Werror promotes all warnings that are enabled into errors (this is on) -# -Wall issues all types of errors. This is off (for now) -CFLAGS := $(CFLAGS) - -################################################################################ - -.PHONY: all bench test clean mrproper - -################################################################################ - -all: $(all_exes) - -test: $(test_exes) - @FAIL=0; \ - for x in $^; \ - do echo $$'\n'"$$x" && ./$$x; \ - if [ $$? != 0 ]; then FAIL=1; fi; \ - done; \ - if [ $$FAIL != 0 ]; then echo "\n" && exit 1; fi; - -bench: $(bench_exes) - build/ur_bench - -clean: - rm -f ./tags $(all_objs) $(all_exes) - -mrproper: clean - rm -f config.mk include/config.h compile_commands.json - -################################################################################ - -build/ur_bench: $(common_objs) bench/ur_bench.o - @echo CC -o $@ - @mkdir -p ./build - @$(CC) $^ $(LDFLAGS) -o $@ - -build/%_tests: $(common_objs) tests/%_tests.o - @echo CC -o $@ - @mkdir -p ./build - @$(CC) $^ $(LDFLAGS) -o $@ - -build/urbit: $(common_objs) $(daemon_objs) $(worker_objs) - @echo CC -o $@ - @mkdir -p ./build - @$(CC) $^ $(LDFLAGS) -o $@ - -# CCDEPS and CCEXTRA are empty except in MingW build, -# which uses them to inject a C source transform step -%.o: %.c $(headers) $(CCDEPS) - @echo CC $< - @$(CC) -I./include $(CFLAGS) $< $(CCEXTRA) -c -o $@ - -tags: $(all_srcs) $(headers) - ctags $^ - -compile_commands.json: Makefile config.mk $(compat_mks) - @echo "[" > $@ && sep= && \ - for src in $(all_srcs); do \ - echo "$$sep{" >> $@; \ - printf '"directory": "%s",\n' $$(pwd) >> $@; \ - printf '"command": "%s",\n' "$(CC) -I./include $(CFLAGS) $$src $(CCEXTRA) -c" >> $@; \ - printf '"file": "%s",\n' $$src >> $@; \ - echo "}" >> $@; \ - sep=','; \ - done && \ - echo "]" >> $@ diff --git a/pkg/urbit/bench/ur_bench.c b/pkg/urbit/bench/ur_bench.c deleted file mode 100644 index 4c0151357..000000000 --- a/pkg/urbit/bench/ur_bench.c +++ /dev/null @@ -1,406 +0,0 @@ -#include "all.h" -#include "vere/vere.h" -#include "ur/ur.h" - -/* _setup(): prepare for tests. -*/ -static void -_setup(void) -{ - u3m_init(1 << 24); - u3m_pave(c3y); - u3e_init(); -} - -/* _ames_writ_ex(): |hi packet from fake ~zod to fake ~nec -*/ -static u3_noun -_ames_writ_ex(void) -{ - c3_y bod_y[63] = { - 0x30, 0x90, 0x2d, 0x0, 0x0, 0x0, 0x1, 0x0, 0x9, 0xc0, 0xd0, - 0x0, 0x4, 0x40, 0x30, 0xf4, 0xa, 0x3d, 0x45, 0x86, 0x66, 0x2c, - 0x2, 0x38, 0xf8, 0x72, 0xa3, 0x9, 0xf6, 0x6, 0xf3, 0x0, 0xbe, - 0x67, 0x61, 0x49, 0x50, 0x4, 0x3c, 0x13, 0xb2, 0x96, 0x42, 0x1b, - 0x62, 0xac, 0x97, 0xff, 0x24, 0xeb, 0x69, 0x1b, 0xb2, 0x60, 0x72, - 0xa, 0x53, 0xdf, 0xe8, 0x8a, 0x9c, 0x6f, 0xb3 - }; - u3_noun lan = u3nc(0, 1); - u3_noun cad = u3nt(c3__send, lan, u3i_bytes(sizeof(bod_y), bod_y)); - u3_noun wir = u3nt(c3__newt, 0x1234, u3_nul); - u3_noun ovo = u3nc(u3nc(u3_blip, wir), cad); - u3_noun wen; - - { - struct timeval tim_u; - gettimeofday(&tim_u, 0); - wen = u3_time_in_tv(&tim_u); - } - - return u3nt(c3__work, 0, u3nc(wen, ovo)); -} - -static void -_jam_bench(void) -{ - struct timeval b4, f2, d0; - c3_w mil_w, i_w, max_w = 10000; - u3_noun wit = _ames_writ_ex(); - - fprintf(stderr, "\r\njam microbenchmark:\r\n"); - - { - gettimeofday(&b4, 0); - - { - u3i_slab sab_u; - - for ( i_w = 0; i_w < max_w; i_w++ ) { - u3s_jam_fib(&sab_u, wit); - u3i_slab_free(&sab_u); - } - } - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - fprintf(stderr, " jam og: %u ms\r\n", mil_w); - } - - { - gettimeofday(&b4, 0); - - { - c3_d len_d; - c3_y* byt_y; - - for ( i_w = 0; i_w < max_w; i_w++ ) { - u3s_jam_xeno(wit, &len_d, &byt_y); - c3_free(byt_y); - } - } - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - fprintf(stderr, " jam xeno: %u ms\r\n", mil_w); - } - - while ( 1 ) { - ur_root_t* rot_u = ur_root_init(); - c3_d len_d; - c3_y* byt_y; - ur_nref ref; - - u3s_jam_xeno(wit, &len_d, &byt_y); - if ( ur_cue_good != ur_cue(rot_u, len_d, byt_y, &ref) ) { - fprintf(stderr, " jam bench: cue failed wtf\r\n"); - break; - } - - c3_free(byt_y); - - { - gettimeofday(&b4, 0); - - for ( i_w = 0; i_w < max_w; i_w++ ) { - ur_jam(rot_u, ref, &len_d, &byt_y); - c3_free(byt_y); - } - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - fprintf(stderr, " jam cons: %u ms\r\n", mil_w); - } - - { - gettimeofday(&b4, 0); - - { - ur_jam_t *jam_u = ur_jam_init(rot_u); - c3_d len_d; - c3_y* byt_y; - - for ( i_w = 0; i_w < max_w; i_w++ ) { - ur_jam_with(jam_u, ref, &len_d, &byt_y); - c3_free(byt_y); - } - - ur_jam_done(jam_u); - } - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - fprintf(stderr, " jam cons with: %u ms\r\n", mil_w); - } - - ur_root_free(rot_u); - break; - } - - u3z(wit); -} - -static void -_cue_bench(void) -{ - struct timeval b4, f2, d0; - c3_w mil_w, i_w, max_w = 20000; - u3_atom vat = u3ke_jam(_ames_writ_ex()); - - fprintf(stderr, "\r\ncue microbenchmark:\r\n"); - - { - gettimeofday(&b4, 0); - - for ( i_w = 0; i_w < max_w; i_w++ ) { - u3z(u3s_cue(vat)); - } - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - fprintf(stderr, " cue og: %u ms\r\n", mil_w); - } - - { - gettimeofday(&b4, 0); - - for ( i_w = 0; i_w < max_w; i_w++ ) { - u3z(u3s_cue_atom(vat)); - } - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - fprintf(stderr, " cue atom: %u ms\r\n", mil_w); - } - - { - gettimeofday(&b4, 0); - - { - c3_w len_w = u3r_met(3, vat); - // XX assumes little-endian - // - c3_y* byt_y = ( c3y == u3a_is_cat(vat) ) - ? (c3_y*)&vat - : (c3_y*)((u3a_atom*)u3a_to_ptr(vat))->buf_w; - - for ( i_w = 0; i_w < max_w; i_w++ ) { - u3z(u3s_cue_xeno(len_w, byt_y)); - } - } - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - fprintf(stderr, " cue xeno: %u ms\r\n", mil_w); - } - - { - gettimeofday(&b4, 0); - - { - u3_cue_xeno* sil_u = u3s_cue_xeno_init(); - - c3_w len_w = u3r_met(3, vat); - // XX assumes little-endian - // - c3_y* byt_y = ( c3y == u3a_is_cat(vat) ) - ? (c3_y*)&vat - : (c3_y*)((u3a_atom*)u3a_to_ptr(vat))->buf_w; - - for ( i_w = 0; i_w < max_w; i_w++ ) { - u3z(u3s_cue_xeno_with(sil_u, len_w, byt_y)); - } - - u3s_cue_xeno_done(sil_u); - } - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - fprintf(stderr, " cue xeno with: %u ms\r\n", mil_w); - } - - { - gettimeofday(&b4, 0); - - { - c3_w len_w = u3r_met(3, vat); - // XX assumes little-endian - // - c3_y* byt_y = ( c3y == u3a_is_cat(vat) ) - ? (c3_y*)&vat - : (c3_y*)((u3a_atom*)u3a_to_ptr(vat))->buf_w; - - for ( i_w = 0; i_w < max_w; i_w++ ) { - ur_cue_test(len_w, byt_y); - } - } - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - fprintf(stderr, " cue test: %u ms\r\n", mil_w); - } - - { - gettimeofday(&b4, 0); - - { - ur_cue_test_t *t = ur_cue_test_init(); - - c3_w len_w = u3r_met(3, vat); - // XX assumes little-endian - // - c3_y* byt_y = ( c3y == u3a_is_cat(vat) ) - ? (c3_y*)&vat - : (c3_y*)((u3a_atom*)u3a_to_ptr(vat))->buf_w; - - for ( i_w = 0; i_w < max_w; i_w++ ) { - ur_cue_test_with(t, len_w, byt_y); - } - - ur_cue_test_done(t); - } - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - fprintf(stderr, " cue test with: %u ms\r\n", mil_w); - } - - { - gettimeofday(&b4, 0); - - { - ur_root_t* rot_u = ur_root_init(); - ur_nref ref; - c3_w len_w = u3r_met(3, vat); - // XX assumes little-endian - // - c3_y* byt_y = ( c3y == u3a_is_cat(vat) ) - ? (c3_y*)&vat - : (c3_y*)((u3a_atom*)u3a_to_ptr(vat))->buf_w; - - for ( i_w = 0; i_w < max_w; i_w++ ) { - ur_cue(rot_u, len_w, byt_y, &ref); - } - - ur_root_free(rot_u); - } - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - fprintf(stderr, " cue cons: %u ms\r\n", mil_w); - } - - { - gettimeofday(&b4, 0); - - { - ur_root_t* rot_u; - ur_nref ref; - c3_w len_w = u3r_met(3, vat); - // XX assumes little-endian - // - c3_y* byt_y = ( c3y == u3a_is_cat(vat) ) - ? (c3_y*)&vat - : (c3_y*)((u3a_atom*)u3a_to_ptr(vat))->buf_w; - - for ( i_w = 0; i_w < max_w; i_w++ ) { - rot_u = ur_root_init(); - ur_cue(rot_u, len_w, byt_y, &ref); - ur_root_free(rot_u); - } - } - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - fprintf(stderr, " cue re-cons: %u ms\r\n", mil_w); - } - - u3z(vat); -} - -static u3_noun -_cue_loop(u3_atom a) -{ - c3_w i_w, max_w = 20000; - - for ( i_w = 0; i_w < max_w; i_w++ ) { - u3z(u3s_cue(a)); - } - - return u3_blip; -} - -static u3_noun -_cue_atom_loop(u3_atom a) -{ - c3_w i_w, max_w = 20000; - - for ( i_w = 0; i_w < max_w; i_w++ ) { - u3z(u3s_cue_atom(a)); - } - - return u3_blip; -} - -static void -_cue_soft_bench(void) -{ - struct timeval b4, f2, d0; - u3_atom vat = u3ke_jam(_ames_writ_ex()); - c3_w mil_w; - - fprintf(stderr, "\r\ncue virtual microbenchmark:\r\n"); - - { - gettimeofday(&b4, 0); - - u3z(u3m_soft(0, _cue_loop, u3k(vat))); - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - fprintf(stderr, " cue virtual og: %u ms\r\n", mil_w); - } - - { - gettimeofday(&b4, 0); - - u3z(u3m_soft(0, _cue_atom_loop, u3k(vat))); - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - mil_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - fprintf(stderr, " cue virtual atom: %u ms\r\n", mil_w); - } - - u3z(vat); -} - -/* main(): run all benchmarks -*/ -int -main(int argc, char* argv[]) -{ - _setup(); - - _jam_bench(); - _cue_bench(); - _cue_soft_bench(); - - // GC - // - u3m_grab(u3_none); - - return 0; -} diff --git a/pkg/urbit/compat/create-include-files.sh b/pkg/urbit/compat/create-include-files.sh deleted file mode 100755 index 34b87cb52..000000000 --- a/pkg/urbit/compat/create-include-files.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -# support running off a tarball that doesn't contain binary pills -(( $($1 ../../bin/ivory.pill) > 512 )) || curl -L https://github.com/urbit/urbit/raw/urbit-v$URBIT_VERSION/bin/ivory.pill > ../../bin/ivory.pill - -poor_mans_xxd () { - cch=0 - echo "unsigned char $2[] = {" - while IFS='' read line - do - for i in $line - do - echo -n " 0x$i," - cch=$((cch+1)) - done - echo - done < <(od -An -v -tx1 $1) - echo "};" - echo "unsigned int $2_len = $cch;" -} - -[ -e include/ca-bundle.h ] || poor_mans_xxd $2 include_ca_bundle_crt >include/ca-bundle.h -[ -e include/ivory_impl.h ] || poor_mans_xxd ../../bin/ivory.pill u3_Ivory_pill >include/ivory_impl.h diff --git a/pkg/urbit/compat/m1brew/compat.mk b/pkg/urbit/compat/m1brew/compat.mk deleted file mode 100644 index 5d612ba84..000000000 --- a/pkg/urbit/compat/m1brew/compat.mk +++ /dev/null @@ -1,14 +0,0 @@ -# paths to brew packages -CFLAGS := $(CFLAGS) -I/opt/homebrew/include -LDFLAGS := $(LDFLAGS) -L/opt/homebrew/lib -# force linker to use static libraries -LDFLAGS := $(shell compat/m1brew/use-static-libs.sh $(LDFLAGS)) -# add extra osx libraries -LDFLAGS := $(LDFLAGS) -framework SystemConfiguration - -ifdef debug -CFLAGS := $(CFLAGS) -O0 -g -else -# clang hangs on noun/allocate.c if -g is specified with -O3 -CFLAGS := $(CFLAGS) -O3 -endif diff --git a/pkg/urbit/compat/m1brew/ent.patch b/pkg/urbit/compat/m1brew/ent.patch deleted file mode 100644 index f26edf7a8..000000000 --- a/pkg/urbit/compat/m1brew/ent.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/configure b/configure ---- a/configure -+++ b/configure -@@ -15,7 +15,7 @@ do - log "Trying IMPL=$IMPL" - - if IMPL=$impl make >/dev/null 2>/dev/null -- then sed -i 's|$(error IMPL must be set)|IMPL='"$impl"'|' Makefile -+ then sed -i "" 's|$(error IMPL must be set)|IMPL='"$impl"'|' Makefile - log "IMPL=$IMPL works" - exit 0 - else log "IMPL=$IMPL failed" diff --git a/pkg/urbit/compat/m1brew/murmur3.patch b/pkg/urbit/compat/m1brew/murmur3.patch deleted file mode 100644 index cd83e9fdd..000000000 --- a/pkg/urbit/compat/m1brew/murmur3.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/makefile b/makefile ---- a/makefile -+++ b/makefile -@@ -12,5 +12,9 @@ shared: murmur3.c murmur3.h - $(CC) -fPIC -O3 -c murmur3.c - $(CC) -shared -Wl,--export-dynamic murmur3.o -o libmurmur3.so - -+static: murmur3.c murmur3.h -+ $(CC) -fPIC -O3 -c murmur3.c -+ $(AR) rcs libmurmur3.a murmur3.o -+ - clean: - rm -rf example *.o *.so diff --git a/pkg/urbit/compat/m1brew/softfloat3.patch b/pkg/urbit/compat/m1brew/softfloat3.patch deleted file mode 100644 index 888d566f4..000000000 --- a/pkg/urbit/compat/m1brew/softfloat3.patch +++ /dev/null @@ -1,85 +0,0 @@ -diff --git a/build/template-FAST_INT64/Makefile b/build/template-FAST_INT64/Makefile ---- a/build/template-FAST_INT64/Makefile -+++ b/build/template-FAST_INT64/Makefile -@@ -34,28 +34,27 @@ - # - #============================================================================= - --# Edit lines marked with `==>'. See "SoftFloat-source.html". -+SOURCE_DIR ?= ../../source -+SPECIALIZE_TYPE ?= 8086-SSE - --==> SOURCE_DIR ?= ../../source --==> SPECIALIZE_TYPE ?= 8086 -+SOFTFLOAT_OPTS ?= \ -+ -DSOFTFLOAT_ROUND_ODD -DINLINE_LEVEL=5 -DSOFTFLOAT_FAST_DIV32TO16 \ -+ -DSOFTFLOAT_FAST_DIV64TO32 - --==> SOFTFLOAT_OPTS ?= \ --==> -DSOFTFLOAT_ROUND_ODD -DINLINE_LEVEL=5 -DSOFTFLOAT_FAST_DIV32TO16 \ --==> -DSOFTFLOAT_FAST_DIV64TO32 -+DELETE = rm -f -+C_INCLUDES = -I. -I$(SOURCE_DIR)/$(SPECIALIZE_TYPE) -I$(SOURCE_DIR)/include -+COMPILE_C = \ -+ cc -c -DSOFTFLOAT_FAST_INT64 $(SOFTFLOAT_OPTS) $(C_INCLUDES) -O2 -o $@ -+MAKELIB = ar crs $@ -+LIBNAME = libsoftfloat3 - --==> DELETE = rm -f --==> C_INCLUDES = -I. -I$(SOURCE_DIR)/$(SPECIALIZE_TYPE) -I$(SOURCE_DIR)/include --==> COMPILE_C = \ --==> cc -c -DSOFTFLOAT_FAST_INT64 $(SOFTFLOAT_OPTS) $(C_INCLUDES) -O2 -o $@ --==> MAKELIB = ar crs $@ -+OBJ = .o -+LIB = .a - --==> OBJ = .o --==> LIB = .a -- --==> OTHER_HEADERS = -+OTHER_HEADERS = - - .PHONY: all --all: softfloat$(LIB) -+all: $(LIBNAME)$(LIB) - - OBJS_PRIMITIVES = \ - s_eq128$(OBJ) \ -@@ -381,11 +380,11 @@ $(OBJS_PRIMITIVES) $(OBJS_OTHERS): %$(OBJ): $(SOURCE_DIR)/%.c - $(OBJS_SPECIALIZE): %$(OBJ): $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/%.c - $(COMPILE_C) $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/$*.c - --softfloat$(LIB): $(OBJS_ALL) -+$(LIBNAME)$(LIB): $(OBJS_ALL) - $(DELETE) $@ - $(MAKELIB) $^ - - .PHONY: clean - clean: -- $(DELETE) $(OBJS_ALL) softfloat$(LIB) -+ $(DELETE) $(OBJS_ALL) $(LIBNAME)$(LIB) - -diff --git a/build/template-FAST_INT64/platform.h b/build/template-FAST_INT64/platform.h ---- a/build/template-FAST_INT64/platform.h -+++ b/build/template-FAST_INT64/platform.h -@@ -34,17 +34,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - =============================================================================*/ - --// Edit lines marked with `==>'. See "SoftFloat-source.html". -- - /*---------------------------------------------------------------------------- - *----------------------------------------------------------------------------*/ --==> #define LITTLEENDIAN 1 -+#define LITTLEENDIAN 1 - - /*---------------------------------------------------------------------------- - *----------------------------------------------------------------------------*/ --==> #define INLINE inline -+#define INLINE inline - - /*---------------------------------------------------------------------------- - *----------------------------------------------------------------------------*/ --==> #define THREAD_LOCAL _Thread_local -+#define THREAD_LOCAL _Thread_local - diff --git a/pkg/urbit/compat/m1brew/use-static-libs.sh b/pkg/urbit/compat/m1brew/use-static-libs.sh deleted file mode 100755 index 7f7cf83a1..000000000 --- a/pkg/urbit/compat/m1brew/use-static-libs.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -set -euo pipefail -declare -a ldirs -for i in $@ -do - case $i in - -L*) ldirs+=(${i:2});; - esac -done -for i in $@ -do - case $i in - -l*) - lib=$(find ${ldirs[@]} -name lib${i:2}.a) - if [ "$lib" != "" ] - then - echo $lib - else - echo $i - fi;; - *) echo $i;; - esac -done diff --git a/pkg/urbit/compat/mingw/compat.c b/pkg/urbit/compat/mingw/compat.c deleted file mode 100644 index ebef5041f..000000000 --- a/pkg/urbit/compat/mingw/compat.c +++ /dev/null @@ -1,377 +0,0 @@ -#include "c/portable.h" -#include -#include -#include - -// set default CRT file mode to binary -// note that mingw binmode.o does nothing -#undef _fmode -int _fmode = _O_BINARY; - -// set standard I/O fds to binary too, because -// MSVCRT creates them before MingW sets _fmode -static void __attribute__ ((constructor)) _set_stdio_to_binary() -{ - _setmode(0, _O_BINARY); - _setmode(1, _O_BINARY); - _setmode(2, _O_BINARY); -} - -// from https://github.com/git/git/blob/master/compat/mingw.c -// ----------------------------------------------------------------------- - -int err_win_to_posix(DWORD winerr) -{ - int error = ENOSYS; - switch(winerr) { - case ERROR_ACCESS_DENIED: error = EACCES; break; - case ERROR_ACCOUNT_DISABLED: error = EACCES; break; - case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break; - case ERROR_ALREADY_ASSIGNED: error = EBUSY; break; - case ERROR_ALREADY_EXISTS: error = EEXIST; break; - case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break; - case ERROR_BAD_COMMAND: error = EIO; break; - case ERROR_BAD_DEVICE: error = ENODEV; break; - case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break; - case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break; - case ERROR_BAD_FORMAT: error = ENOEXEC; break; - case ERROR_BAD_LENGTH: error = EINVAL; break; - case ERROR_BAD_PATHNAME: error = ENOENT; break; - case ERROR_BAD_PIPE: error = EPIPE; break; - case ERROR_BAD_UNIT: error = ENODEV; break; - case ERROR_BAD_USERNAME: error = EINVAL; break; - case ERROR_BROKEN_PIPE: error = EPIPE; break; - case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break; - case ERROR_BUSY: error = EBUSY; break; - case ERROR_BUSY_DRIVE: error = EBUSY; break; - case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break; - case ERROR_CANNOT_MAKE: error = EACCES; break; - case ERROR_CANTOPEN: error = EIO; break; - case ERROR_CANTREAD: error = EIO; break; - case ERROR_CANTWRITE: error = EIO; break; - case ERROR_CRC: error = EIO; break; - case ERROR_CURRENT_DIRECTORY: error = EACCES; break; - case ERROR_DEVICE_IN_USE: error = EBUSY; break; - case ERROR_DEV_NOT_EXIST: error = ENODEV; break; - case ERROR_DIRECTORY: error = EINVAL; break; - case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break; - case ERROR_DISK_CHANGE: error = EIO; break; - case ERROR_DISK_FULL: error = ENOSPC; break; - case ERROR_DRIVE_LOCKED: error = EBUSY; break; - case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break; - case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break; - case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break; - case ERROR_FILE_EXISTS: error = EEXIST; break; - case ERROR_FILE_INVALID: error = ENODEV; break; - case ERROR_FILE_NOT_FOUND: error = ENOENT; break; - case ERROR_GEN_FAILURE: error = EIO; break; - case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break; - case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break; - case ERROR_INVALID_ACCESS: error = EACCES; break; - case ERROR_INVALID_ADDRESS: error = EFAULT; break; - case ERROR_INVALID_BLOCK: error = EFAULT; break; - case ERROR_INVALID_DATA: error = EINVAL; break; - case ERROR_INVALID_DRIVE: error = ENODEV; break; - case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break; - case ERROR_INVALID_FLAGS: error = EINVAL; break; - case ERROR_INVALID_FUNCTION: error = ENOSYS; break; - case ERROR_INVALID_HANDLE: error = EBADF; break; - case ERROR_INVALID_LOGON_HOURS: error = EACCES; break; - case ERROR_INVALID_NAME: error = EINVAL; break; - case ERROR_INVALID_OWNER: error = EINVAL; break; - case ERROR_INVALID_PARAMETER: error = EINVAL; break; - case ERROR_INVALID_PASSWORD: error = EPERM; break; - case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break; - case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break; - case ERROR_INVALID_TARGET_HANDLE: error = EIO; break; - case ERROR_INVALID_WORKSTATION: error = EACCES; break; - case ERROR_IO_DEVICE: error = EIO; break; - case ERROR_IO_INCOMPLETE: error = EINTR; break; - case ERROR_LOCKED: error = EBUSY; break; - case ERROR_LOCK_VIOLATION: error = EACCES; break; - case ERROR_LOGON_FAILURE: error = EACCES; break; - case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break; - case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break; - case ERROR_MORE_DATA: error = EPIPE; break; - case ERROR_NEGATIVE_SEEK: error = ESPIPE; break; - case ERROR_NOACCESS: error = EFAULT; break; - case ERROR_NONE_MAPPED: error = EINVAL; break; - case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break; - case ERROR_NOT_READY: error = EAGAIN; break; - case ERROR_NOT_SAME_DEVICE: error = EXDEV; break; - case ERROR_NO_DATA: error = EPIPE; break; - case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break; - case ERROR_NO_PROC_SLOTS: error = EAGAIN; break; - case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break; - case ERROR_OPEN_FAILED: error = EIO; break; - case ERROR_OPEN_FILES: error = EBUSY; break; - case ERROR_OPERATION_ABORTED: error = EINTR; break; - case ERROR_OUTOFMEMORY: error = ENOMEM; break; - case ERROR_PASSWORD_EXPIRED: error = EACCES; break; - case ERROR_PATH_BUSY: error = EBUSY; break; - case ERROR_PATH_NOT_FOUND: error = ENOENT; break; - case ERROR_PIPE_BUSY: error = EBUSY; break; - case ERROR_PIPE_CONNECTED: error = EPIPE; break; - case ERROR_PIPE_LISTENING: error = EPIPE; break; - case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break; - case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break; - case ERROR_READ_FAULT: error = EIO; break; - case ERROR_SEEK: error = EIO; break; - case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break; - case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break; - case ERROR_SHARING_VIOLATION: error = EACCES; break; - case ERROR_STACK_OVERFLOW: error = ENOMEM; break; - case ERROR_SUCCESS: error = 0; break; - case ERROR_SWAPERROR: error = ENOENT; break; - case ERROR_TOO_MANY_MODULES: error = EMFILE; break; - case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break; - case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break; - case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break; - case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break; - case ERROR_WRITE_FAULT: error = EIO; break; - case ERROR_WRITE_PROTECT: error = EROFS; break; - } - return error; -} - -int link(const char *path1, const char *path2) -{ - if ( CreateHardLinkA(path2, path1, NULL) ) { - return 0; - } - - errno = err_win_to_posix(GetLastError()); - return -1; -} - -// from msys2 mingw-packages-dev patches -// ----------------------------------------------------------------------- - -static DWORD __map_mmap_prot_page(const int prot) -{ - DWORD protect = 0; - - if (prot == PROT_NONE) - return protect; - - if ((prot & PROT_EXEC) != 0) - { - protect = ((prot & PROT_WRITE) != 0) ? - PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ; - } - else - { - protect = ((prot & PROT_WRITE) != 0) ? - PAGE_READWRITE : PAGE_READONLY; - } - - return protect; -} - -static DWORD __map_mmap_prot_file(const int prot) -{ - DWORD desiredAccess = 0; - - if (prot == PROT_NONE) - return desiredAccess; - - if ((prot & PROT_READ) != 0) - desiredAccess |= FILE_MAP_READ; - if ((prot & PROT_WRITE) != 0) - desiredAccess |= FILE_MAP_WRITE; - if ((prot & PROT_EXEC) != 0) - desiredAccess |= FILE_MAP_EXECUTE; - - return desiredAccess; -} - -void* mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) -{ - HANDLE fm, h; - - void * map = MAP_FAILED; - - const DWORD dwFileOffsetLow = (sizeof(off_t) <= sizeof(DWORD)) ? - (DWORD)off : (DWORD)(off & 0xFFFFFFFFL); - const DWORD dwFileOffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) ? - (DWORD)0 : (DWORD)((off >> 32) & 0xFFFFFFFFL); - const DWORD protect = __map_mmap_prot_page(prot); - const DWORD desiredAccess = __map_mmap_prot_file(prot); - - errno = 0; - - if (len == 0 - /* Usupported protection combinations */ - || prot == PROT_EXEC) - { - errno = EINVAL; - return MAP_FAILED; - } - - if ((flags & MAP_ANON) == 0) - { - h = (HANDLE)_get_osfhandle(fildes); - - if (h == INVALID_HANDLE_VALUE) - { - errno = EBADF; - return MAP_FAILED; - } - } - else h = INVALID_HANDLE_VALUE; - - fm = CreateFileMapping(h, NULL, protect, 0, len, NULL); - - if (fm == NULL) - { - errno = err_win_to_posix(GetLastError()); - return MAP_FAILED; - } - - map = MapViewOfFileEx(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len, addr); - errno = err_win_to_posix(GetLastError()); - - CloseHandle(fm); - - if (map == NULL) - return MAP_FAILED; - - if ((flags & MAP_FIXED) != 0 && map != addr) - { - UnmapViewOfFile(map); - errno = EEXIST; - return MAP_FAILED; - } - - return map; -} - -int munmap(void *addr, size_t len) -{ - if (UnmapViewOfFile(addr)) - return 0; - - errno = err_win_to_posix(GetLastError()); - return -1; -} - -int msync(void *addr, size_t len, int flags) -{ - if (FlushViewOfFile(addr, len)) - return 0; - - errno = err_win_to_posix(GetLastError()); - return -1; -} - -// ----------------------------------------------------------------------- - -// vere uses kill() only to kill lockfile owner with SIGTERM or SIGKILL -// Windows does not have signals, so I handle SIGKILL as TerminateProcess() -// and return an error in all other cases -int kill(pid_t pid, int sig) -{ - if (pid > 0 && sig == SIGKILL) { - HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid); - - if (TerminateProcess(h, -1)) { - CloseHandle(h); - return 0; - } - - errno = err_win_to_posix(GetLastError()); - CloseHandle(h); - return -1; - } - - errno = EINVAL; - return -1; -} - -// libgcc built for mingw has included an implementation of mprotect -// via VirtualProtect since olden days, but it takes int rather than size_t -// and therefore fails or does unexpected things for >2GB blocks on 64-bit -// https://github.com/gcc-mirror/gcc/blob/master/libgcc/libgcc2.c -int mprotect (void *addr, size_t len, int prot) -{ - DWORD np, op; - - if (prot == (PROT_READ | PROT_WRITE | PROT_EXEC)) - np = PAGE_EXECUTE_READWRITE; - else if (prot == (PROT_READ | PROT_EXEC)) - np = PAGE_EXECUTE_READ; - else if (prot == (PROT_EXEC)) - np = PAGE_EXECUTE; - else if (prot == (PROT_READ | PROT_WRITE)) - np = PAGE_READWRITE; - else if (prot == (PROT_READ)) - np = PAGE_READONLY; - else if (prot == 0) - np = PAGE_NOACCESS; - else - { - errno = EINVAL; - return -1; - } - - if (VirtualProtect (addr, len, np, &op)) - return 0; - - // NB: return code of ntdll!RtlGetLastNtStatus() is useful - // for diagnosing obscure VirtualProtect failures - errno = err_win_to_posix(GetLastError()); - return -1; -} - -int utimes(const char *path, const struct timeval times[2]) -{ - struct _utimbuf utb = {.actime = times[0].tv_sec, .modtime = times[1].tv_sec}; - return _utime(path, &utb); -} - -int fdatasync(int fildes) -{ - HANDLE h = (HANDLE)_get_osfhandle(fildes); - - if (h == INVALID_HANDLE_VALUE) - { - errno = EBADF; - return -1; - } - - if (FlushFileBuffers(h)) - { - errno = 0; - return 0; - } - else - { - errno = err_win_to_posix(GetLastError()); - return -1; - } -} - -intmax_t mdb_get_filesize(HANDLE han_u) -{ - LARGE_INTEGER li; - GetFileSizeEx(han_u, &li); - return li.QuadPart; -} - -char *realpath(const char *path, char *resolved_path) -{ - // XX MAX_PATH - // - return _fullpath(resolved_path, path, MAX_PATH); -} - -long sysconf(int name) -{ - SYSTEM_INFO si; - - if ( _SC_PAGESIZE != name ) { - return -1; - } - GetNativeSystemInfo(&si); - return si.dwPageSize; -} diff --git a/pkg/urbit/compat/mingw/compat.h b/pkg/urbit/compat/mingw/compat.h deleted file mode 100644 index 56c35e90a..000000000 --- a/pkg/urbit/compat/mingw/compat.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _MINGW_IO_H -#define _MINGW_IO_H - -#define mkdir(A, B) mkdir(A) - -int link(const char *path1, const char *path2); -char *realpath(const char *path, char *resolved_path); -int fdatasync(int fd); -int utimes(const char *path, const struct timeval times[2]); -long sysconf(int name); - -int kill(pid_t pid, int signum); - -#define SIGUSR1 10 -#define SIGALRM 14 -#define SIGVTALRM 26 -#define SIGSTK 31 -#define SIG_COUNT 32 -#define _SC_PAGESIZE 29 - -#endif//_MINGW_IO_H diff --git a/pkg/urbit/compat/mingw/compat.mk b/pkg/urbit/compat/mingw/compat.mk deleted file mode 100644 index 8add2a3b6..000000000 --- a/pkg/urbit/compat/mingw/compat.mk +++ /dev/null @@ -1,17 +0,0 @@ -# increase default thread stack size and link Windows implibs -LDFLAGS := $(LDFLAGS) -static -Wl,--stack,67108864 -lbcrypt -lntdll -lws2_32 -# libcurl -CFLAGS := $(CFLAGS) -DCURL_STATICLIB -LDFLAGS := $(LDFLAGS) -lzstd -lcrypt32 -# libh2o -CFLAGS := $(CFLAGS) -DH2O_NO_UNIX_SOCKETS -# libuv -LDFLAGS := $(LDFLAGS) -luserenv -liphlpapi -lpsapi -# secp256k1, due to _FORTIFY_SOURCE -LDFLAGS := $(LDFLAGS) -lssp - -ifdef debug -CFLAGS := $(CFLAGS) -O0 -g -else -CFLAGS := $(CFLAGS) -O3 -g -endif diff --git a/pkg/urbit/compat/mingw/ctrlc.c b/pkg/urbit/compat/mingw/ctrlc.c deleted file mode 100644 index 9be57981b..000000000 --- a/pkg/urbit/compat/mingw/ctrlc.c +++ /dev/null @@ -1,7 +0,0 @@ -#include - -// initialize msvcrt signals early, otherwise Ctrl-C does nothing -static void __attribute__ ((constructor)) _init_crt_signals() -{ - signal(SIGINT, SIG_DFL); -} diff --git a/pkg/urbit/compat/mingw/daemon.c b/pkg/urbit/compat/mingw/daemon.c deleted file mode 100644 index 46e73b0ea..000000000 --- a/pkg/urbit/compat/mingw/daemon.c +++ /dev/null @@ -1,116 +0,0 @@ -#include "all.h" -#include "vere/vere.h" - -/* _dup_std_handle(): creates an inheritable duplicate of a standard handle. -*/ -static BOOL -_dup_std_handle(HANDLE* new_u, DWORD typ_u) -{ - DWORD dum_u; - HANDLE han_u = GetStdHandle(typ_u); - BOOL con_u = GetConsoleMode(han_u, &dum_u); - if ( con_u ) { - han_u = (HANDLE)_get_osfhandle(c3_open(c3_dev_null, O_RDWR, 0)); - } - - if ( !DuplicateHandle(GetCurrentProcess(), han_u, GetCurrentProcess(), new_u, 0, TRUE, DUPLICATE_SAME_ACCESS) ) { - fprintf(stderr, "vere: DuplicateHandle(%d): %d\r\n", typ_u, GetLastError()); - exit(1); - } - - return con_u; -} - -/* _on_boot_completed_cb: invoked when the ship has finished booting. -*/ -static void _on_boot_completed_cb() { - HANDLE hin_u = GetStdHandle(STD_INPUT_HANDLE); - SetEvent(hin_u); - CloseHandle(hin_u); -} - -/* u3_daemon_init(): platform-specific daemon mode initialization. -*/ -void -u3_daemon_init() -{ - // detect if this process is the child daemon process - // - if ( ResetEvent(GetStdHandle(STD_INPUT_HANDLE)) ) { - u3_Host.bot_f = _on_boot_completed_cb; - return; - } - - STARTUPINFOW psi_u; - ZeroMemory(&psi_u, sizeof(psi_u)); - psi_u.cb = sizeof(psi_u); - psi_u.dwFlags = STARTF_USESTDHANDLES; - - // duplicate standard output and error handles for the child process, - // replacing any raw console handles with handles to /dev/null - // print a warning if raw console output detected - // - // On Windows, console handles become invalid once the console is - // detached. This will cause urbit terminal output to fail. libuv - // provides no way of changing the handle of an open uv_pipe_handle, - // and Windows has no equivalent of dup2() for handles, so I cannot - // substitute a /dev/null handle once the terminal is initialized. - // It is possible to create an anonymous pipe and have the child - // process take over its drain end after it signals that the ship - // has booted, but -d is intended for background operation anyway - // and does not seem to warrant the added complexity. - // - if ( _dup_std_handle(&psi_u.hStdOutput, STD_OUTPUT_HANDLE) | - _dup_std_handle(&psi_u.hStdError, STD_ERROR_HANDLE) ) - { - fprintf(stderr, "vere: -d used from a Windows console without redirection\r\n" - " no output from the daemon process will be visible\r\n"); - fflush(stderr); - } - - // create an event for the child process to signal - // the parent that the ship has finished booting - // pass the handle as "stdin" (otherwise unused with -d) - // - SECURITY_ATTRIBUTES sa_u = {sizeof (SECURITY_ATTRIBUTES), NULL, TRUE}; - if ( !(psi_u.hStdInput = CreateEvent(&sa_u, TRUE, FALSE, NULL)) ) { - fprintf(stderr, "vere: CreateEvent: %d\r\n", GetLastError()); - exit(1); - } - - // create the child process with the same command line as parent - // it will start, re-parse the command line, and call u3_daemon_init - // - PROCESS_INFORMATION ppi_u; - if ( !CreateProcessW(NULL, _wcsdup(GetCommandLineW()), NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &psi_u, &ppi_u) ) { - fprintf(stderr, "vere: CreateProcess: %d\r\n", GetLastError()); - exit(1); - } - - CloseHandle(ppi_u.hThread); - - // wait for the child process to exit or to signal the event - // - DWORD exi_u; - HANDLE han_u[2] = {ppi_u.hProcess, psi_u.hStdInput}; - switch ( WaitForMultipleObjects(2, han_u, FALSE, INFINITE) ) { - case WAIT_OBJECT_0: - // the child process exited prematurely, propagate its exit code - // - if ( GetExitCodeProcess(ppi_u.hProcess, &exi_u) ) { - exit(exi_u); - } - - fprintf(stderr, "vere: GetExitCodeProcess: %d\r\n", GetLastError()); - exit(1); - - case WAIT_OBJECT_0 + 1: - // the child process has finished booting, exit normally - // - exit(0); - - default: - fprintf(stderr, "vere: WaitForMultipleObjects: %d\r\n", GetLastError()); - exit(1); - } -} diff --git a/pkg/urbit/compat/mingw/h2o.patch b/pkg/urbit/compat/mingw/h2o.patch deleted file mode 100644 index 1bfc90e4a..000000000 --- a/pkg/urbit/compat/mingw/h2o.patch +++ /dev/null @@ -1,1834 +0,0 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 5a04e1426..9ddad60d1 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -69,6 +69,18 @@ OPTION(WITH_BUNDLED_SSL "whether or not to use the bundled libressl" ${WITH_BUND - - OPTION(WITHOUT_LIBS "skip building libs even when possible" OFF) - OPTION(BUILD_SHARED_LIBS "whether to build a shared library" OFF) -+OPTION(WITHOUT_FASTCGI "don't include fastcgi" OFF) -+OPTION(WITHOUT_MEMCACHED "don't include memcached" OFF) -+ -+IF (MINGW) -+ SET(WITHOUT_FASTCGI "ON") -+ SET(WITHOUT_MEMCACHED "ON") -+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_POSIX_C_SOURCE -DO_CLOEXEC=0 -DH2O_NO_UNIX_SOCKETS") -+ENDIF (MINGW) -+ -+IF (WITHOUT_MEMCACHED) -+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DH2O_NO_MEMCACHED") -+ENDIF (WITHOUT_MEMCACHED) - - FIND_PROGRAM(RUBY ruby) - FIND_PROGRAM(BISON bison) -@@ -228,16 +240,7 @@ SET(PICOTLS_SOURCE_FILES - deps/picotls/lib/openssl.c) - - SET(LIB_SOURCE_FILES -- deps/cloexec/cloexec.c - deps/libgkc/gkc.c -- deps/libyrmcds/close.c -- deps/libyrmcds/connect.c -- deps/libyrmcds/recv.c -- deps/libyrmcds/send.c -- deps/libyrmcds/send_text.c -- deps/libyrmcds/socket.c -- deps/libyrmcds/strerror.c -- deps/libyrmcds/text_mode.c - deps/picohttpparser/picohttpparser.c - - lib/common/cache.c -@@ -245,7 +248,6 @@ SET(LIB_SOURCE_FILES - lib/common/filecache.c - lib/common/hostinfo.c - lib/common/http1client.c -- lib/common/memcached.c - lib/common/memory.c - lib/common/multithread.c - lib/common/serverutil.c -@@ -272,7 +274,6 @@ SET(LIB_SOURCE_FILES - lib/handler/compress/gzip.c - lib/handler/errordoc.c - lib/handler/expires.c -- lib/handler/fastcgi.c - lib/handler/file.c - lib/handler/headers.c - lib/handler/mimemap.c -@@ -290,7 +291,6 @@ SET(LIB_SOURCE_FILES - lib/handler/configurator/compress.c - lib/handler/configurator/errordoc.c - lib/handler/configurator/expires.c -- lib/handler/configurator/fastcgi.c - lib/handler/configurator/file.c - lib/handler/configurator/headers.c - lib/handler/configurator/proxy.c -@@ -314,6 +314,33 @@ SET(LIB_SOURCE_FILES - lib/http2/stream.c - lib/http2/http2_debug_state.c) - -+IF (NOT MINGW) -+ SET(LIB_SOURCE_FILES -+ ${LIB_SOURCE_FILES} -+ deps/cloexec/cloexec.c) -+ENDIF (NOT MINGW) -+ -+IF (NOT WITHOUT_FASTCGI) -+ SET(LIB_SOURCE_FILES -+ ${LIB_SOURCE_FILES} -+ lib/handler/fastcgi.c -+ lib/handler/configurator/fastcgi.c) -+ENDIF (NOT WITHOUT_FASTCGI) -+ -+IF (NOT WITHOUT_MEMCACHED) -+ SET(LIB_SOURCE_FILES -+ ${LIB_SOURCE_FILES} -+ deps/libyrmcds/close.c -+ deps/libyrmcds/connect.c -+ deps/libyrmcds/recv.c -+ deps/libyrmcds/send.c -+ deps/libyrmcds/send_text.c -+ deps/libyrmcds/socket.c -+ deps/libyrmcds/strerror.c -+ deps/libyrmcds/text_mode.c -+ lib/common/memcached.c) -+ENDIF (NOT WITHOUT_MEMCACHED) -+ - SET(UNIT_TEST_SOURCE_FILES - ${LIB_SOURCE_FILES} - ${LIBYAML_SOURCE_FILES} -diff --git a/examples/libh2o/http1client.c b/examples/libh2o/http1client.c -index bcf9b94b2..592376759 100644 ---- a/examples/libh2o/http1client.c -+++ b/examples/libh2o/http1client.c -@@ -134,6 +134,11 @@ h2o_http1client_head_cb on_connect(h2o_http1client_t *client, const char *errstr - - int main(int argc, char **argv) - { -+#ifdef _WIN32 -+ WSADATA wsaData; -+ WSAStartup(MAKEWORD(2, 0), &wsaData); -+#endif -+ - h2o_multithread_queue_t *queue; - h2o_multithread_receiver_t getaddr_receiver; - h2o_timeout_t io_timeout; -diff --git a/examples/libh2o/simple.c b/examples/libh2o/simple.c -index bb72bf60c..be7045d1c 100644 ---- a/examples/libh2o/simple.c -+++ b/examples/libh2o/simple.c -@@ -21,11 +21,15 @@ - */ - #include - #include --#include - #include - #include - #include -+#ifdef _WIN32 -+#include -+#else -+#include - #include -+#endif - #include - #include "h2o.h" - #include "h2o/http1.h" -@@ -219,7 +223,12 @@ int main(int argc, char **argv) - { - h2o_hostconf_t *hostconf; - -+#ifdef _WIN32 -+ WSADATA wsaData; -+ WSAStartup(MAKEWORD(2, 0), &wsaData); -+#else - signal(SIGPIPE, SIG_IGN); -+#endif - - h2o_config_init(&config); - hostconf = h2o_config_register_host(&config, h2o_iovec_init(H2O_STRLIT("default")), 65535); -diff --git a/include/h2o.h b/include/h2o.h -index 57877bd12..84822b792 100644 ---- a/include/h2o.h -+++ b/include/h2o.h -@@ -32,7 +32,11 @@ extern "C" { - #include - #include - #include -+#ifdef _WIN32 -+#include -+#else - #include -+#endif - #include - #include - #include -diff --git a/include/h2o/configurator.h b/include/h2o/configurator.h -index d1a2e2515..d59d070dd 100644 ---- a/include/h2o/configurator.h -+++ b/include/h2o/configurator.h -@@ -145,7 +145,7 @@ int h2o_configurator_apply_commands(h2o_configurator_context_t *ctx, yoml_t *nod - * emits configuration error - */ - void h2o_configurator_errprintf(h2o_configurator_command_t *cmd, yoml_t *node, const char *reason, ...) -- __attribute__((format(printf, 3, 4))); -+ __attribute__((format(gnu_printf, 3, 4))); - /** - * interprets the configuration value using sscanf, or prints an error upon failure - * @param configurator configurator -@@ -154,7 +154,7 @@ void h2o_configurator_errprintf(h2o_configurator_command_t *cmd, yoml_t *node, c - * @return 0 if successful, -1 if not - */ - int h2o_configurator_scanf(h2o_configurator_command_t *cmd, yoml_t *node, const char *fmt, ...) -- __attribute__((format(scanf, 3, 4))); -+ __attribute__((format(gnu_scanf, 3, 4))); - /** - * interprets the configuration value and returns the index of the matched string within the candidate strings, or prints an error - * upon failure -diff --git a/include/h2o/filecache.h b/include/h2o/filecache.h -index a000c4c6d..494f61fb1 100644 ---- a/include/h2o/filecache.h -+++ b/include/h2o/filecache.h -@@ -61,6 +61,7 @@ void h2o_filecache_destroy(h2o_filecache_t *cache); - void h2o_filecache_clear(h2o_filecache_t *cache); - - h2o_filecache_ref_t *h2o_filecache_open_file(h2o_filecache_t *cache, const char *path, int oflag); -+ssize_t h2o_filecache_read_file(h2o_filecache_ref_t *ref, void *buf, size_t count, off_t offset); - void h2o_filecache_close_file(h2o_filecache_ref_t *ref); - struct tm *h2o_filecache_get_last_modified(h2o_filecache_ref_t *ref, char *outbuf); - size_t h2o_filecache_get_etag(h2o_filecache_ref_t *ref, char *outbuf); -diff --git a/include/h2o/hostinfo.h b/include/h2o/hostinfo.h -index 14ac30c6c..b39fea520 100644 ---- a/include/h2o/hostinfo.h -+++ b/include/h2o/hostinfo.h -@@ -22,13 +22,16 @@ - #ifndef h2o__hostinfo_h - #define h2o__hostinfo_h - --#include -+#ifdef _WIN32 -+#include -+#else - #include - #include - #include - #include - #include - #include -+#endif - #include "h2o/multithread.h" - - typedef struct st_h2o_hostinfo_getaddr_req_t h2o_hostinfo_getaddr_req_t; -diff --git a/include/h2o/memory.h b/include/h2o/memory.h -index 10c137c88..354fa4359 100644 ---- a/include/h2o/memory.h -+++ b/include/h2o/memory.h -@@ -78,8 +78,19 @@ typedef struct st_h2o_buffer_prototype_t h2o_buffer_prototype_t; - * buffer structure compatible with iovec - */ - typedef struct st_h2o_iovec_t { -+#ifdef __MINGW32__ -+#define H2O_IOVEC_NULL {0, NULL} -+#define H2O_IOVEC_EMPTY {0, ""} -+#define H2O_IOVEC_STRLIT(s) {sizeof(s) - 1, (s)} -+ unsigned int len; -+ char *base; -+#else -+#define H2O_IOVEC_NULL {NULL} -+#define H2O_IOVEC_EMPTY {"", 0} -+#define H2O_IOVEC_STRLIT(s) {(s), sizeof(s) - 1} - char *base; - size_t len; -+#endif - } h2o_iovec_t; - - typedef struct st_h2o_mem_recycle_t { -diff --git a/include/h2o/socket.h b/include/h2o/socket.h -index 58ada8509..268dd8a2e 100644 ---- a/include/h2o/socket.h -+++ b/include/h2o/socket.h -@@ -27,7 +27,11 @@ extern "C" { - #endif - - #include -+#ifdef _WIN32 -+#include -+#else - #include -+#endif - #include - #include "h2o/cache.h" - #include "h2o/memory.h" -diff --git a/include/h2o/socketpool.h b/include/h2o/socketpool.h -index cc4161df4..f1c4eb3c3 100644 ---- a/include/h2o/socketpool.h -+++ b/include/h2o/socketpool.h -@@ -26,8 +26,10 @@ - extern "C" { - #endif - -+#ifndef _WIN32 - #include - #include -+#endif - #include - #include "h2o/linklist.h" - #include "h2o/multithread.h" -diff --git a/include/h2o/url.h b/include/h2o/url.h -index 231c9a263..6a707a567 100644 ---- a/include/h2o/url.h -+++ b/include/h2o/url.h -@@ -22,7 +22,9 @@ - #ifndef h2o__url_h - #define h2o__url_h - -+#ifndef H2O_NO_UNIX_SOCKETS - #include -+#endif - #include "h2o/memory.h" - - typedef struct st_h2o_url_scheme_t { -@@ -92,11 +94,13 @@ static h2o_iovec_t h2o_url_stringify(h2o_mem_pool_t *pool, const h2o_url_t *url) - * copies a URL object (null-terminates all the string elements) - */ - void h2o_url_copy(h2o_mem_pool_t *pool, h2o_url_t *dest, const h2o_url_t *src); -+#ifndef H2O_NO_UNIX_SOCKETS - /** - * extracts sockaddr_un from host and returns NULL (or returns an error string if failed) - */ - const char *h2o_url_host_to_sun(h2o_iovec_t host, struct sockaddr_un *sa); - extern const char *h2o_url_host_to_sun_err_is_not_unix_socket; -+#endif - - /* inline definitions */ - -diff --git a/lib/common/file.c b/lib/common/file.c -index 3cf5ac5d1..d3e0048b6 100644 ---- a/lib/common/file.c -+++ b/lib/common/file.c -@@ -25,7 +25,6 @@ - #include - #include - #include --#include - #include - #include "h2o/file.h" - -@@ -33,7 +32,7 @@ h2o_iovec_t h2o_file_read(const char *fn) - { - int fd; - struct stat st; -- h2o_iovec_t ret = {NULL}; -+ h2o_iovec_t ret = H2O_IOVEC_NULL; - - /* open */ - if ((fd = open(fn, O_RDONLY | O_CLOEXEC)) == -1) -@@ -64,5 +63,5 @@ Error: - if (fd != -1) - close(fd); - free(ret.base); -- return (h2o_iovec_t){NULL}; -+ return (h2o_iovec_t)H2O_IOVEC_NULL; - } -diff --git a/lib/common/filecache.c b/lib/common/filecache.c -index 747a1ffa6..e37e1f498 100644 ---- a/lib/common/filecache.c -+++ b/lib/common/filecache.c -@@ -136,6 +136,24 @@ Exit: - return ref; - } - -+ssize_t h2o_filecache_read_file(h2o_filecache_ref_t *ref, void *buf, size_t count, off_t offset) -+{ -+ #ifdef _WIN32 -+ // h2o reads from h2o_filecache_ref_t.fd only with pread (comment it out to verify) -+ // this allows me to ignore the existence of the file pointer position maintained -+ // by Windows I/O manager and use NtReadFile() without opening extra file handles -+ /* -+ #include -+ IO_STATUS_BLOCK sb; -+ LARGE_INTEGER li; -+ NTSTATUS s = NtReadFile(_get_osfhandle(fd), NULL, NULL, NULL, &sb, buf, count, &li, NULL); -+ */ -+ return -1; -+ #else -+ return pread(ref->fd, buf, count, offset); -+ #endif -+} -+ - void h2o_filecache_close_file(h2o_filecache_ref_t *ref) - { - if (--ref->_refcnt != 0) -diff --git a/lib/common/http1client.c b/lib/common/http1client.c -index 8547ea817..a9de3d67d 100644 ---- a/lib/common/http1client.c -+++ b/lib/common/http1client.c -@@ -19,12 +19,18 @@ - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -+#ifdef _WIN32 -+#include -+#else - #include - #include - #include - #include -+#endif - #include -+#ifndef H2O_NO_UNIX_SOCKETS - #include -+#endif - #include "picohttpparser.h" - #include "h2o.h" - -@@ -535,6 +541,7 @@ void h2o_http1client_connect(h2o_http1client_t **_client, void *data, h2o_http1c - return; - } - } -+ #ifndef _WIN32 - { /* directly call connect(2) if `host` refers to an UNIX-domain socket */ - struct sockaddr_un sa; - const char *to_sa_err; -@@ -547,6 +554,7 @@ void h2o_http1client_connect(h2o_http1client_t **_client, void *data, h2o_http1c - return; - } - } -+ #endif - /* resolve destination and then connect */ - client->_getaddr_req = - h2o_hostinfo_getaddr(ctx->getaddr_receiver, host, h2o_iovec_init(serv, sprintf(serv, "%u", (unsigned)port)), AF_UNSPEC, -diff --git a/lib/common/memory.c b/lib/common/memory.c -index ba9f2dba2..3a505d8ea 100644 ---- a/lib/common/memory.c -+++ b/lib/common/memory.c -@@ -27,7 +27,9 @@ - #include - #include - #include -+#ifndef _WIN32 - #include -+#endif - #include - #include "h2o/memory.h" - -@@ -190,20 +192,24 @@ void h2o_mem_link_shared(h2o_mem_pool_t *pool, void *p) - link_shared(pool, H2O_STRUCT_FROM_MEMBER(struct st_h2o_mem_pool_shared_entry_t, bytes, p)); - } - -+#ifndef _WIN32 - static size_t topagesize(size_t capacity) - { - size_t pagesize = getpagesize(); - return (offsetof(h2o_buffer_t, _buf) + capacity + pagesize - 1) / pagesize * pagesize; - } -+#endif - - void h2o_buffer__do_free(h2o_buffer_t *buffer) - { - /* caller should assert that the buffer is not part of the prototype */ - if (buffer->capacity == buffer->_prototype->_initial_buf.capacity) { - h2o_mem_free_recycle(&buffer->_prototype->allocator, buffer); -+ #ifndef _WIN32 - } else if (buffer->_fd != -1) { - close(buffer->_fd); - munmap((void *)buffer, topagesize(buffer->capacity)); -+ #endif - } else { - free(buffer); - } -@@ -240,6 +246,7 @@ h2o_iovec_t h2o_buffer_reserve(h2o_buffer_t **_inbuf, size_t min_guarantee) - do { - new_capacity *= 2; - } while (new_capacity - inbuf->size < min_guarantee); -+ #ifndef _WIN32 - if (inbuf->_prototype->mmap_settings != NULL && inbuf->_prototype->mmap_settings->threshold <= new_capacity) { - size_t new_allocsize = topagesize(new_capacity); - int fd; -@@ -287,7 +294,9 @@ h2o_iovec_t h2o_buffer_reserve(h2o_buffer_t **_inbuf, size_t min_guarantee) - inbuf->capacity = new_capacity; - inbuf->bytes = newp->_buf + offset; - } -- } else { -+ } else -+ #endif -+ { - h2o_buffer_t *newp = h2o_mem_alloc(offsetof(h2o_buffer_t, _buf) + new_capacity); - newp->size = inbuf->size; - newp->bytes = newp->_buf; -@@ -306,10 +315,12 @@ h2o_iovec_t h2o_buffer_reserve(h2o_buffer_t **_inbuf, size_t min_guarantee) - - return ret; - -+#ifndef _WIN32 - MapError: - ret.base = NULL; - ret.len = 0; - return ret; -+#endif - } - - void h2o_buffer_consume(h2o_buffer_t **_inbuf, size_t delta) -diff --git a/lib/common/multithread.c b/lib/common/multithread.c -index b4e8ba836..9a3dbe7d4 100644 ---- a/lib/common/multithread.c -+++ b/lib/common/multithread.c -@@ -22,7 +22,6 @@ - */ - #include - #include --#include "cloexec.h" - #include "h2o/multithread.h" - - struct st_h2o_multithread_queue_t { -@@ -73,6 +72,7 @@ pthread_mutex_t h2o_conn_id_mutex = PTHREAD_MUTEX_INITIALIZER; - #if H2O_USE_LIBUV - #else - -+#include "cloexec.h" - #include - #include - #include -diff --git a/lib/common/serverutil.c b/lib/common/serverutil.c -index 8226f6efc..a599e7412 100644 ---- a/lib/common/serverutil.c -+++ b/lib/common/serverutil.c -@@ -21,26 +21,30 @@ - */ - #include - #include -+#ifndef _WIN32 - #include --#include - #include --#include - #include -+#include -+#if !defined(_SC_NPROCESSORS_ONLN) -+#include -+#endif -+#endif -+#include -+#include - #include - #include - #include - #include --#include - #include --#if !defined(_SC_NPROCESSORS_ONLN) --#include --#endif --#include "cloexec.h" - #include "h2o/memory.h" - #include "h2o/serverutil.h" - #include "h2o/socket.h" - #include "h2o/string_.h" -- -+#if !H2O_USE_LIBUV -+#include "cloexec.h" -+#endif -+#if 0 - void h2o_set_signal_handler(int signo, void (*cb)(int signo)) - { - struct sigaction action; -@@ -137,6 +141,7 @@ static char **build_spawn_env(void) - return newenv; - } - -+#ifndef _WIN32 - pid_t h2o_spawnp(const char *cmd, char *const *argv, const int *mapped_fds, int cloexec_mutex_is_locked) - { - #if defined(__linux__) -@@ -235,6 +240,7 @@ Error: - - #endif - } -+#endif - - int h2o_read_command(const char *cmd, char **argv, h2o_buffer_t **resp, int *child_status) - { -@@ -315,3 +321,4 @@ size_t h2o_numproc(void) - return 1; - #endif - } -+#endif -\ No newline at end of file -diff --git a/lib/common/socket.c b/lib/common/socket.c -index 5b1c37e04..86ebbd8b4 100644 ---- a/lib/common/socket.c -+++ b/lib/common/socket.c -@@ -23,11 +23,18 @@ - #include - #include - #include -+#ifdef _WIN32 -+#include -+#include -+#else - #include - #include - #include -+#endif - #include -+#ifndef H2O_NO_UNIX_SOCKETS - #include -+#endif - #include - #include - #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -@@ -861,12 +868,7 @@ int h2o_socket_compare_address(struct sockaddr *x, struct sockaddr *y) - - CMP(x->sa_family, y->sa_family); - -- if (x->sa_family == AF_UNIX) { -- struct sockaddr_un *xun = (void *)x, *yun = (void *)y; -- int r = strcmp(xun->sun_path, yun->sun_path); -- if (r != 0) -- return r; -- } else if (x->sa_family == AF_INET) { -+ if (x->sa_family == AF_INET) { - struct sockaddr_in *xin = (void *)x, *yin = (void *)y; - CMP(ntohl(xin->sin_addr.s_addr), ntohl(yin->sin_addr.s_addr)); - CMP(ntohs(xin->sin_port), ntohs(yin->sin_port)); -@@ -878,6 +880,13 @@ int h2o_socket_compare_address(struct sockaddr *x, struct sockaddr *y) - CMP(ntohs(xin6->sin6_port), ntohs(yin6->sin6_port)); - CMP(xin6->sin6_flowinfo, yin6->sin6_flowinfo); - CMP(xin6->sin6_scope_id, yin6->sin6_scope_id); -+ #ifndef H2O_NO_UNIX_SOCKETS -+ } else if (x->sa_family == AF_UNIX) { -+ struct sockaddr_un *xun = (void *)x, *yun = (void *)y; -+ int r = strcmp(xun->sun_path, yun->sun_path); -+ if (r != 0) -+ return r; -+ #endif - } else { - assert(!"unknown sa_family"); - } -@@ -1015,7 +1024,7 @@ static void on_handshake_complete(h2o_socket_t *sock, const char *err) - - static void proceed_handshake(h2o_socket_t *sock, const char *err) - { -- h2o_iovec_t first_input = {NULL}; -+ h2o_iovec_t first_input = H2O_IOVEC_NULL; - int ret = 0; - - sock->_cb.write = NULL; -diff --git a/lib/common/socketpool.c b/lib/common/socketpool.c -index da69933f7..730d3d22f 100644 ---- a/lib/common/socketpool.c -+++ b/lib/common/socketpool.c -@@ -21,12 +21,18 @@ - */ - #include - #include -+#ifdef _WIN32 -+#include -+#else - #include -+#include - #include - #include -+#endif - #include -+#ifndef H2O_NO_UNIX_SOCKETS - #include --#include -+#endif - #include "h2o/hostinfo.h" - #include "h2o/linklist.h" - #include "h2o/socketpool.h" -@@ -110,11 +116,15 @@ void h2o_socketpool_init_by_address(h2o_socketpool_t *pool, struct sockaddr *sa, - assert(salen <= sizeof(pool->peer.sockaddr.bytes)); - - if ((host_len = h2o_socket_getnumerichost(sa, salen, host)) == SIZE_MAX) { -+ #ifndef H2O_NO_UNIX_SOCKETS - if (sa->sa_family != AF_UNIX) - h2o_fatal("failed to convert a non-unix socket address to a numerical representation"); - /* use the sockaddr_un::sun_path as the SNI indicator (is that the right thing to do?) */ - strcpy(host, ((struct sockaddr_un *)sa)->sun_path); - host_len = strlen(host); -+ #else -+ h2o_fatal("failed to convert a socket address to a numerical representation"); -+ #endif - } - - common_init(pool, H2O_SOCKETPOOL_TYPE_SOCKADDR, h2o_iovec_init(host, host_len), is_ssl, capacity); -diff --git a/lib/common/string.c b/lib/common/string.c -index 3c068f3ad..2c33624b7 100644 ---- a/lib/common/string.c -+++ b/lib/common/string.c -@@ -441,16 +441,21 @@ const char *h2o_next_token(h2o_iovec_t *iter, int separator, size_t *element_len - *iter = h2o_iovec_init(cur, end - cur); - *element_len = token_end - token_start; - if (value != NULL) -- *value = (h2o_iovec_t){NULL}; -+ *value = (h2o_iovec_t)H2O_IOVEC_NULL; - return token_start; - - FindValue: - *iter = h2o_iovec_init(cur, end - cur); - *element_len = token_end - token_start; -- if ((value->base = (char *)h2o_next_token(iter, separator, &value->len, NULL)) == NULL) { -- *value = (h2o_iovec_t){"", 0}; -- } else if (h2o_memis(value->base, value->len, H2O_STRLIT(","))) { -- *value = (h2o_iovec_t){"", 0}; -+ -+ size_t tmp; -+ if ((value->base = (char *)h2o_next_token(iter, separator, &tmp, NULL)) == NULL) { -+ *value = (h2o_iovec_t)H2O_IOVEC_EMPTY; -+ return token_start; -+ } -+ value->len = tmp; -+ if (h2o_memis(value->base, value->len, H2O_STRLIT(","))) { -+ *value = (h2o_iovec_t)H2O_IOVEC_EMPTY; - iter->base -= 1; - iter->len += 1; - } -@@ -499,7 +504,7 @@ h2o_iovec_t h2o_htmlescape(h2o_mem_pool_t *pool, const char *src, size_t len) - /* escape and return the result if necessary */ - if (add_size != 0) { - /* allocate buffer and fill in the chars that are known not to require escaping */ -- h2o_iovec_t escaped = {h2o_mem_alloc_pool(pool, len + add_size + 1), 0}; -+ h2o_iovec_t escaped = h2o_iovec_init(h2o_mem_alloc_pool(pool, len + add_size + 1), 0); - /* fill-in the rest */ - for (s = src; s != end; ++s) { - switch (*s) { -@@ -529,7 +534,7 @@ h2o_iovec_t h2o_htmlescape(h2o_mem_pool_t *pool, const char *src, size_t len) - - h2o_iovec_t h2o_concat_list(h2o_mem_pool_t *pool, h2o_iovec_t *list, size_t count) - { -- h2o_iovec_t ret = {NULL, 0}; -+ h2o_iovec_t ret = H2O_IOVEC_NULL; - size_t i; - - /* calc the length */ -diff --git a/lib/common/url.c b/lib/common/url.c -index d65d18fb5..9b9ec85bb 100644 ---- a/lib/common/url.c -+++ b/lib/common/url.c -@@ -19,15 +19,21 @@ - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -+#ifdef _WIN32 -+#include -+#else - #include -+#endif - #include -+#ifndef H2O_NO_UNIX_SOCKETS - #include -+#endif - #include "h2o/memory.h" - #include "h2o/string_.h" - #include "h2o/url.h" - --const h2o_url_scheme_t H2O_URL_SCHEME_HTTP = {{H2O_STRLIT("http")}, 80}; --const h2o_url_scheme_t H2O_URL_SCHEME_HTTPS = {{H2O_STRLIT("https")}, 443}; -+const h2o_url_scheme_t H2O_URL_SCHEME_HTTP = {H2O_IOVEC_STRLIT("http"), 80}; -+const h2o_url_scheme_t H2O_URL_SCHEME_HTTPS = {H2O_IOVEC_STRLIT("https"), 443}; - - static int decode_hex(int ch) - { -@@ -277,8 +283,8 @@ int h2o_url_parse_relative(const char *url, size_t url_len, h2o_url_t *parsed) - return parse_authority_and_path(p + 2, url_end, parsed); - - /* reset authority, host, port, and set path */ -- parsed->authority = (h2o_iovec_t){NULL}; -- parsed->host = (h2o_iovec_t){NULL}; -+ parsed->authority = (h2o_iovec_t)H2O_IOVEC_NULL; -+ parsed->host = (h2o_iovec_t)H2O_IOVEC_NULL; - parsed->_port = 65535; - parsed->path = h2o_iovec_init(p, url_end - p); - -@@ -324,7 +330,7 @@ h2o_iovec_t h2o_url_resolve(h2o_mem_pool_t *pool, const h2o_url_t *base, const h - h2o_url_resolve_path(&base_path, &relative_path); - } else { - assert(relative->path.len == 0); -- relative_path = (h2o_iovec_t){NULL}; -+ relative_path = (h2o_iovec_t)H2O_IOVEC_NULL; - } - - Build: -@@ -388,6 +394,7 @@ void h2o_url_copy(h2o_mem_pool_t *pool, h2o_url_t *dest, const h2o_url_t *src) - dest->_port = src->_port; - } - -+#ifndef H2O_NO_UNIX_SOCKETS - const char *h2o_url_host_to_sun(h2o_iovec_t host, struct sockaddr_un *sa) - { - #define PREFIX "unix:" -@@ -407,3 +414,4 @@ const char *h2o_url_host_to_sun(h2o_iovec_t host, struct sockaddr_un *sa) - } - - const char *h2o_url_host_to_sun_err_is_not_unix_socket = "supplied name does not look like an unix-domain socket"; -+#endif -diff --git a/lib/core/config.c b/lib/core/config.c -index ce1d32018..267708723 100644 ---- a/lib/core/config.c -+++ b/lib/core/config.c -@@ -246,7 +246,7 @@ h2o_hostconf_t *h2o_config_register_host(h2o_globalconf_t *config, h2o_iovec_t h - /* create hostconf */ - hostconf = create_hostconf(config); - hostconf->authority.host = host_lc; -- host_lc = (h2o_iovec_t){NULL}; -+ host_lc = (h2o_iovec_t)H2O_IOVEC_NULL; - hostconf->authority.port = port; - if (hostconf->authority.port == 65535) { - hostconf->authority.hostport = hostconf->authority.host; -diff --git a/lib/core/context.c b/lib/core/context.c -index 8d1101381..f472adbe6 100644 ---- a/lib/core/context.c -+++ b/lib/core/context.c -@@ -23,7 +23,6 @@ - #include - #include - #include "h2o.h" --#include "h2o/memcached.h" - - void h2o_context_init_pathconf_context(h2o_context_t *ctx, h2o_pathconf_t *pathconf) - { -@@ -194,7 +193,9 @@ void h2o_context_update_timestamp_cache(h2o_context_t *ctx) - if (ctx->_timestamp_cache.value != NULL) - h2o_mem_release_shared(ctx->_timestamp_cache.value); - ctx->_timestamp_cache.value = h2o_mem_alloc_shared(NULL, sizeof(h2o_timestamp_string_t), NULL); -- gmtime_r(&ctx->_timestamp_cache.tv_at.tv_sec, &gmt); -+ /* work around pointer type collision in MingW */ -+ time_t tmp = ctx->_timestamp_cache.tv_at.tv_sec; -+ gmtime_r(&tmp, &gmt); - h2o_time2str_rfc1123(ctx->_timestamp_cache.value->rfc1123, &gmt); - h2o_time2str_log(ctx->_timestamp_cache.value->log, ctx->_timestamp_cache.tv_at.tv_sec); - } -diff --git a/lib/core/logconf.c b/lib/core/logconf.c -index 4d79736cc..74c198ce7 100644 ---- a/lib/core/logconf.c -+++ b/lib/core/logconf.c -@@ -597,8 +597,11 @@ char *h2o_log_request(h2o_logconf_t *logconf, h2o_req_t *req, size_t *len, char - goto EmitNull; - { - size_t bufsz, len; -- if (localt.tm_year == 0) -- localtime_r(&req->processed_at.at.tv_sec, &localt); -+ if (localt.tm_year == 0) { -+ /* work around pointer type collision in MingW */ -+ time_t tmp = req->processed_at.at.tv_sec; -+ localtime_r(&tmp, &localt); -+ } - for (bufsz = 128;; bufsz *= 2) { - RESERVE(bufsz); - if ((len = strftime(pos, bufsz, element->data.name.base, &localt)) != 0) -diff --git a/lib/core/proxy.c b/lib/core/proxy.c -index edb4baf9d..448dc103d 100644 ---- a/lib/core/proxy.c -+++ b/lib/core/proxy.c -@@ -19,10 +19,14 @@ - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ --#include - #include - #include -+#ifdef _WIN32 -+#include -+#else -+#include - #include -+#endif - #include "picohttpparser.h" - #include "h2o.h" - #include "h2o/http1.h" -@@ -79,7 +83,7 @@ static h2o_iovec_t rewrite_location(h2o_mem_pool_t *pool, const char *location, - h2o_iovec_init(loc_parsed.path.base + match->path.len, loc_parsed.path.len - match->path.len)); - - NoRewrite: -- return (h2o_iovec_t){NULL}; -+ return (h2o_iovec_t)H2O_IOVEC_NULL; - } - - static h2o_iovec_t build_request_merge_headers(h2o_mem_pool_t *pool, h2o_iovec_t merged, h2o_iovec_t added, int seperator) -@@ -136,7 +140,7 @@ static h2o_iovec_t build_request(h2o_req_t *req, int keepalive, int is_websocket - char remote_addr[NI_MAXHOST]; - struct sockaddr_storage ss; - socklen_t sslen; -- h2o_iovec_t cookie_buf = {NULL}, xff_buf = {NULL}, via_buf = {NULL}; -+ h2o_iovec_t cookie_buf = H2O_IOVEC_NULL, xff_buf = H2O_IOVEC_NULL, via_buf = H2O_IOVEC_NULL; - int preserve_x_forwarded_proto = req->conn->ctx->globalconf->proxy.preserve_x_forwarded_proto; - int emit_x_forwarded_headers = req->conn->ctx->globalconf->proxy.emit_x_forwarded_headers; - int emit_via_header = req->conn->ctx->globalconf->proxy.emit_via_header; -@@ -202,7 +206,7 @@ static h2o_iovec_t build_request(h2o_req_t *req, int keepalive, int is_websocket - assert(offset <= buf.len); - if (req->entity.base != NULL || req_requires_content_length(req)) { - RESERVE(sizeof("content-length: " H2O_UINT64_LONGEST_STR) - 1); -- offset += sprintf(buf.base + offset, "content-length: %zu\r\n", req->entity.len); -+ offset += sprintf(buf.base + offset, "content-length: %zu\r\n", (size_t)req->entity.len); - } - - /* rewrite headers if necessary */ -diff --git a/lib/core/request.c b/lib/core/request.c -index 96aabb22d..65810ed91 100644 ---- a/lib/core/request.c -+++ b/lib/core/request.c -@@ -22,7 +22,9 @@ - #include - #include - #include -+#ifndef _WIN32 - #include -+#endif - #include "h2o.h" - - #ifndef IOV_MAX -@@ -595,10 +597,16 @@ void h2o_req_log_error(h2o_req_t *req, const char *module, const char *fmt, ...) - p += 3; - } - *p++ = ':'; -+ #ifdef _WIN32 -+ write(2, prefix, p - prefix); -+ write(2, errbuf, errlen); -+ write(2, "\n", 1); -+ #else - /* use writev(2) to emit error atomically */ - struct iovec vecs[] = {{prefix, p - prefix}, {errbuf, errlen}, {"\n", 1}}; - H2O_BUILD_ASSERT(sizeof(vecs) / sizeof(vecs[0]) < IOV_MAX); - writev(2, vecs, sizeof(vecs) / sizeof(vecs[0])); -+ #endif - } - } - -@@ -611,8 +619,8 @@ void h2o_send_redirect(h2o_req_t *req, int status, const char *reason, const cha - } - - static h2o_generator_t generator = {NULL, NULL}; -- static const h2o_iovec_t body_prefix = {H2O_STRLIT("Moved

    The document has moved here")}; -+ static const h2o_iovec_t body_prefix = H2O_IOVEC_STRLIT("Moved

    The document has moved here"); - - /* build and send response */ - h2o_iovec_t bufs[3]; -diff --git a/lib/core/token_table.h b/lib/core/token_table.h -index ae26aa6c4..fa74f1e08 100644 ---- a/lib/core/token_table.h -+++ b/lib/core/token_table.h -@@ -21,68 +21,68 @@ - */ - - /* DO NOT EDIT! generated by tokens.pl */ --h2o_token_t h2o__tokens[] = {{{H2O_STRLIT(":authority")}, 1, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT(":method")}, 2, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT(":path")}, 4, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT(":scheme")}, 6, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT(":status")}, 8, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("accept")}, 19, 0, 0, 0, 0, 1, 0}, -- {{H2O_STRLIT("accept-charset")}, 15, 0, 0, 0, 0, 1, 0}, -- {{H2O_STRLIT("accept-encoding")}, 16, 0, 0, 0, 0, 1, 0}, -- {{H2O_STRLIT("accept-language")}, 17, 0, 0, 0, 0, 1, 0}, -- {{H2O_STRLIT("accept-ranges")}, 18, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("access-control-allow-origin")}, 20, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("age")}, 21, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("allow")}, 22, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("authorization")}, 23, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("cache-control")}, 24, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("cache-digest")}, 0, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("connection")}, 0, 1, 1, 0, 1, 0, 0}, -- {{H2O_STRLIT("content-disposition")}, 25, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("content-encoding")}, 26, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("content-language")}, 27, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("content-length")}, 28, 0, 0, 1, 0, 0, 0}, -- {{H2O_STRLIT("content-location")}, 29, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("content-range")}, 30, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("content-type")}, 31, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("cookie")}, 32, 0, 0, 0, 0, 0, 1}, -- {{H2O_STRLIT("date")}, 33, 0, 1, 0, 0, 0, 0}, -- {{H2O_STRLIT("etag")}, 34, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("expect")}, 35, 0, 0, 1, 0, 0, 0}, -- {{H2O_STRLIT("expires")}, 36, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("from")}, 37, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("host")}, 38, 0, 0, 1, 1, 0, 0}, -- {{H2O_STRLIT("http2-settings")}, 0, 1, 0, 0, 1, 0, 0}, -- {{H2O_STRLIT("if-match")}, 39, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("if-modified-since")}, 40, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("if-none-match")}, 41, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("if-range")}, 42, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("if-unmodified-since")}, 43, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("keep-alive")}, 0, 1, 1, 0, 0, 0, 0}, -- {{H2O_STRLIT("last-modified")}, 44, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("link")}, 45, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("location")}, 46, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("max-forwards")}, 47, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("proxy-authenticate")}, 48, 1, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("proxy-authorization")}, 49, 1, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("range")}, 50, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("referer")}, 51, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("refresh")}, 52, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("retry-after")}, 53, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("server")}, 54, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("set-cookie")}, 55, 0, 0, 0, 0, 0, 1}, -- {{H2O_STRLIT("strict-transport-security")}, 56, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("te")}, 0, 1, 0, 0, 1, 0, 0}, -- {{H2O_STRLIT("transfer-encoding")}, 57, 1, 1, 1, 1, 0, 0}, -- {{H2O_STRLIT("upgrade")}, 0, 1, 1, 1, 1, 0, 0}, -- {{H2O_STRLIT("user-agent")}, 58, 0, 0, 0, 0, 1, 0}, -- {{H2O_STRLIT("vary")}, 59, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("via")}, 60, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("www-authenticate")}, 61, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("x-compress-hint")}, 0, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("x-forwarded-for")}, 0, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("x-reproxy-url")}, 0, 0, 0, 0, 0, 0, 0}, -- {{H2O_STRLIT("x-traffic")}, 0, 0, 0, 0, 0, 0, 0}}; -+h2o_token_t h2o__tokens[] = {{H2O_IOVEC_STRLIT(":authority"), 1, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT(":method"), 2, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT(":path"), 4, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT(":scheme"), 6, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT(":status"), 8, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("accept"), 19, 0, 0, 0, 0, 1, 0}, -+ {H2O_IOVEC_STRLIT("accept-charset"), 15, 0, 0, 0, 0, 1, 0}, -+ {H2O_IOVEC_STRLIT("accept-encoding"), 16, 0, 0, 0, 0, 1, 0}, -+ {H2O_IOVEC_STRLIT("accept-language"), 17, 0, 0, 0, 0, 1, 0}, -+ {H2O_IOVEC_STRLIT("accept-ranges"), 18, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("access-control-allow-origin"), 20, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("age"), 21, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("allow"), 22, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("authorization"), 23, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("cache-control"), 24, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("cache-digest"), 0, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("connection"), 0, 1, 1, 0, 1, 0, 0}, -+ {H2O_IOVEC_STRLIT("content-disposition"), 25, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("content-encoding"), 26, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("content-language"), 27, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("content-length"), 28, 0, 0, 1, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("content-location"), 29, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("content-range"), 30, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("content-type"), 31, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("cookie"), 32, 0, 0, 0, 0, 0, 1}, -+ {H2O_IOVEC_STRLIT("date"), 33, 0, 1, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("etag"), 34, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("expect"), 35, 0, 0, 1, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("expires"), 36, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("from"), 37, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("host"), 38, 0, 0, 1, 1, 0, 0}, -+ {H2O_IOVEC_STRLIT("http2-settings"), 0, 1, 0, 0, 1, 0, 0}, -+ {H2O_IOVEC_STRLIT("if-match"), 39, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("if-modified-since"), 40, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("if-none-match"), 41, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("if-range"), 42, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("if-unmodified-since"), 43, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("keep-alive"), 0, 1, 1, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("last-modified"), 44, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("link"), 45, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("location"), 46, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("max-forwards"), 47, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("proxy-authenticate"), 48, 1, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("proxy-authorization"), 49, 1, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("range"), 50, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("referer"), 51, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("refresh"), 52, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("retry-after"), 53, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("server"), 54, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("set-cookie"), 55, 0, 0, 0, 0, 0, 1}, -+ {H2O_IOVEC_STRLIT("strict-transport-security"), 56, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("te"), 0, 1, 0, 0, 1, 0, 0}, -+ {H2O_IOVEC_STRLIT("transfer-encoding"), 57, 1, 1, 1, 1, 0, 0}, -+ {H2O_IOVEC_STRLIT("upgrade"), 0, 1, 1, 1, 1, 0, 0}, -+ {H2O_IOVEC_STRLIT("user-agent"), 58, 0, 0, 0, 0, 1, 0}, -+ {H2O_IOVEC_STRLIT("vary"), 59, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("via"), 60, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("www-authenticate"), 61, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("x-compress-hint"), 0, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("x-forwarded-for"), 0, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("x-reproxy-url"), 0, 0, 0, 0, 0, 0, 0}, -+ {H2O_IOVEC_STRLIT("x-traffic"), 0, 0, 0, 0, 0, 0, 0}}; - size_t h2o__num_tokens = 62; - - const h2o_token_t *h2o_lookup_token(const char *name, size_t len) -diff --git a/lib/core/util.c b/lib/core/util.c -index 50d2b2493..13c363ee1 100644 ---- a/lib/core/util.c -+++ b/lib/core/util.c -@@ -63,6 +63,7 @@ static void free_accept_data(struct st_h2o_accept_data_t *data) - free(data); - } - -+#ifndef H2O_NO_MEMCACHED - static struct { - h2o_memcached_context_t *memc; - unsigned expiration; -@@ -97,15 +98,18 @@ void h2o_accept_setup_async_ssl_resumption(h2o_memcached_context_t *memc, unsign - async_resumption_context.expiration = expiration; - h2o_socket_ssl_async_resumption_init(async_resumption_get, async_resumption_new); - } -+#endif - - void on_accept_timeout(h2o_timeout_entry_t *entry) - { - /* TODO log */ - struct st_h2o_accept_data_t *data = H2O_STRUCT_FROM_MEMBER(struct st_h2o_accept_data_t, timeout, entry); -+ #ifndef H2O_NO_MEMCACHED - if (data->async_resumption_get_req != NULL) { - h2o_memcached_cancel_get(async_resumption_context.memc, data->async_resumption_get_req); - data->async_resumption_get_req = NULL; - } -+ #endif - h2o_socket_t *sock = data->sock; - free_accept_data(data); - h2o_socket_close(sock); -@@ -158,7 +162,11 @@ static ssize_t parse_proxy_line(char *src, size_t len, struct sockaddr *sa, sock - - char *p = src, *end = p + len; - void *addr; -+ #if _WIN32 -+ u_short *port; -+ #else - in_port_t *port; -+ #endif - - /* "PROXY "*/ - EXPECT_CHAR('P'); -@@ -369,7 +377,7 @@ static void push_one_path(h2o_mem_pool_t *pool, h2o_iovec_vector_t *paths_to_pus - } - - /* check scheme and authority if given URL contains either of the two, or if base is specified */ -- h2o_url_t base = {input_scheme, input_authority, {NULL}, base_path, 65535}; -+ h2o_url_t base = {input_scheme, input_authority, H2O_IOVEC_NULL, base_path, 65535}; - if (base_scheme != NULL) { - base.scheme = base_scheme; - base.authority = *base_authority; -@@ -528,7 +536,7 @@ h2o_iovec_t h2o_build_destination(h2o_req_t *req, const char *prefix, size_t pre - if (req->path.base[0] != '/' && next_unnormalized == 1) { - next_unnormalized = 0; - } -- parts[num_parts++] = (h2o_iovec_t){req->path.base + next_unnormalized, req->path.len - next_unnormalized}; -+ parts[num_parts++] = h2o_iovec_init(req->path.base + next_unnormalized, req->path.len - next_unnormalized); - } - } - -@@ -536,10 +544,7 @@ h2o_iovec_t h2o_build_destination(h2o_req_t *req, const char *prefix, size_t pre - } - - /* h2-14 and h2-16 are kept for backwards compatibility, as they are often used */ --#define ALPN_ENTRY(s) \ -- { \ -- H2O_STRLIT(s) \ -- } -+#define ALPN_ENTRY(s) H2O_IOVEC_STRLIT(s) - #define ALPN_PROTOCOLS_CORE ALPN_ENTRY("h2"), ALPN_ENTRY("h2-16"), ALPN_ENTRY("h2-14") - #define NPN_PROTOCOLS_CORE \ - "\x02" \ -@@ -549,10 +554,10 @@ h2o_iovec_t h2o_build_destination(h2o_req_t *req, const char *prefix, size_t pre - "\x05" \ - "h2-14" - --static const h2o_iovec_t http2_alpn_protocols[] = {ALPN_PROTOCOLS_CORE, {NULL}}; -+static const h2o_iovec_t http2_alpn_protocols[] = {ALPN_PROTOCOLS_CORE, H2O_IOVEC_NULL}; - const h2o_iovec_t *h2o_http2_alpn_protocols = http2_alpn_protocols; - --static const h2o_iovec_t alpn_protocols[] = {ALPN_PROTOCOLS_CORE, {H2O_STRLIT("http/1.1")}, {NULL}}; -+static const h2o_iovec_t alpn_protocols[] = {ALPN_PROTOCOLS_CORE, H2O_IOVEC_STRLIT("http/1.1"), H2O_IOVEC_NULL}; - const h2o_iovec_t *h2o_alpn_protocols = alpn_protocols; - - const char *h2o_http2_npn_protocols = NPN_PROTOCOLS_CORE; -diff --git a/lib/handler/access_log.c b/lib/handler/access_log.c -index 4a7704174..d56c21add 100644 ---- a/lib/handler/access_log.c -+++ b/lib/handler/access_log.c -@@ -22,12 +22,16 @@ - #include - #include - #include -+#include -+#include -+#ifdef _WIN32 -+#include -+#else - #include - #include - #include --#include --#include - #include -+#endif - #include - #include "h2o.h" - #include "h2o/serverutil.h" -@@ -73,6 +77,7 @@ int h2o_access_log_open_log(const char *path) - { - int fd; - -+ #ifndef _WIN32 - if (path[0] == '|') { - int pipefds[2]; - pid_t pid; -@@ -96,7 +101,9 @@ int h2o_access_log_open_log(const char *path) - /* close the read side of the pipefds and return the write side */ - close(pipefds[0]); - fd = pipefds[1]; -- } else { -+ } else -+ #endif -+ { - if ((fd = open(path, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0644)) == -1) { - fprintf(stderr, "failed to open log file:%s:%s\n", path, strerror(errno)); - return -1; -diff --git a/lib/handler/configurator/headers_util.c b/lib/handler/configurator/headers_util.c -index c05b9b7c2..56e47842e 100644 ---- a/lib/handler/configurator/headers_util.c -+++ b/lib/handler/configurator/headers_util.c -@@ -87,7 +87,7 @@ static int on_config_header_unset(h2o_configurator_command_t *cmd, h2o_configura - h2o_configurator_errprintf(cmd, node, "invalid header name"); - return -1; - } -- if (add_cmd(cmd, node, H2O_HEADERS_CMD_UNSET, name, (h2o_iovec_t){NULL}, self->get_commands(self->child)) != 0) { -+ if (add_cmd(cmd, node, H2O_HEADERS_CMD_UNSET, name, (h2o_iovec_t)H2O_IOVEC_NULL, self->get_commands(self->child)) != 0) { - if (!h2o_iovec_is_token(name)) - free(name->base); - return -1; -diff --git a/lib/handler/file.c b/lib/handler/file.c -index 5d7c7a2a4..c0bc486ec 100644 ---- a/lib/handler/file.c -+++ b/lib/handler/file.c -@@ -128,7 +128,7 @@ static void do_proceed(h2o_generator_t *_self, h2o_req_t *req) - rlen = self->bytesleft; - if (rlen > MAX_BUF_SIZE) - rlen = MAX_BUF_SIZE; -- while ((rret = pread(self->file.ref->fd, self->buf, rlen, self->file.off)) == -1 && errno == EINTR) -+ while ((rret = h2o_filecache_read_file(self->file.ref, self->buf, rlen, self->file.off)) == -1 && errno == EINTR) - ; - if (rret == -1) { - h2o_send(req, NULL, 0, H2O_SEND_STATE_ERROR); -@@ -177,7 +177,7 @@ static void do_multirange_proceed(h2o_generator_t *_self, h2o_req_t *req) - rlen = self->bytesleft; - if (rlen + used_buf > MAX_BUF_SIZE) - rlen = MAX_BUF_SIZE - used_buf; -- while ((rret = pread(self->file.ref->fd, self->buf + used_buf, rlen, self->file.off)) == -1 && errno == EINTR) -+ while ((rret = h2o_filecache_read_file(self->file.ref, self->buf + used_buf, rlen, self->file.off)) == -1 && errno == EINTR) - ; - if (rret == -1) - goto Error; -@@ -213,7 +213,7 @@ static h2o_send_state_t do_pull(h2o_generator_t *_self, h2o_req_t *req, h2o_iove - - if (self->bytesleft < buf->len) - buf->len = self->bytesleft; -- while ((rret = pread(self->file.ref->fd, buf->base, buf->len, self->file.off)) == -1 && errno == EINTR) -+ while ((rret = h2o_filecache_read_file(self->file.ref, buf->base, buf->len, self->file.off)) == -1 && errno == EINTR) - ; - if (rret <= 0) { - buf->len = 0; -@@ -237,7 +237,7 @@ static struct st_h2o_sendfile_generator_t *create_generator(h2o_req_t *req, cons - { - struct st_h2o_sendfile_generator_t *self; - h2o_filecache_ref_t *fileref; -- h2o_iovec_t content_encoding = (h2o_iovec_t){NULL}; -+ h2o_iovec_t content_encoding = H2O_IOVEC_NULL; - unsigned gunzip = 0; - - *is_dir = 0; -diff --git a/lib/handler/proxy.c b/lib/handler/proxy.c -index 1d87225e1..7de3c4ec5 100644 ---- a/lib/handler/proxy.c -+++ b/lib/handler/proxy.c -@@ -19,7 +19,9 @@ - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -+#ifndef H2O_NO_UNIX_SOCKETS - #include -+#endif - #include "h2o.h" - #include "h2o/socketpool.h" - -@@ -136,29 +138,37 @@ static void on_handler_dispose(h2o_handler_t *_self) - - void h2o_proxy_register_reverse_proxy(h2o_pathconf_t *pathconf, h2o_url_t *upstream, h2o_proxy_config_vars_t *config) - { -- struct sockaddr_un sa; -+ #ifndef H2O_NO_UNIX_SOCKETS - const char *to_sa_err; -+ #endif - struct rp_handler_t *self = (void *)h2o_create_handler(pathconf, sizeof(*self)); - self->super.on_context_init = on_context_init; - self->super.on_context_dispose = on_context_dispose; - self->super.dispose = on_handler_dispose; - self->super.on_req = on_req; -- to_sa_err = h2o_url_host_to_sun(upstream->host, &sa); - if (config->keepalive_timeout != 0) { - self->sockpool = h2o_mem_alloc(sizeof(*self->sockpool)); - int is_ssl = upstream->scheme == &H2O_URL_SCHEME_HTTPS; -+ #ifndef H2O_NO_UNIX_SOCKETS -+ struct sockaddr_un sa; -+ to_sa_err = h2o_url_host_to_sun(upstream->host, &sa); - if (to_sa_err == h2o_url_host_to_sun_err_is_not_unix_socket) { -+ #endif - h2o_socketpool_init_by_hostport(self->sockpool, upstream->host, h2o_url_get_port(upstream), is_ssl, - SIZE_MAX /* FIXME */); -+ #ifndef H2O_NO_UNIX_SOCKETS - } else { - assert(to_sa_err == NULL); - h2o_socketpool_init_by_address(self->sockpool, (void *)&sa, sizeof(sa), is_ssl, SIZE_MAX /* FIXME */); - } -+ #endif - } - h2o_url_copy(NULL, &self->upstream, upstream); -+ #ifndef H2O_NO_UNIX_SOCKETS - if (to_sa_err) { - h2o_strtolower(self->upstream.host.base, self->upstream.host.len); - } -+ #endif - self->config = *config; - if (self->config.ssl_ctx != NULL) - SSL_CTX_up_ref(self->config.ssl_ctx); -diff --git a/lib/handler/redirect.c b/lib/handler/redirect.c -index c8b9c5086..9eb5d4552 100644 ---- a/lib/handler/redirect.c -+++ b/lib/handler/redirect.c -@@ -68,7 +68,7 @@ static void redirect_internally(h2o_redirect_handler_t *self, h2o_req_t *req, h2 - break; - default: - method = h2o_iovec_init(H2O_STRLIT("GET")); -- req->entity = (h2o_iovec_t){NULL}; -+ req->entity = (h2o_iovec_t)H2O_IOVEC_NULL; - break; - } - -diff --git a/lib/handler/reproxy.c b/lib/handler/reproxy.c -index 369386d27..2639045c6 100644 ---- a/lib/handler/reproxy.c -+++ b/lib/handler/reproxy.c -@@ -47,7 +47,7 @@ static void on_setup_ostream(h2o_filter_t *self, h2o_req_t *req, h2o_ostream_t * - break; - default: - method = h2o_iovec_init(H2O_STRLIT("GET")); -- req->entity = (h2o_iovec_t){NULL}; -+ req->entity = (h2o_iovec_t)H2O_IOVEC_NULL; - break; - } - -diff --git a/lib/handler/status.c b/lib/handler/status.c -index 93befed3b..95f9ce823 100644 ---- a/lib/handler/status.c -+++ b/lib/handler/status.c -@@ -95,7 +95,7 @@ static void send_response(struct st_h2o_status_collector_t *collector) - h2o_iovec_t resp[nr_resp]; - - memset(resp, 0, sizeof(resp[0]) * nr_resp); -- resp[cur_resp++] = (h2o_iovec_t){H2O_STRLIT("{\n")}; -+ resp[cur_resp++] = h2o_iovec_init(H2O_STRLIT("{\n")); - - int coma_removed = 0; - for (i = 0; i < req->conn->ctx->globalconf->statuses.size; i++) { -@@ -110,7 +110,7 @@ static void send_response(struct st_h2o_status_collector_t *collector) - coma_removed = 1; - } - } -- resp[cur_resp++] = (h2o_iovec_t){H2O_STRLIT("\n}\n")}; -+ resp[cur_resp++] = h2o_iovec_init(H2O_STRLIT("\n}\n")); - - req->res.status = 200; - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, NULL, H2O_STRLIT("text/plain; charset=utf-8")); -@@ -213,7 +213,7 @@ static int on_req(h2o_handler_t *_self, h2o_req_t *req) - } else if (h2o_memis(local_path.base, local_path.len, H2O_STRLIT("/json"))) { - int ret; - /* "/json" maps to the JSON API */ -- h2o_iovec_t status_list = {NULL, 0}; /* NULL means we'll show all statuses */ -+ h2o_iovec_t status_list = H2O_IOVEC_NULL; /* NULL means we'll show all statuses */ - if (req->query_at != SIZE_MAX && (req->path.len - req->query_at > 6)) { - if (h2o_memis(&req->path.base[req->query_at], 6, "?show=", 6)) { - status_list = h2o_iovec_init(&req->path.base[req->query_at + 6], req->path.len - req->query_at - 6); -diff --git a/lib/handler/status/durations.c b/lib/handler/status/durations.c -index f011107bf..0e45e3eed 100644 ---- a/lib/handler/status/durations.c -+++ b/lib/handler/status/durations.c -@@ -203,5 +203,5 @@ void h2o_duration_stats_register(h2o_globalconf_t *conf) - } - - h2o_status_handler_t durations_status_handler = { -- {H2O_STRLIT("durations")}, durations_status_init, durations_status_per_thread, durations_status_final, -+ H2O_IOVEC_STRLIT("durations"), durations_status_init, durations_status_per_thread, durations_status_final, - }; -diff --git a/lib/handler/status/events.c b/lib/handler/status/events.c -index e6ed0b7c6..64fb6546f 100644 ---- a/lib/handler/status/events.c -+++ b/lib/handler/status/events.c -@@ -108,5 +108,5 @@ static h2o_iovec_t events_status_final(void *priv, h2o_globalconf_t *gconf, h2o_ - } - - h2o_status_handler_t events_status_handler = { -- {H2O_STRLIT("events")}, events_status_init, events_status_per_thread, events_status_final, -+ H2O_IOVEC_STRLIT("events"), events_status_init, events_status_per_thread, events_status_final, - }; -diff --git a/lib/handler/status/requests.c b/lib/handler/status/requests.c -index 4854e4a1f..56c28c36c 100644 ---- a/lib/handler/status/requests.c -+++ b/lib/handler/status/requests.c -@@ -123,7 +123,7 @@ static void *requests_status_init(void) - /* log format compilation error is an internal logic flaw, therefore we need not send the details to the client */ - fprintf(stderr, "[lib/handler/status/requests.c] failed to compile log format: %s", errbuf); - -- rsc->req_data = (h2o_iovec_t){NULL}; -+ rsc->req_data = (h2o_iovec_t)H2O_IOVEC_NULL; - pthread_mutex_init(&rsc->mutex, NULL); - - return rsc; -@@ -131,7 +131,7 @@ static void *requests_status_init(void) - - static h2o_iovec_t requests_status_final(void *priv, h2o_globalconf_t *gconf, h2o_req_t *req) - { -- h2o_iovec_t ret = {NULL}; -+ h2o_iovec_t ret = H2O_IOVEC_NULL; - struct st_requests_status_ctx_t *rsc = priv; - - if (rsc->logconf != NULL) { -@@ -147,5 +147,5 @@ static h2o_iovec_t requests_status_final(void *priv, h2o_globalconf_t *gconf, h2 - } - - h2o_status_handler_t requests_status_handler = { -- {H2O_STRLIT("requests")}, requests_status_init, requests_status_per_thread, requests_status_final, -+ H2O_IOVEC_STRLIT("requests"), requests_status_init, requests_status_per_thread, requests_status_final, - }; -diff --git a/lib/http1.c b/lib/http1.c -index 98c4e55ab..b765b8aae 100644 ---- a/lib/http1.c -+++ b/lib/http1.c -@@ -323,7 +323,7 @@ static ssize_t fixup_request(struct st_h2o_http1_conn_t *conn, struct phr_header - h2o_iovec_t *expect) - { - ssize_t entity_header_index; -- h2o_iovec_t connection = {NULL, 0}, host = {NULL, 0}, upgrade = {NULL, 0}; -+ h2o_iovec_t connection = H2O_IOVEC_NULL, host = H2O_IOVEC_NULL, upgrade = H2O_IOVEC_NULL; - - expect->base = NULL; - expect->len = 0; -@@ -406,12 +406,12 @@ static void send_bad_request_on_complete(h2o_socket_t *sock, const char *err) - - static void send_bad_request(struct st_h2o_http1_conn_t *conn) - { -- const static h2o_iovec_t resp = {H2O_STRLIT("HTTP/1.1 400 Bad Request\r\n" -+ const static h2o_iovec_t resp = H2O_IOVEC_STRLIT("HTTP/1.1 400 Bad Request\r\n" - "Content-Type: text/plain; charset=utf-8\r\n" - "Connection: close\r\n" - "Content-Length: 11\r\n" - "\r\n" -- "Bad Request")}; -+ "Bad Request"); - - assert(conn->req.version == 0 && "request has not been parsed successfully"); - assert(conn->req.http1_is_persistent == 0); -@@ -421,7 +421,7 @@ static void send_bad_request(struct st_h2o_http1_conn_t *conn) - - static void handle_incoming_request(struct st_h2o_http1_conn_t *conn) - { -- size_t inreqlen = conn->sock->input->size < H2O_MAX_REQLEN ? conn->sock->input->size : H2O_MAX_REQLEN; -+ size_t methodlen, pathlen, inreqlen = conn->sock->input->size < H2O_MAX_REQLEN ? conn->sock->input->size : H2O_MAX_REQLEN; - int reqlen, minor_version; - struct phr_header headers[H2O_MAX_HEADERS]; - size_t num_headers = H2O_MAX_HEADERS; -@@ -433,8 +433,10 @@ static void handle_incoming_request(struct st_h2o_http1_conn_t *conn) - conn->req.timestamps.request_begin_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); - - reqlen = phr_parse_request(conn->sock->input->bytes, inreqlen, (const char **)&conn->req.input.method.base, -- &conn->req.input.method.len, (const char **)&conn->req.input.path.base, &conn->req.input.path.len, -+ &methodlen, (const char **)&conn->req.input.path.base, &pathlen, - &minor_version, headers, &num_headers, conn->_prevreqlen); -+ conn->req.input.method.len = methodlen; -+ conn->req.input.path.len = pathlen; - conn->_prevreqlen = inreqlen; - - switch (reqlen) { -@@ -455,7 +457,7 @@ static void handle_incoming_request(struct st_h2o_http1_conn_t *conn) - return; - } - if (expect.base != NULL) { -- static const h2o_iovec_t res = {H2O_STRLIT("HTTP/1.1 100 Continue\r\n\r\n")}; -+ static const h2o_iovec_t res = H2O_IOVEC_STRLIT("HTTP/1.1 100 Continue\r\n\r\n"); - h2o_socket_write(conn->sock, (void *)&res, 1, on_continue_sent); - /* processing of the incoming entity is postponed until the 100 response is sent */ - h2o_socket_read_stop(conn->sock); -@@ -477,7 +479,7 @@ static void handle_incoming_request(struct st_h2o_http1_conn_t *conn) - /* upgrade to HTTP/2 if the request starts with: PRI * HTTP/2 */ - if (conn->super.ctx->globalconf->http1.upgrade_to_http2) { - /* should check up to the first octet that phr_parse_request returns an error */ -- static const h2o_iovec_t HTTP2_SIG = {H2O_STRLIT("PRI * HTTP/2")}; -+ static const h2o_iovec_t HTTP2_SIG = H2O_IOVEC_STRLIT("PRI * HTTP/2"); - if (conn->sock->input->size >= HTTP2_SIG.len && memcmp(conn->sock->input->bytes, HTTP2_SIG.base, HTTP2_SIG.len) == 0) { - h2o_accept_ctx_t accept_ctx = {conn->super.ctx, conn->super.hosts}; - h2o_socket_t *sock = conn->sock; -@@ -638,7 +640,7 @@ static size_t flatten_headers(char *buf, h2o_req_t *req, const char *connection) - * - https://www.igvita.com/2013/05/01/deploying-webp-via-accept-content-negotiation/ - */ - if (is_msie(req)) { -- static h2o_header_t cache_control_private = {&H2O_TOKEN_CACHE_CONTROL->buf, NULL, {H2O_STRLIT("private")}}; -+ static h2o_header_t cache_control_private = {&H2O_TOKEN_CACHE_CONTROL->buf, NULL, H2O_IOVEC_STRLIT("private")}; - header = &cache_control_private; - } - } -@@ -660,11 +662,11 @@ static size_t flatten_headers(char *buf, h2o_req_t *req, const char *connection) - - static void proceed_pull(struct st_h2o_http1_conn_t *conn, size_t nfilled) - { -- h2o_iovec_t buf = {conn->_ostr_final.pull.buf, nfilled}; -+ h2o_iovec_t buf = h2o_iovec_init(conn->_ostr_final.pull.buf, nfilled); - h2o_send_state_t send_state; - - if (buf.len < MAX_PULL_BUF_SZ) { -- h2o_iovec_t cbuf = {buf.base + buf.len, MAX_PULL_BUF_SZ - buf.len}; -+ h2o_iovec_t cbuf = h2o_iovec_init(buf.base + buf.len, MAX_PULL_BUF_SZ - buf.len); - send_state = h2o_pull(&conn->req, conn->_ostr_final.pull.cb, &cbuf); - if (send_state == H2O_SEND_STATE_ERROR) { - conn->req.http1_is_persistent = 0; -diff --git a/lib/http2/casper.c b/lib/http2/casper.c -index 56e00d71f..e5c9a0ed7 100644 ---- a/lib/http2/casper.c -+++ b/lib/http2/casper.c -@@ -56,7 +56,7 @@ h2o_http2_casper_t *h2o_http2_casper_create(unsigned capacity_bits, unsigned rem - memset(&casper->keys, 0, sizeof(casper->keys)); - casper->capacity_bits = capacity_bits; - casper->remainder_bits = remainder_bits; -- casper->cookie_cache = (h2o_iovec_t){NULL}; -+ casper->cookie_cache = (h2o_iovec_t)H2O_IOVEC_NULL; - - return casper; - } -@@ -89,7 +89,7 @@ int h2o_http2_casper_lookup(h2o_http2_casper_t *casper, const char *path, size_t - - /* we need to set a new value */ - free(casper->cookie_cache.base); -- casper->cookie_cache = (h2o_iovec_t){NULL}; -+ casper->cookie_cache = (h2o_iovec_t)H2O_IOVEC_NULL; - h2o_vector_reserve(NULL, &casper->keys, casper->keys.size + 1); - memmove(casper->keys.entries + i + 1, casper->keys.entries + i, (casper->keys.size - i) * sizeof(casper->keys.entries[0])); - ++casper->keys.size; -@@ -99,7 +99,7 @@ int h2o_http2_casper_lookup(h2o_http2_casper_t *casper, const char *path, size_t - - void h2o_http2_casper_consume_cookie(h2o_http2_casper_t *casper, const char *cookie, size_t cookie_len) - { -- h2o_iovec_t binary = {NULL}; -+ h2o_iovec_t binary = H2O_IOVEC_NULL; - uint64_t tiny_keys_buf[128], *keys = tiny_keys_buf; - - /* check the name of the cookie */ -@@ -177,7 +177,7 @@ h2o_iovec_t h2o_http2_casper_get_cookie(h2o_http2_casper_t *casper) - return casper->cookie_cache; - - if (casper->keys.size == 0) -- return (h2o_iovec_t){NULL}; -+ return (h2o_iovec_t)H2O_IOVEC_NULL; - - /* encode as binary */ - char tiny_bin_buf[128], *bin_buf = tiny_bin_buf; -diff --git a/lib/http2/connection.c b/lib/http2/connection.c -index 2f8cad620..c7ba5d6b2 100644 ---- a/lib/http2/connection.c -+++ b/lib/http2/connection.c -@@ -27,7 +27,7 @@ - #include "h2o/http2.h" - #include "h2o/http2_internal.h" - --static const h2o_iovec_t CONNECTION_PREFACE = {H2O_STRLIT("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")}; -+static const h2o_iovec_t CONNECTION_PREFACE = H2O_IOVEC_STRLIT("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"); - - const h2o_http2_priority_t h2o_http2_default_priority = { - 0, /* exclusive */ -@@ -43,7 +43,7 @@ const h2o_http2_settings_t H2O_HTTP2_SETTINGS_HOST = { - 16384 /* max_frame_size */ - }; - --static const h2o_iovec_t SETTINGS_HOST_BIN = {H2O_STRLIT("\x00\x00\x0c" /* frame size */ -+static const h2o_iovec_t SETTINGS_HOST_BIN = H2O_IOVEC_STRLIT("\x00\x00\x0c"/* frame size */ - "\x04" /* settings frame */ - "\x00" /* no flags */ - "\x00\x00\x00\x00" /* stream id */ -@@ -51,7 +51,7 @@ static const h2o_iovec_t SETTINGS_HOST_BIN = {H2O_STRLIT("\x00\x00\x0c" /* f - "\x00\x00\x00\x64" /* max_concurrent_streams = 100 */ - "\x00\x04" - "\x01\x00\x00\x00" /* initial_window_size = 16777216 */ -- )}; -+ ); - - static __thread h2o_buffer_prototype_t wbuf_buffer_prototype = {{16}, {H2O_HTTP2_DEFAULT_OUTBUF_SIZE}}; - -@@ -103,7 +103,7 @@ static void graceful_shutdown_resend_goaway(h2o_timeout_entry_t *entry) - for (node = ctx->http2._conns.next; node != &ctx->http2._conns; node = node->next) { - h2o_http2_conn_t *conn = H2O_STRUCT_FROM_MEMBER(h2o_http2_conn_t, _conns, node); - if (conn->state < H2O_HTTP2_CONN_STATE_HALF_CLOSED) { -- enqueue_goaway(conn, H2O_HTTP2_ERROR_NONE, (h2o_iovec_t){NULL}); -+ enqueue_goaway(conn, H2O_HTTP2_ERROR_NONE, (h2o_iovec_t)H2O_IOVEC_NULL); - do_close_stragglers = 1; - } - } -@@ -135,7 +135,7 @@ static void initiate_graceful_shutdown(h2o_context_t *ctx) - h2o_http2_conn_t *conn = H2O_STRUCT_FROM_MEMBER(h2o_http2_conn_t, _conns, node); - if (conn->state < H2O_HTTP2_CONN_STATE_HALF_CLOSED) { - h2o_http2_encode_goaway_frame(&conn->_write.buf, INT32_MAX, H2O_HTTP2_ERROR_NONE, -- (h2o_iovec_t){H2O_STRLIT("graceful shutdown")}); -+ (h2o_iovec_t)H2O_IOVEC_STRLIT("graceful shutdown")); - h2o_http2_conn_request_write(conn); - } - } -@@ -876,7 +876,7 @@ static int parse_input(h2o_http2_conn_t *conn) - } else if (ret < 0) { - if (ret != H2O_HTTP2_ERROR_PROTOCOL_CLOSE_IMMEDIATELY) { - enqueue_goaway(conn, (int)ret, -- err_desc != NULL ? (h2o_iovec_t){(char *)err_desc, strlen(err_desc)} : (h2o_iovec_t){NULL}); -+ err_desc != NULL ? h2o_iovec_init((char *)err_desc, strlen(err_desc)) : (h2o_iovec_t)H2O_IOVEC_NULL); - } - return close_connection(conn); - } -@@ -1046,7 +1046,7 @@ void do_emit_writereq(h2o_http2_conn_t *conn) - - if (conn->_write.buf->size != 0) { - /* write and wait for completion */ -- h2o_iovec_t buf = {conn->_write.buf->bytes, conn->_write.buf->size}; -+ h2o_iovec_t buf = h2o_iovec_init(conn->_write.buf->bytes, conn->_write.buf->size); - h2o_socket_write(conn->sock, &buf, 1, on_write_complete); - conn->_write.buf_in_flight = conn->_write.buf; - h2o_buffer_init(&conn->_write.buf, &wbuf_buffer_prototype); -@@ -1290,7 +1290,7 @@ static void push_path(h2o_req_t *src_req, const char *abspath, size_t abspath_le - h2o_http2_stream_prepare_for_request(conn, stream); - - /* setup request */ -- stream->req.input.method = (h2o_iovec_t){H2O_STRLIT("GET")}; -+ stream->req.input.method = (h2o_iovec_t)H2O_IOVEC_STRLIT("GET"); - stream->req.input.scheme = src_stream->req.input.scheme; - stream->req.input.authority = - h2o_strdup(&stream->req.pool, src_stream->req.input.authority.base, src_stream->req.input.authority.len); -diff --git a/lib/http2/hpack.c b/lib/http2/hpack.c -index 4adb15cd7..f4e4679e2 100644 ---- a/lib/http2/hpack.c -+++ b/lib/http2/hpack.c -@@ -902,7 +902,7 @@ void h2o_hpack_flatten_response(h2o_buffer_t **buf, h2o_hpack_header_table_t *he - if (server_name->len) { - dst = encode_header(header_table, dst, &H2O_TOKEN_SERVER->buf, server_name); - } -- h2o_iovec_t date_value = {ts->str->rfc1123, H2O_TIMESTR_RFC1123_LEN}; -+ h2o_iovec_t date_value = h2o_iovec_init(ts->str->rfc1123, H2O_TIMESTR_RFC1123_LEN); - dst = encode_header(header_table, dst, &H2O_TOKEN_DATE->buf, &date_value); - #endif - size_t i; -diff --git a/lib/http2/hpack_static_table.h b/lib/http2/hpack_static_table.h -index 4c1243103..fae748537 100644 ---- a/lib/http2/hpack_static_table.h -+++ b/lib/http2/hpack_static_table.h -@@ -23,65 +23,65 @@ - /* automatically generated by tokens.pl */ - - static const struct st_h2o_hpack_static_table_entry_t h2o_hpack_static_table[61] = { -- { H2O_TOKEN_AUTHORITY, { H2O_STRLIT("") } }, -- { H2O_TOKEN_METHOD, { H2O_STRLIT("GET") } }, -- { H2O_TOKEN_METHOD, { H2O_STRLIT("POST") } }, -- { H2O_TOKEN_PATH, { H2O_STRLIT("/") } }, -- { H2O_TOKEN_PATH, { H2O_STRLIT("/index.html") } }, -- { H2O_TOKEN_SCHEME, { H2O_STRLIT("http") } }, -- { H2O_TOKEN_SCHEME, { H2O_STRLIT("https") } }, -- { H2O_TOKEN_STATUS, { H2O_STRLIT("200") } }, -- { H2O_TOKEN_STATUS, { H2O_STRLIT("204") } }, -- { H2O_TOKEN_STATUS, { H2O_STRLIT("206") } }, -- { H2O_TOKEN_STATUS, { H2O_STRLIT("304") } }, -- { H2O_TOKEN_STATUS, { H2O_STRLIT("400") } }, -- { H2O_TOKEN_STATUS, { H2O_STRLIT("404") } }, -- { H2O_TOKEN_STATUS, { H2O_STRLIT("500") } }, -- { H2O_TOKEN_ACCEPT_CHARSET, { H2O_STRLIT("") } }, -- { H2O_TOKEN_ACCEPT_ENCODING, { H2O_STRLIT("gzip, deflate") } }, -- { H2O_TOKEN_ACCEPT_LANGUAGE, { H2O_STRLIT("") } }, -- { H2O_TOKEN_ACCEPT_RANGES, { H2O_STRLIT("") } }, -- { H2O_TOKEN_ACCEPT, { H2O_STRLIT("") } }, -- { H2O_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN, { H2O_STRLIT("") } }, -- { H2O_TOKEN_AGE, { H2O_STRLIT("") } }, -- { H2O_TOKEN_ALLOW, { H2O_STRLIT("") } }, -- { H2O_TOKEN_AUTHORIZATION, { H2O_STRLIT("") } }, -- { H2O_TOKEN_CACHE_CONTROL, { H2O_STRLIT("") } }, -- { H2O_TOKEN_CONTENT_DISPOSITION, { H2O_STRLIT("") } }, -- { H2O_TOKEN_CONTENT_ENCODING, { H2O_STRLIT("") } }, -- { H2O_TOKEN_CONTENT_LANGUAGE, { H2O_STRLIT("") } }, -- { H2O_TOKEN_CONTENT_LENGTH, { H2O_STRLIT("") } }, -- { H2O_TOKEN_CONTENT_LOCATION, { H2O_STRLIT("") } }, -- { H2O_TOKEN_CONTENT_RANGE, { H2O_STRLIT("") } }, -- { H2O_TOKEN_CONTENT_TYPE, { H2O_STRLIT("") } }, -- { H2O_TOKEN_COOKIE, { H2O_STRLIT("") } }, -- { H2O_TOKEN_DATE, { H2O_STRLIT("") } }, -- { H2O_TOKEN_ETAG, { H2O_STRLIT("") } }, -- { H2O_TOKEN_EXPECT, { H2O_STRLIT("") } }, -- { H2O_TOKEN_EXPIRES, { H2O_STRLIT("") } }, -- { H2O_TOKEN_FROM, { H2O_STRLIT("") } }, -- { H2O_TOKEN_HOST, { H2O_STRLIT("") } }, -- { H2O_TOKEN_IF_MATCH, { H2O_STRLIT("") } }, -- { H2O_TOKEN_IF_MODIFIED_SINCE, { H2O_STRLIT("") } }, -- { H2O_TOKEN_IF_NONE_MATCH, { H2O_STRLIT("") } }, -- { H2O_TOKEN_IF_RANGE, { H2O_STRLIT("") } }, -- { H2O_TOKEN_IF_UNMODIFIED_SINCE, { H2O_STRLIT("") } }, -- { H2O_TOKEN_LAST_MODIFIED, { H2O_STRLIT("") } }, -- { H2O_TOKEN_LINK, { H2O_STRLIT("") } }, -- { H2O_TOKEN_LOCATION, { H2O_STRLIT("") } }, -- { H2O_TOKEN_MAX_FORWARDS, { H2O_STRLIT("") } }, -- { H2O_TOKEN_PROXY_AUTHENTICATE, { H2O_STRLIT("") } }, -- { H2O_TOKEN_PROXY_AUTHORIZATION, { H2O_STRLIT("") } }, -- { H2O_TOKEN_RANGE, { H2O_STRLIT("") } }, -- { H2O_TOKEN_REFERER, { H2O_STRLIT("") } }, -- { H2O_TOKEN_REFRESH, { H2O_STRLIT("") } }, -- { H2O_TOKEN_RETRY_AFTER, { H2O_STRLIT("") } }, -- { H2O_TOKEN_SERVER, { H2O_STRLIT("") } }, -- { H2O_TOKEN_SET_COOKIE, { H2O_STRLIT("") } }, -- { H2O_TOKEN_STRICT_TRANSPORT_SECURITY, { H2O_STRLIT("") } }, -- { H2O_TOKEN_TRANSFER_ENCODING, { H2O_STRLIT("") } }, -- { H2O_TOKEN_USER_AGENT, { H2O_STRLIT("") } }, -- { H2O_TOKEN_VARY, { H2O_STRLIT("") } }, -- { H2O_TOKEN_VIA, { H2O_STRLIT("") } }, -- { H2O_TOKEN_WWW_AUTHENTICATE, { H2O_STRLIT("") } } -+ { H2O_TOKEN_AUTHORITY, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_METHOD, H2O_IOVEC_STRLIT("GET") }, -+ { H2O_TOKEN_METHOD, H2O_IOVEC_STRLIT("POST") }, -+ { H2O_TOKEN_PATH, H2O_IOVEC_STRLIT("/") }, -+ { H2O_TOKEN_PATH, H2O_IOVEC_STRLIT("/index.html") }, -+ { H2O_TOKEN_SCHEME, H2O_IOVEC_STRLIT("http") }, -+ { H2O_TOKEN_SCHEME, H2O_IOVEC_STRLIT("https") }, -+ { H2O_TOKEN_STATUS, H2O_IOVEC_STRLIT("200") }, -+ { H2O_TOKEN_STATUS, H2O_IOVEC_STRLIT("204") }, -+ { H2O_TOKEN_STATUS, H2O_IOVEC_STRLIT("206") }, -+ { H2O_TOKEN_STATUS, H2O_IOVEC_STRLIT("304") }, -+ { H2O_TOKEN_STATUS, H2O_IOVEC_STRLIT("400") }, -+ { H2O_TOKEN_STATUS, H2O_IOVEC_STRLIT("404") }, -+ { H2O_TOKEN_STATUS, H2O_IOVEC_STRLIT("500") }, -+ { H2O_TOKEN_ACCEPT_CHARSET, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_ACCEPT_ENCODING, H2O_IOVEC_STRLIT("gzip, deflate") }, -+ { H2O_TOKEN_ACCEPT_LANGUAGE, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_ACCEPT_RANGES, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_ACCEPT, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_AGE, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_ALLOW, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_AUTHORIZATION, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_CACHE_CONTROL, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_CONTENT_DISPOSITION, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_CONTENT_ENCODING, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_CONTENT_LANGUAGE, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_CONTENT_LENGTH, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_CONTENT_LOCATION, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_CONTENT_RANGE, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_CONTENT_TYPE, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_COOKIE, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_DATE, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_ETAG, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_EXPECT, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_EXPIRES, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_FROM, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_HOST, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_IF_MATCH, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_IF_MODIFIED_SINCE, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_IF_NONE_MATCH, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_IF_RANGE, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_IF_UNMODIFIED_SINCE, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_LAST_MODIFIED, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_LINK, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_LOCATION, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_MAX_FORWARDS, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_PROXY_AUTHENTICATE, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_PROXY_AUTHORIZATION, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_RANGE, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_REFERER, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_REFRESH, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_RETRY_AFTER, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_SERVER, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_SET_COOKIE, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_STRICT_TRANSPORT_SECURITY, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_TRANSFER_ENCODING, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_USER_AGENT, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_VARY, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_VIA, H2O_IOVEC_STRLIT("") }, -+ { H2O_TOKEN_WWW_AUTHENTICATE, H2O_IOVEC_STRLIT("") } - }; -diff --git a/lib/http2/http2_debug_state.c b/lib/http2/http2_debug_state.c -index 3ef8de37f..e9245ddcd 100644 ---- a/lib/http2/http2_debug_state.c -+++ b/lib/http2/http2_debug_state.c -@@ -62,7 +62,7 @@ static const char *get_debug_state_string(h2o_http2_stream_t *stream) - return NULL; - } - --__attribute__((format(printf, 3, 4))) static void append_chunk(h2o_mem_pool_t *pool, h2o_iovec_vector_t *chunks, const char *fmt, -+__attribute__((format(gnu_printf, 3, 4))) static void append_chunk(h2o_mem_pool_t *pool, h2o_iovec_vector_t *chunks, const char *fmt, - ...) - { - va_list args; -diff --git a/misc/tokens.pl b/misc/tokens.pl -index 1fcf173fa..1407f6681 100755 ---- a/misc/tokens.pl -+++ b/misc/tokens.pl -@@ -94,7 +94,7 @@ print $fh render_mt(<< 'EOT', \@tokens, LICENSE)->as_string; - /* DO NOT EDIT! generated by tokens.pl */ - h2o_token_t h2o__tokens[] = { - ? for my $i (0..$#$tokens) { -- { { H2O_STRLIT("[$i][0] ?>") }, [$i][$_] } (1..$#{$tokens->[$i]})) ?> } -+ { H2O_IOVEC_STRLIT("[$i][0] ?>"), [$i][$_] } (1..$#{$tokens->[$i]})) ?> } - ? } - }; - size_t h2o__num_tokens = ; -@@ -135,7 +135,7 @@ print $fh render_mt(<< 'EOT', \@hpack, LICENSE)->as_string; - - static const struct st_h2o_hpack_static_table_entry_t h2o_hpack_static_table[] = { - ? for my $i (0..$#$entries) { -- { [$i][0]) ?>, { H2O_STRLIT("[$i][1] || "" ?>") } } -+ { [$i][0]) ?>, H2O_IOVEC_STRLIT("[$i][1] || "" ?>") } - ? } - }; - EOT -diff --git a/src/main.c b/src/main.c -index af0867f29..7c801755d 100644 ---- a/src/main.c -+++ b/src/main.c -@@ -43,7 +43,9 @@ - #include - #include - #include -+#ifndef H2O_NO_UNIX_SOCKETS - #include -+#endif - #include - #include - #include -@@ -886,6 +888,7 @@ Found: - return conf.server_starter.fds[i]; - } - -+#ifndef H2O_NO_UNIX_SOCKETS - static int open_unix_listener(h2o_configurator_command_t *cmd, yoml_t *node, struct sockaddr_un *sa) - { - struct stat st; -@@ -948,6 +951,7 @@ ErrorExit: - close(fd); - return -1; - } -+#endif - - static int open_tcp_listener(h2o_configurator_command_t *cmd, yoml_t *node, const char *hostname, const char *servname, int domain, - int type, int protocol, struct sockaddr *addr, socklen_t addrlen) -@@ -1067,6 +1071,7 @@ static int on_config_listen(h2o_configurator_command_t *cmd, h2o_configurator_co - return -1; - } - -+ #ifndef H2O_NO_UNIX_SOCKETS - if (strcmp(type, "unix") == 0) { - - /* unix socket */ -@@ -1110,7 +1115,9 @@ static int on_config_listen(h2o_configurator_command_t *cmd, h2o_configurator_co - if (listener->hosts != NULL && ctx->hostconf != NULL) - h2o_append_to_null_terminated_list((void *)&listener->hosts, ctx->hostconf); - -- } else if (strcmp(type, "tcp") == 0) { -+ } else -+ #endif -+ if (strcmp(type, "tcp") == 0) { - - /* TCP socket */ - struct addrinfo hints, *res, *ai; -@@ -1712,11 +1719,13 @@ static char **build_server_starter_argv(const char *h2o_cmd, const char *config_ - sprintf(newarg, "--port=%s:%s", host, serv); - } - } break; -+ #ifndef H2O_NO_UNIX_SOCKETS - case AF_UNIX: { - struct sockaddr_un *sa = (void *)&conf.listeners[i]->addr; - newarg = h2o_mem_alloc(sizeof("--path=") + strlen(sa->sun_path)); - sprintf(newarg, "--path=%s", sa->sun_path); - } break; -+ #endif - } - h2o_vector_reserve(NULL, &args, args.size + 1); - args.entries[args.size++] = newarg; diff --git a/pkg/urbit/compat/mingw/lmdb.patch b/pkg/urbit/compat/mingw/lmdb.patch deleted file mode 100644 index e023a7133..000000000 --- a/pkg/urbit/compat/mingw/lmdb.patch +++ /dev/null @@ -1,74 +0,0 @@ -diff --git a/mdb.c b/mdb.c ---- a/mdb.c -+++ b/mdb.c -@@ -1707,28 +1707,27 @@ static char *const mdb_errstr[] = { - "MDB_PROBLEM: Unexpected problem - txn should abort", - }; - --char * --mdb_strerror(int err) -+void -+mdb_logerror(FILE* f, int err, const char* fmt, ...) - { --#ifdef _WIN32 -- /** HACK: pad 4KB on stack over the buf. Return system msgs in buf. -- * This works as long as no function between the call to mdb_strerror -- * and the actual use of the message uses more than 4K of stack. -- */ --#define MSGSIZE 1024 --#define PADSIZE 4096 -- char buf[MSGSIZE+PADSIZE], *ptr = buf; --#endif -+ va_list ap; -+ va_start(ap, fmt); -+ vfprintf(f, fmt, ap); -+ va_end(ap); -+ - int i; - if (!err) -- return ("Successful return: 0"); -+ { -+ fprintf(stderr, ": %s\r\n", "Successful return: 0"); -+ return; -+ } - - if (err >= MDB_KEYEXIST && err <= MDB_LAST_ERRCODE) { - i = err - MDB_KEYEXIST; -- return mdb_errstr[i]; -+ fprintf(stderr, ": %s\r\n", mdb_errstr[i]); -+ return; - } - --#ifdef _WIN32 - /* These are the C-runtime error codes we use. The comment indicates - * their numeric value, and the Win32 error they would correspond to - * if the error actually came from a Win32 API. A major mess, we should -@@ -1742,18 +1741,20 @@ mdb_strerror(int err) - case EBUSY: /* 16, CURRENT_DIRECTORY */ - case EINVAL: /* 22, BAD_COMMAND */ - case ENOSPC: /* 28, OUT_OF_PAPER */ -- return strerror(err); -+ fprintf(stderr, ": %s\r\n", strerror(err)); - default: - ; - } -- buf[0] = 0; -- FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | -+ LPSTR ptr; -+ if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | -+ FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_IGNORE_INSERTS, -- NULL, err, 0, ptr, MSGSIZE, (va_list *)buf+MSGSIZE); -- return ptr; --#else -- return strerror(err); --#endif -+ NULL, err, 0, (LPSTR)&ptr, sizeof (LPSTR), NULL)) -+ { -+ fprintf(stderr, ": %s\r\n", ptr); -+ LocalFree(ptr); -+ } else -+ fprintf(stderr, ": <%d>\r\n", err); - } - - /** assert(3) variant in cursor context */ diff --git a/pkg/urbit/compat/mingw/mman.h b/pkg/urbit/compat/mingw/mman.h deleted file mode 100644 index 965fecfd8..000000000 --- a/pkg/urbit/compat/mingw/mman.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _SYS_MMAN_H -#define _SYS_MMAN_H - -void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); -int munmap(void *addr, size_t length); -int msync(void *addr, size_t length, int flags); -int mprotect(void *addr, size_t len, int prot); - -#define PROT_NONE 0x00 /* No access. */ -#define PROT_READ 0x01 /* Pages can be read. */ -#define PROT_WRITE 0x02 /* Pages can be written. */ -#define PROT_EXEC 0x04 /* Pages can be executed. */ - -#define MAP_FILE 0x0001 /* Mapped from a file or device. */ -#define MAP_ANON 0x0002 /* Allocated from anonymous virtual memory. */ -#define MAP_TYPE 0x000f /* Mask for type field. */ -#define MAP_SHARED 0x0010 /* Share changes. */ -#define MAP_PRIVATE 0x0000 /* Changes private; copy pages on write. */ -#define MAP_FIXED 0x0100 /* Map address must be exactly as requested. */ -#define MAP_FAILED ((void *) -1) - -#define MS_ASYNC 1 /* Sync memory asynchronously. */ -#define MS_SYNC 0 /* Synchronous memory sync. */ -#define MS_INVALIDATE 2 /* Invalidate the caches. */ - -#endif//_SYS_MMAN_H diff --git a/pkg/urbit/compat/mingw/murmur3.patch b/pkg/urbit/compat/mingw/murmur3.patch deleted file mode 100644 index cd83e9fdd..000000000 --- a/pkg/urbit/compat/mingw/murmur3.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/makefile b/makefile ---- a/makefile -+++ b/makefile -@@ -12,5 +12,9 @@ shared: murmur3.c murmur3.h - $(CC) -fPIC -O3 -c murmur3.c - $(CC) -shared -Wl,--export-dynamic murmur3.o -o libmurmur3.so - -+static: murmur3.c murmur3.h -+ $(CC) -fPIC -O3 -c murmur3.c -+ $(AR) rcs libmurmur3.a murmur3.o -+ - clean: - rm -rf example *.o *.so diff --git a/pkg/urbit/compat/mingw/ptty.c b/pkg/urbit/compat/mingw/ptty.c deleted file mode 100644 index 7ad2962c4..000000000 --- a/pkg/urbit/compat/mingw/ptty.c +++ /dev/null @@ -1,152 +0,0 @@ -/* compat/mingw/ptty.c -** -*/ -#include "all.h" -#include "vere/vere.h" -#include - -/* _ptty_get_type(): detects tty type. -*/ -static DWORD -_ptty_get_type(int fd) -{ - HANDLE h = (HANDLE)_get_osfhandle(fd); - if (h == INVALID_HANDLE_VALUE) - return FILE_TYPE_UNKNOWN; - - DWORD t = GetFileType(h); - if (t != FILE_TYPE_PIPE) - return t ; - - // https://github.com/fusesource/jansi-native/commit/461068c67a38647d2890e96250636fc0117074f5 - ULONG result; - BYTE buffer[1024]; - POBJECT_NAME_INFORMATION nameinfo = (POBJECT_NAME_INFORMATION) buffer; - PWSTR name; - - /* get pipe name */ - if (!NT_SUCCESS(NtQueryObject(h, ObjectNameInformation, buffer, sizeof(buffer) - sizeof(WCHAR), &result))) - return FILE_TYPE_UNKNOWN; - - name = nameinfo->Name.Buffer; - name[nameinfo->Name.Length] = 0; - - // check for popular terminal emulators - // that use named pipes to communicate with subprocesses - if (wcsstr(name, L"\\ConEmu") || - (wcsstr(name, L"msys-") || wcsstr(name, L"cygwin-")) && wcsstr(name, L"-pty")) - return FILE_TYPE_PIPE; - - return FILE_TYPE_UNKNOWN; -} - -/* _ttyf_nop(): stub function. -*/ -static c3_o -_ttyf_nop(u3_utty* uty_u) -{ - return c3y; -} - -/* _ttyf_start_raw_input(): ends raw input on the tty. -*/ -static c3_o -_ttyf_set_normal(u3_utty* uty_u) -{ - c3_i e; - if ( 0 != (e = uv_tty_set_mode(&uty_u->pin_u.tty_u, UV_TTY_MODE_NORMAL)) ) { - fprintf(stderr, "uv_tty_set_mode(UV_TTY_MODE_NORMAL) -> %d\r\n", e); - return c3n; - } - return c3y; -} - -/* _ttyf_start_raw_input(): sets the tty to raw input. -*/ -static c3_o -_ttyf_set_raw(u3_utty* uty_u) -{ - c3_i e; - if ( 0 != (e = uv_tty_set_mode(&uty_u->pin_u.tty_u, UV_TTY_MODE_RAW)) ) { - fprintf(stderr, "uv_tty_set_mode(UV_TTY_MODE_RAW) -> %d\r\n", e); - return c3n; - } - return c3y; -} - -/* _ttyf_get_winsize(): gets the tty window size. -*/ -static c3_o -_ttyf_get_winsize(u3_utty* uty_u, c3_l* col_l, c3_l* row_l) -{ - c3_i col_i, row_i; - if ( 0 != uv_tty_get_winsize(&uty_u->pop_u.tty_u, &col_i, &row_i) ) { - return c3n; - } - - *col_l = col_i; - *row_l = row_i; - return c3y; -} - -/* _ttyf_get_winsize(): gets the tty window size. -*/ -static c3_o -_ttyf_nop_winsize(u3_utty* uty_u, c3_l* col_l, c3_l* row_l) -{ - return c3n; -} - -/* u3_ptty_init(): initialize platform-specific tty. -*/ -u3_utty* -u3_ptty_init(uv_loop_t* lup_u, const c3_c** err_c) -{ - DWORD pip_l = _ptty_get_type(0); - DWORD pop_l = _ptty_get_type(1); - if ( pip_l == FILE_TYPE_UNKNOWN || pop_l == FILE_TYPE_UNKNOWN) { - *err_c = "not a tty"; - return NULL; - } - - if ( pip_l != pop_l ) { - *err_c = "partly redirected"; - return NULL; - } - - c3_i e; - u3_utty* uty_u = c3_calloc(sizeof(u3_utty)); - if ( pip_l == FILE_TYPE_CHAR ) { - if ( 0 == (e = uv_tty_init(lup_u, &uty_u->pin_u.tty_u, 0, 0)) && - 0 == (e = uv_tty_init(lup_u, &uty_u->pop_u.tty_u, 1, 0)) ) - { - SetConsoleOutputCP(CP_UTF8); - uty_u->sta_f = _ttyf_set_raw; - uty_u->sto_f = _ttyf_set_normal; - uty_u->wsz_f = _ttyf_get_winsize; - } - } else { - if ( 0 == (e = uv_pipe_init(lup_u, &uty_u->pin_u.pip_u, 0)) && - 0 == (e = uv_pipe_init(lup_u, &uty_u->pop_u.pip_u, 0)) && - 0 == (e = uv_pipe_open(&uty_u->pin_u.pip_u, 0)) && - 0 == (e = uv_pipe_open(&uty_u->pop_u.pip_u, 1)) ) - { - fprintf(stderr, "vere: running interactive in a terminal emulator is experimental\r\n" - " use -t to disable interactivity or use native Windows console\r\n") ; - uty_u->sta_f = _ttyf_nop; - uty_u->sto_f = _ttyf_nop; - uty_u->wsz_f = _ttyf_nop_winsize; - } - } - - if ( e ) { - *err_c = uv_strerror(e); - c3_free(uty_u); - return NULL; - } - - uty_u->fid_i = 1; - uty_u->hij_f = _ttyf_nop; - uty_u->loj_f = _ttyf_nop; - return uty_u; -} diff --git a/pkg/urbit/compat/mingw/rsignal.c b/pkg/urbit/compat/mingw/rsignal.c deleted file mode 100644 index b49dff515..000000000 --- a/pkg/urbit/compat/mingw/rsignal.c +++ /dev/null @@ -1,167 +0,0 @@ -#include "all.h" -#include "rsignal.h" -#include - -int err_win_to_posix(DWORD winerr); - -// The current implementation of rsignal_ is single-threaded, -// but it can be extended to multi-threaded by replacing these -// static variables with a thread id-based hash map. -// -static __p_sig_fn_t _fns[SIG_COUNT]; -static volatile DWORD _tid; -static HANDLE _hvt; - -void rsignal_install_handler(int sig, __p_sig_fn_t fn) -{ - if (sig < 0 || sig >= SIG_COUNT) - return; - - DWORD newtid = GetCurrentThreadId(); - DWORD oldtid = InterlockedExchange(&_tid, newtid); - if (oldtid != 0 && oldtid != newtid) { - fprintf(stderr, "\r\nrsignal_install_handler: %u -> %u\r\n", oldtid, newtid); - return; - } - - __p_sig_fn_t oldfn = InterlockedExchangePointer((PVOID*)&_fns[sig], fn); - if (fn != 0 && oldfn != 0 && oldfn != fn) { - fprintf(stderr, "\r\nrsignal_install_handler: %p -> %p\r\n", oldfn, fn); - } -} - -void rsignal_deinstall_handler(int sig) -{ - rsignal_install_handler(sig, 0); -} - -void rsignal_raise(int sig) -{ - if (sig < 0 || sig >= SIG_COUNT) - return; - - __p_sig_fn_t oldfn = InterlockedExchangePointer((PVOID*)&_fns[sig], 0); - if (oldfn == 0) - return; - - if (_tid == GetCurrentThreadId()) { - oldfn(sig); - return; - } - - HANDLE hthread = OpenThread(THREAD_ALL_ACCESS, FALSE, _tid); - if (!hthread) { - fprintf(stderr, "\r\nrsignal_raise: OpenThread(%u): %d\r\n", _tid, GetLastError()); - return; - } - - if (SuspendThread(hthread) < 0) { - fprintf(stderr, "\r\nrsignal_raise: SuspendThread(%u): %d\r\n", _tid, GetLastError()); - goto cleanup; - } - - oldfn(sig); - - if (!ResumeThread(hthread)) { - fprintf(stderr, "\r\nrsignal_raise: ResumeThread(%u): %d\r\n", _tid, GetLastError()); - - // abort because the main thread is stuck - abort(); - } - -cleanup: - CloseHandle(hthread); -} - -static void _rsignal_vt_cb(PVOID param, BOOLEAN timedOut) -{ - rsignal_raise(SIGVTALRM); -} - -int rsignal_setitimer(int type, struct itimerval *in, struct itimerval *out) -{ - if (in == 0) { - errno = EFAULT; - return -1; - } - - if (type != ITIMER_VIRTUAL || out != 0) { - errno = ENOTSUP; - return -1; - } - - if (_hvt != NULL) { - DeleteTimerQueueTimer(NULL, _hvt, NULL); - _hvt = NULL; - } - - if (timerisset(&in->it_value) && !CreateTimerQueueTimer(&_hvt, NULL, _rsignal_vt_cb, NULL, - in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000, - in->it_interval.tv_sec * 1000 + in->it_interval.tv_usec / 1000, 0)) - { - errno = err_win_to_posix(GetLastError()); - return -1; - } else { - return 0; - } -} - -// direct import from ntdll.dll -extern DWORD64 __imp_KiUserExceptionDispatcher; - -static void _rsignal_longjmp(intptr_t* builtin_jb) -{ - __builtin_longjmp(builtin_jb, 1); -} - -void rsignal_post_longjmp(DWORD tid, intptr_t* builtin_jb) -{ - HANDLE hthread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid); - if (!hthread) { - fprintf(stderr, "\r\nrsignal: OpenThread(%u): %d\r\n", tid, GetLastError()); - return; - } - - CONTEXT context; - context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; - if (!GetThreadContext(hthread, &context)) { - fprintf(stderr, "\r\nrsignal: GetThreadContext(%u): %d\r\n", tid, GetLastError()); - goto cleanup; - } - - // see if the thread is currently handling a structured exception - // if so, let the handler (usually the libsigsegv handler) finish - // and set up the the signal to run at the exception resume point - // otherwise, passing a parameter to fn is completely unreliable - // - DWORD64 kibase; - PRUNTIME_FUNCTION ki = RtlLookupFunctionEntry(__imp_KiUserExceptionDispatcher, &kibase, NULL); - CONTEXT c = context; - while (1) - { - DWORD64 base, frame; - PRUNTIME_FUNCTION f = RtlLookupFunctionEntry(c.Rip, &base, NULL); - if (!f) break; - if (f == ki) - { - // KiUserExceptionDispatcher has a "bare" frame - // with $rsp pointing to the CONTEXT structure - // - ((PCONTEXT)c.Rsp)->Rip = (DWORD64)_rsignal_longjmp; - ((PCONTEXT)c.Rsp)->Rcx = (DWORD64)builtin_jb; - goto cleanup; - } - PVOID handler_data; - RtlVirtualUnwind(0, base, c.Rip, f, &c, &handler_data, &frame, NULL); - } - - context.Rip = (DWORD64)_rsignal_longjmp; - context.Rcx = (DWORD64)builtin_jb; - if (!SetThreadContext(hthread, &context)) { - fprintf(stderr, "\r\nrsignal: SetThreadContext(%u): %d\r\n", tid, GetLastError()); - goto cleanup; - } - -cleanup: - CloseHandle(hthread); -} diff --git a/pkg/urbit/compat/mingw/rsignal.h b/pkg/urbit/compat/mingw/rsignal.h deleted file mode 100644 index 5af8e2dcd..000000000 --- a/pkg/urbit/compat/mingw/rsignal.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _RSIGNAL_H -#define _RSIGNAL_H - -typedef struct { - jmp_buf jb; - unsigned long tid; -} rsignal_jmpbuf; - -#define rsignal_setjmp(buf) (buf.tid = GetCurrentThreadId(), setjmp(buf.jb)) -#define rsignal_longjmp(buf, val) if (buf.tid != GetCurrentThreadId()) {buf.jb.retval = (val); rsignal_post_longjmp(buf.tid, buf.jb.buffer);} else longjmp(buf.jb, val) - -void rsignal_raise(int sig); -void rsignal_install_handler(int sig, __p_sig_fn_t fn); -void rsignal_deinstall_handler(int sig); -void rsignal_post_longjmp(unsigned long tid, intptr_t* builtin_jb); - -#define ITIMER_VIRTUAL 1 -struct itimerval { - struct timeval it_value, it_interval; -}; - -int rsignal_setitimer(int type, struct itimerval *in, struct itimerval *out); - -#endif//_RSIGNAL_H diff --git a/pkg/urbit/compat/mingw/seh_handler.c b/pkg/urbit/compat/mingw/seh_handler.c deleted file mode 100644 index ecf59f0a4..000000000 --- a/pkg/urbit/compat/mingw/seh_handler.c +++ /dev/null @@ -1,25 +0,0 @@ -#include "all.h" -#include "rsignal.h" -#include "vere/vere.h" - -/* _mingw_exception_filter: replaces libsigsegv on MingW -*/ -EXCEPTION_DISPOSITION _mingw_exception_filter( - IN PEXCEPTION_RECORD ExceptionRecord, - IN ULONG64 EstablisherFrame, - IN OUT PCONTEXT ContextRecord, - IN OUT PDISPATCHER_CONTEXT DispatcherContext) -{ - if (ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && - ExceptionRecord->ExceptionInformation[0] == 1 && - u3e_fault((void*)ExceptionRecord->ExceptionInformation[1], 1)) - { - return ExceptionContinueExecution; - } - - if (ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { - rsignal_raise(SIGSTK); - } - - return ExceptionContinueSearch; -} diff --git a/pkg/urbit/compat/mingw/seh_handler_decorator.cc b/pkg/urbit/compat/mingw/seh_handler_decorator.cc deleted file mode 100644 index acc97efcc..000000000 --- a/pkg/urbit/compat/mingw/seh_handler_decorator.cc +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include - -enum { INIT, CPAR, DQ, DQS, SQ, SQS }; -char line[1 << 16]; - -/* seh_handler_decorator: registers u3_exception_handler for all functions in given source file -*/ -int main(int argc, const char* argv[]) -{ - if (argc != 2) - return 1; - - int c, state = INIT, curly = 0, emit = 0; - - while (fgets(line, sizeof(line), stdin)) - { - if (line[0] == '#') - { - emit = !!strstr(line, argv[1]); - fputs(line, stdout); - } - else - for (int i = 0; line[i]; i++) - { - switch (state) { - case INIT: - case CPAR: - switch (line[i]) { - case ' ': - case '\t': - case '\n': - case '\r': - case '\f': break; - case '{': curly++; if (emit && curly == 1 && state == CPAR) goto emit_handler; goto reset; - case '}': curly--; goto reset; - case '"': state = DQ; break; - case '\'': state = SQ; break; - case ')': state = CPAR; break; - reset: - default: state = INIT; break; - } break; - case DQ: - switch (line[i]) { - case '\\': state = DQS; break; - case '"': state = INIT; break; - } break; - case DQS: state = DQ; break; - case SQ: - switch (line[i]) { - case '\\': state = SQS; break; - case '\'': state = INIT; break; - } break; - case SQS: state = SQ; break; - } - fputc(line[i], stdout); - continue; - emit_handler: - fputs("{__asm__(\".seh_handler _mingw_exception_filter,@except\\n\");", stdout); - state = INIT; - } - } - - return 0; -} diff --git a/pkg/urbit/compat/mingw/seh_handler_decorator.mk b/pkg/urbit/compat/mingw/seh_handler_decorator.mk deleted file mode 100644 index aa2a4c37d..000000000 --- a/pkg/urbit/compat/mingw/seh_handler_decorator.mk +++ /dev/null @@ -1,24 +0,0 @@ -# This include file injects a step that transforms vere C source to register -# a SEH exception handler for each function that is declared in a .c file. -# It inserts a .seh_handler directive into each function body with __asm__. -# This directive affects the x64 unwind tables (.pdata and .xdata sections) -# emitted by the compiler. -# -# See gas/config/obj-coff-seh.h in binutils source for .seh_handler, and -# https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64 -# for a description of how stack unwinding and SEH work in x64 Windows. -# -# When this file sets CCEXTRA, the first invocation of $(CC) in Makefile -# writes preprocessor output to stdout (-E -o -), which is piped to a simple -# parser that inserts __asm__ statements to each function in the .c file -# being compiled. The second invocation of $(CC) reads transformed source -# from stdin (-x cpp-output -). $< argument to $(sehdexe) tells the parser -# which .c file is being compiled. - -sehdexe := build/seh_handler_decorator.exe -CCDEPS := $(CCDEPS) $(sehdexe) -CCEXTRA = -E -o -|$(sehdexe) $<|$(CC) $(CFLAGS) -x cpp-output - - -$(sehdexe): compat/mingw/seh_handler_decorator.cc - @mkdir -p ./build - @$(CC) $< -o $@ diff --git a/pkg/urbit/compat/mingw/setjmp.h b/pkg/urbit/compat/mingw/setjmp.h deleted file mode 100644 index 497636872..000000000 --- a/pkg/urbit/compat/mingw/setjmp.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _MINGW_SETJMP_H -#define _MINGW_SETJMP_H - -// msvcrt setjmp/longjmp are broken on 64-bit systems, use gcc builtins -typedef struct jmp_buf { - intptr_t buffer[5]; - int retval; -} jmp_buf; - -#define _setjmp setjmp -#define _longjmp longjmp -#define longjmp(buf, val) {buf.retval = (val); __builtin_longjmp(buf.buffer, 1);} -#define setjmp(buf) (__builtin_setjmp(buf.buffer) ? (buf.retval) : 0) - -#endif//_MINGW_SETJMP_H diff --git a/pkg/urbit/compat/mingw/softfloat3.patch b/pkg/urbit/compat/mingw/softfloat3.patch deleted file mode 100644 index 9f0c5c5e7..000000000 --- a/pkg/urbit/compat/mingw/softfloat3.patch +++ /dev/null @@ -1,36 +0,0 @@ -diff --git a/build/Win64-MinGW-w64/Makefile b/build/Win64-MinGW-w64/Makefile ---- a/build/Win64-MinGW-w64/Makefile -+++ b/build/Win64-MinGW-w64/Makefile -@@ -46,7 +46,8 @@ C_INCLUDES = -I. -I$(SOURCE_DIR)/$(SPECIALIZE_TYPE) -I$(SOURCE_DIR)/include - COMPILE_C = \ - x86_64-w64-mingw32-gcc -c -Werror-implicit-function-declaration \ - -DSOFTFLOAT_FAST_INT64 $(SOFTFLOAT_OPTS) $(C_INCLUDES) -O2 -o $@ --MAKELIB = x86_64-w64-mingw32-ar crs $@ -+MAKELIB = x86_64-w64-mingw32-gcc-ar crs $@ -+LIBNAME = libsoftfloat3 - - OBJ = .o - LIB = .a -@@ -54,7 +55,7 @@ LIB = .a - OTHER_HEADERS = $(SOURCE_DIR)/include/opts-GCC.h - - .PHONY: all --all: softfloat$(LIB) -+all: $(LIBNAME)$(LIB) - - OBJS_PRIMITIVES = \ - s_eq128$(OBJ) \ -@@ -380,11 +381,11 @@ $(OBJS_PRIMITIVES) $(OBJS_OTHERS): %$(OBJ): $(SOURCE_DIR)/%.c - $(OBJS_SPECIALIZE): %$(OBJ): $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/%.c - $(COMPILE_C) $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/$*.c - --softfloat$(LIB): $(OBJS_ALL) -+$(LIBNAME)$(LIB): $(OBJS_ALL) - $(DELETE) $@ - $(MAKELIB) $^ - - .PHONY: clean - clean: -- $(DELETE) $(OBJS_ALL) softfloat$(LIB) -+ $(DELETE) $(OBJS_ALL) $(LIBNAME)$(LIB) - diff --git a/pkg/urbit/compat/mingw/uv.patch b/pkg/urbit/compat/mingw/uv.patch deleted file mode 100644 index 1a0a6d694..000000000 --- a/pkg/urbit/compat/mingw/uv.patch +++ /dev/null @@ -1,38 +0,0 @@ -diff --git a/src/win/pipe.c b/src/win/pipe.c -index 0f2bb869b..f81245ec6 100644 ---- a/src/win/pipe.c -+++ b/src/win/pipe.c -@@ -270,6 +270,12 @@ static int uv_set_pipe_handle(uv_loop_t* loop, - - if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) { - err = GetLastError(); -+ if ((err == ERROR_INVALID_FUNCTION || err == ERROR_INVALID_PARAMETER) && (duplex_flags & UV_HANDLE_WRITABLE)) { -+ /* -+ * it's not a pipe, but simple writes should be fine -+ * let's trust callers to know what they're doing -+ */ -+ } else - if (err == ERROR_ACCESS_DENIED) { - /* - * SetNamedPipeHandleState can fail if the handle doesn't have either -@@ -1054,7 +1054,6 @@ static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) { - assert(req != NULL); - assert(req->type == UV_WRITE); - assert(handle->type == UV_NAMED_PIPE); -- assert(req->write_buffer.base); - - result = WriteFile(handle->handle, - req->write_buffer.base, -diff --git a/src/win/tty.c b/src/win/tty.c -index c359d5601..1b9d4f853 100644 ---- a/src/win/tty.c -+++ b/src/win/tty.c -@@ -367,7 +367,7 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { - flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; - break; - case UV_TTY_MODE_RAW: -- flags = ENABLE_WINDOW_INPUT; -+ flags = ENABLE_WINDOW_INPUT | ENABLE_PROCESSED_INPUT; - break; - case UV_TTY_MODE_IO: - return UV_ENOTSUP; diff --git a/pkg/urbit/compat/openbsd/lmdb.patch b/pkg/urbit/compat/openbsd/lmdb.patch deleted file mode 100644 index f997db980..000000000 --- a/pkg/urbit/compat/openbsd/lmdb.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/Makefile b/Makefile ---- a/Makefile -+++ b/Makefile -@@ -18,7 +18,7 @@ - # There may be other macros in mdb.c of interest. You should - # read mdb.c before changing any of them. - # --CC = gcc -+CC = cc - AR = ar - W = -W -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized - THREADS = -pthread diff --git a/pkg/urbit/compat/openbsd/murmur3.patch b/pkg/urbit/compat/openbsd/murmur3.patch deleted file mode 100644 index cd83e9fdd..000000000 --- a/pkg/urbit/compat/openbsd/murmur3.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/makefile b/makefile ---- a/makefile -+++ b/makefile -@@ -12,5 +12,9 @@ shared: murmur3.c murmur3.h - $(CC) -fPIC -O3 -c murmur3.c - $(CC) -shared -Wl,--export-dynamic murmur3.o -o libmurmur3.so - -+static: murmur3.c murmur3.h -+ $(CC) -fPIC -O3 -c murmur3.c -+ $(AR) rcs libmurmur3.a murmur3.o -+ - clean: - rm -rf example *.o *.so diff --git a/pkg/urbit/compat/openbsd/softfloat3.patch b/pkg/urbit/compat/openbsd/softfloat3.patch deleted file mode 100644 index 278a7011e..000000000 --- a/pkg/urbit/compat/openbsd/softfloat3.patch +++ /dev/null @@ -1,85 +0,0 @@ -diff --git a/build/template-FAST_INT64/Makefile b/build/template-FAST_INT64/Makefile ---- a/build/template-FAST_INT64/Makefile -+++ b/build/template-FAST_INT64/Makefile -@@ -34,28 +34,27 @@ - # - #============================================================================= - --# Edit lines marked with `==>'. See "SoftFloat-source.html". -+SOURCE_DIR ?= ../../source -+SPECIALIZE_TYPE ?= 8086-SSE - --==> SOURCE_DIR ?= ../../source --==> SPECIALIZE_TYPE ?= 8086 -+SOFTFLOAT_OPTS ?= \ -+ -DSOFTFLOAT_ROUND_ODD -DINLINE_LEVEL=5 -DSOFTFLOAT_FAST_DIV32TO16 \ -+ -DSOFTFLOAT_FAST_DIV64TO32 - --==> SOFTFLOAT_OPTS ?= \ --==> -DSOFTFLOAT_ROUND_ODD -DINLINE_LEVEL=5 -DSOFTFLOAT_FAST_DIV32TO16 \ --==> -DSOFTFLOAT_FAST_DIV64TO32 -+DELETE = rm -f -+C_INCLUDES = -I. -I$(SOURCE_DIR)/$(SPECIALIZE_TYPE) -I$(SOURCE_DIR)/include -+COMPILE_C = \ -+ cc -c -DSOFTFLOAT_FAST_INT64 $(SOFTFLOAT_OPTS) $(C_INCLUDES) -O2 -o $@ -+MAKELIB = ar crs $@ -+LIBNAME = libsoftfloat3 - --==> DELETE = rm -f --==> C_INCLUDES = -I. -I$(SOURCE_DIR)/$(SPECIALIZE_TYPE) -I$(SOURCE_DIR)/include --==> COMPILE_C = \ --==> cc -c -DSOFTFLOAT_FAST_INT64 $(SOFTFLOAT_OPTS) $(C_INCLUDES) -O2 -o $@ --==> MAKELIB = ar crs $@ -+OBJ = .o -+LIB = .a - --==> OBJ = .o --==> LIB = .a -- --==> OTHER_HEADERS = -+OTHER_HEADERS = - - .PHONY: all --all: softfloat$(LIB) -+all: $(LIBNAME)$(LIB) - - OBJS_PRIMITIVES = \ - s_eq128$(OBJ) \ -@@ -381,11 +380,11 @@ $(OBJS_PRIMITIVES) $(OBJS_OTHERS): %$(OBJ): $(SOURCE_DIR)/%.c - $(OBJS_SPECIALIZE): %$(OBJ): $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/%.c - $(COMPILE_C) $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/$*.c - --softfloat$(LIB): $(OBJS_ALL) -+$(LIBNAME)$(LIB): $(OBJS_ALL) - $(DELETE) $@ - $(MAKELIB) $^ - - .PHONY: clean - clean: -- $(DELETE) $(OBJS_ALL) softfloat$(LIB) -+ $(DELETE) $(OBJS_ALL) $(LIBNAME)$(LIB) - -diff --git a/build/template-FAST_INT64/platform.h b/build/template-FAST_INT64/platform.h ---- a/build/template-FAST_INT64/platform.h -+++ b/build/template-FAST_INT64/platform.h -@@ -34,17 +34,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - =============================================================================*/ - --// Edit lines marked with `==>'. See "SoftFloat-source.html". -- - /*---------------------------------------------------------------------------- - *----------------------------------------------------------------------------*/ --==> #define LITTLEENDIAN 1 -+#define LITTLEENDIAN 1 - - /*---------------------------------------------------------------------------- - *----------------------------------------------------------------------------*/ --==> #define INLINE inline -+#define INLINE inline - - /*---------------------------------------------------------------------------- - *----------------------------------------------------------------------------*/ --==> #define THREAD_LOCAL _Thread_local -+#define THREAD_LOCAL - diff --git a/pkg/urbit/compat/poor-mans-nix-shell.sh b/pkg/urbit/compat/poor-mans-nix-shell.sh deleted file mode 100644 index 839a859d7..000000000 --- a/pkg/urbit/compat/poor-mans-nix-shell.sh +++ /dev/null @@ -1,159 +0,0 @@ -declare -a cdirs -declare -a ldirs -declare -a pdirs -declare -A hdeps -sources=(../../nix/sources.json ../../nix/sources-pmnsh.json) -[ "yes" == "${build_openssl-no}" ] && sources=(../../nix/sources-openssl.json ${sources[@]}) -patches=compat/$1 -deriver=urbit-$1-build -markfil=.$1~ -depdirs= -nixpath=${NIX_STORE-../build} - -: ${gnutar:=tar} -: ${gnumake:=make} -: ${sha256tool:=sha256sum} - -export MAKE=$gnumake - -# LDFLAGS doesn't like absolute paths -if [ "${nixpath:0:1}" == "/" ] -then - mkdir -p $nixpath - nixpath=$(realpath --relative-to=. $nixpath) -fi - -hex2nixbase32 () { - local digits='0123456789abcdfghijklmnpqrsvwxyz' - local bits=0 - local left=0 # number of bits left in $bits - local i=0 - while ((1)) - do - while ((left>=5)) - do - echo -n ${digits:$((bits&31)):1} - bits=$((bits>>5)) - left=$((left-5)) - done - if ((i == ${#1})) - then - break - fi - char=0x${1:i:2} - i=$((i+2)) - bits=$((bits|(char<<(left)))) - left=$((left+8)) - done - echo -n ${digits:$bits:1} -} - -buildnixdep () { - echo Building dependency $key... - local cache=https://app.cachix.org/api/v1/cache/${CACHIX_CACHE-} - local hash= - if [ -n "$url" ] - then - hash=${hdeps[$key]} - dir=$nixpath/$hash-$key - if [ -e $dir/$markfil ] - then - # dependency present, don't reupload - hash= - else - # dependency absent, check the binary cache if configured - if [ -n "${CACHIX_CACHE-}" ] - then - echo Checking binary cache for $hash-$key... - narinfo="$cache/${hash}.narinfo" - if curl -fLI "$narinfo" - then - url="$cache/$(curl -fL "$narinfo"|while IFS=: read k v; do if [ "$k" == "URL" ]; then echo $v; fi; done)" - echo Found $url - strip=0 - hash= - fi - fi - mkdir -p $dir - pushd $dir - curl -fL "$url"|($gnutar --strip $strip -xzf - || true) - popd - fi - else - # local dependency - dir=../$key - fi - - # patch and build the dependency if necessary - if [ ! -e $dir/$markfil ] - then - local patch=$patches/$key.patch - [ -e $patch ] && patch -d $dir -p 1 <$patch - pushd $dir - eval "$cmdprep" - eval $gnumake "$cmdmake" - touch $markfil - popd - fi - - # if configured, upload freshly built dependency to binary cache - if [ -n "$hash" -a -n "${CACHIX_AUTH_TOKEN-}" ] - then - ( - echo Uploading freshly built $hash-$key to binary cache... - tar -C $dir -czf $hash.tar . - local size=$(stat -c '%s' $hash.tar) - read filehash _ < <($sha256tool $hash.tar) - curl -fL -H "Content-Type: application/gzip" -H "Authorization: Bearer $CACHIX_AUTH_TOKEN" --data-binary @"$hash.tar" "$cache/nar" - curl -fL -H "Content-Type: application/json" -H "Authorization: Bearer $CACHIX_AUTH_TOKEN" --data-binary @- "$cache/${hash}.narinfo" < - -/* - This is set to the the write-end of a pipe when Urbit is started in - daemon mode. It's meant to be used as a signal to the parent process - that the child process has finished booting. -*/ -static c3_i _child_process_booted_signal_fd = -1; - -/* - This should be called whenever the ship has been booted enough to - handle commands from automation code. Specifically, once the Eyre's - `chis` interface is up and running. - - In daemon mode, this signals to the parent process that it can - exit. Otherwise, it does nothing. - - Once we've sent a signal with `write`, we close the file descriptor - and overwrite the global to make it impossible to accidentally do - this twice. -*/ -static void _on_boot_completed_cb() { - c3_c buf[2] = {0,0}; - - if ( -1 == _child_process_booted_signal_fd ) { - return; - } - - if ( 0 == write(_child_process_booted_signal_fd, buf, 1) ) { - c3_assert(!"_on_boot_completed_cb: Can't write to parent FD"); - } - - close(_child_process_booted_signal_fd); - _child_process_booted_signal_fd = -1; -} - -/* u3_daemon_init(): platform-specific daemon mode initialization. - - We use a pipe to communicate between the child and the parent. The - parent waits for the child to write something to the pipe and - then exits. If the pipe is closed with nothing written to it, get - the exit status from the child process and also exit with that status. - - We want the child to write to the pipe once it's booted, so we put - `_on_boot_completed_cb` into `u3_Host.bot_f`, which is NULL in - non-daemon mode. That gets called once the `chis` service is - available. - - In both processes, we are good fork() citizens, and close all unused - file descriptors. Closing `pipefd[1]` in the parent process is - especially important, since the pipe needs to be closed if the child - process dies. When the pipe is closed, the read fails, and that's - how we know that something went wrong. - - There are some edge cases around `WEXITSTATUS` that are not handled - here, but I don't think it matters. -*/ -void -u3_daemon_init() -{ - c3_i pipefd[2]; - - if ( 0 != pipe(pipefd) ) { - c3_assert(!"Failed to create pipe"); - } - - pid_t childpid = fork(); - - if ( 0 == childpid ) { - close(pipefd[0]); - _child_process_booted_signal_fd = pipefd[1]; - u3_Host.bot_f = _on_boot_completed_cb; - return; - } - - close(pipefd[1]); - close(0); - close(1); - close(2); - - c3_c buf[2] = {0,0}; - if ( 1 == read(pipefd[0], buf, 1) ) { - exit(0); - } - - c3_i status; - wait(&status); - exit(WEXITSTATUS(status)); -} diff --git a/pkg/urbit/compat/posix/ptty.c b/pkg/urbit/compat/posix/ptty.c deleted file mode 100644 index 7c1a17f00..000000000 --- a/pkg/urbit/compat/posix/ptty.c +++ /dev/null @@ -1,192 +0,0 @@ -/* compat/posix/ptty.c -** -*/ -#include "all.h" -#include "vere/vere.h" -#include -#include - -/* u3_ptty: POSIX terminal extension to u3_utty. -*/ -typedef struct { - u3_utty tty_u; // common tty structure - c3_i cug_i; // blocking fcntl flags - c3_i nob_i; // nonblocking fcntl flags - struct termios bak_u; // cooked terminal state - struct termios raw_u; // raw terminal state -} u3_ptty; - -/* _term_tcsetattr(): tcsetattr w/retry on EINTR. -*/ -static c3_i -_term_tcsetattr(c3_i fil_i, c3_i act_i, const struct termios* tms_u) -{ - c3_i ret_i = 0; - c3_w len_w = 0; - - do { - // abort pathological retry loop - // - if ( 100 == ++len_w ) { - fprintf(stderr, "term: tcsetattr loop: %s\r\n", strerror(errno)); - return -1; - } - ret_i = tcsetattr(fil_i, act_i, tms_u); - } while ( (-1 == ret_i) && (EINTR == errno) ); - - return ret_i; -} - -/* _ttyf_start_raw_input(): sets the tty to raw input. -*/ -static c3_o -_ttyf_start_raw_input(u3_utty* uty_u) -{ - u3_ptty* pty_u = (u3_ptty*)uty_u; - if ( 0 != _term_tcsetattr(uty_u->fid_i, TCSADRAIN, &pty_u->raw_u) ) { - return c3n; - } - if ( -1 == fcntl(uty_u->fid_i, F_SETFL, pty_u->nob_i) ) { - c3_assert(!"init-fcntl"); - } - return c3y; -} - -/* _ttyf_start_raw_input(): ends raw input on the tty. -*/ -static c3_o -_ttyf_end_raw_input(u3_utty* uty_u) -{ - u3_ptty* pty_u = (u3_ptty*)uty_u; - if ( 0 != _term_tcsetattr(uty_u->fid_i, TCSADRAIN, &pty_u->bak_u) ) { - return c3n; - } - if ( -1 == fcntl(uty_u->fid_i, F_SETFL, pty_u->cug_i) ) { - c3_assert(!"exit-fcntl"); - } - return c3y; -} - -/* _ttyf_hija(): hijacks the tty for cooked output. -*/ -static c3_o -_ttyf_hija(u3_utty* uty_u) -{ - u3_ptty* pty_u = (u3_ptty*)uty_u; - if ( 0 != _term_tcsetattr(1, TCSADRAIN, &pty_u->bak_u) ) { - perror("hija-tcsetattr-1"); - c3_assert(!"hija-tcsetattr"); - } - if ( -1 == fcntl(1, F_SETFL, pty_u->cug_i) ) { - perror("hija-fcntl-1"); - c3_assert(!"hija-fcntl"); - } - if ( 0 != _term_tcsetattr(0, TCSADRAIN, &pty_u->bak_u) ) { - perror("hija-tcsetattr-0"); - c3_assert(!"hija-tcsetattr"); - } - if ( -1 == fcntl(0, F_SETFL, pty_u->cug_i) ) { - perror("hija-fcntl-0"); - c3_assert(!"hija-fcntl"); - } - return c3y; -} - -/* _ttyf_loja(): releases the tty from cooked output. -*/ -static c3_o -_ttyf_loja(u3_utty* uty_u) -{ - u3_ptty* pty_u = (u3_ptty*)uty_u; - if ( 0 != _term_tcsetattr(1, TCSADRAIN, &pty_u->raw_u) ) { - perror("loja-tcsetattr-1"); - c3_assert(!"loja-tcsetattr"); - } - if ( -1 == fcntl(1, F_SETFL, pty_u->nob_i) ) { - perror("hija-fcntl-1"); - c3_assert(!"loja-fcntl"); - } - if ( 0 != _term_tcsetattr(0, TCSADRAIN, &pty_u->raw_u) ) { - perror("loja-tcsetattr-0"); - c3_assert(!"loja-tcsetattr"); - } - if ( -1 == fcntl(0, F_SETFL, pty_u->nob_i) ) { - perror("hija-fcntl-0"); - c3_assert(!"loja-fcntl"); - } - return c3y; -} - -/* _ttyf_get_winsize(): gets the tty window size. -*/ -static c3_o -_ttyf_get_winsize(u3_utty* uty_u, c3_l* col_l, c3_l* row_l) -{ - struct winsize siz_u; - if ( 0 == ioctl(uty_u->fid_i, TIOCGWINSZ, &siz_u) ) - { - *col_l = siz_u.ws_col; - *row_l = siz_u.ws_row; - return c3y; - } else { - return c3n; - } -} - -/* u3_ptty_init(): initialize platform-specific tty. -*/ -u3_utty* -u3_ptty_init(uv_loop_t* lup_u, const c3_c** err_c) -{ - u3_ptty* pty_u = c3_calloc(sizeof(u3_ptty)); - u3_utty* uty_u = &pty_u->tty_u; - - if ( !isatty(0) || !isatty(1) ) { - *err_c = "not a tty"; - c3_free(pty_u); - return NULL; - } - - uv_pipe_init(lup_u, &uty_u->pin_u.pip_u, 0); - uv_pipe_init(lup_u, &uty_u->pop_u.pip_u, 0); - uv_pipe_open(&uty_u->pin_u.pip_u, 0); - uv_pipe_open(&uty_u->pop_u.pip_u, 1); - - // Load old terminal state to restore. - // - { - if ( 0 != tcgetattr(uty_u->fid_i, &pty_u->bak_u) ) { - c3_assert(!"init-tcgetattr"); - } - if ( -1 == fcntl(uty_u->fid_i, F_GETFL, &pty_u->cug_i) ) { - c3_assert(!"init-fcntl"); - } - pty_u->cug_i &= ~O_NONBLOCK; // could fix? - pty_u->nob_i = pty_u->cug_i | O_NONBLOCK; // O_NDELAY on older unix - } - - // Construct raw termios configuration. - // - // makes input available per-character, does not echo input, - // disables special input pre-processing, output post-processing. - // - { - pty_u->raw_u = pty_u->bak_u; - - pty_u->raw_u.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN); - pty_u->raw_u.c_iflag &= ~(ICRNL | INPCK | ISTRIP); - pty_u->raw_u.c_cflag &= ~(CSIZE | PARENB); - pty_u->raw_u.c_cflag |= CS8; - pty_u->raw_u.c_oflag &= ~(OPOST); - pty_u->raw_u.c_cc[VMIN] = 0; - pty_u->raw_u.c_cc[VTIME] = 0; - } - - uty_u->fid_i = 1; - uty_u->sta_f = _ttyf_start_raw_input; - uty_u->sto_f = _ttyf_end_raw_input; - uty_u->hij_f = _ttyf_hija; - uty_u->loj_f = _ttyf_loja; - uty_u->wsz_f = _ttyf_get_winsize; - return uty_u; -} diff --git a/pkg/urbit/compat/posix/rsignal.h b/pkg/urbit/compat/posix/rsignal.h deleted file mode 100644 index 276006a18..000000000 --- a/pkg/urbit/compat/posix/rsignal.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _RSIGNAL_H -#define _RSIGNAL_H - -#define rsignal_jmpbuf sigjmp_buf -#define rsignal_setjmp(buf) sigsetjmp((buf), 1) -#define rsignal_longjmp siglongjmp -#define rsignal_install_handler signal -#define rsignal_deinstall_handler(sig) signal((sig), SIG_IGN) -#define rsignal_setitimer setitimer - -#endif//_RSIGNAL_H diff --git a/pkg/urbit/configure b/pkg/urbit/configure deleted file mode 100755 index acea03a86..000000000 --- a/pkg/urbit/configure +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -URBIT_VERSION="$(cat ./version)" - -# we require pkg-config metadata to statically link these -# -pkgc_deps=" \ - libcurl \ - libh2o \ - liburcrypt-0 \ - libuv \ - openssl \ -" - -deps=" \ - ent \ - gmp \ - lmdb \ - murmur3 \ - pthread \ - sigsegv \ - softfloat3 \ -" - -echo '#pragma once' >include/config.h - -defmacro () { - echo "#define $1 $2" >>include/config.h -} - -defmacro URBIT_VERSION "\"$URBIT_VERSION\"" -defmacro U3_VERE_PACE "\"${VERE_PACE:-once}\"" - -opt_debug= -opt_static= - -while test $# != 0 -do - case $1 in - --enable-debug) - opt_debug=1 - ;; - --disable-debug) - opt_debug= - ;; - --enable-static) - opt_static=1 - ;; - --enable-shared) - opt_static= - ;; - --disable-static) - opt_static= - ;; - --disable-shared) - opt_static=1 - ;; - *) - echo "unrecognized option: $1" - ;; - esac - shift -done - -[ -z "${NO_GUARD_PAGE-}" ] && defmacro U3_GUARD_PAGE 1 -[ -n "${MEMORY_DEBUG-}" ] && defmacro U3_MEMORY_DEBUG 1 -[ -n "${MEMORY_LOG-}" ] && defmacro U3_MEMORY_LOG 1 -[ -n "${CPU_DEBUG-}" ] && defmacro U3_CPU_DEBUG 1 -[ -n "${EVENT_TIME_DEBUG-}" ] && defmacro U3_EVENT_TIME_DEBUG 1 - -if [ -n "${HOST-}" ] -then os=$(sed 's$^[^-]*-\([^-]*\)-.*$\1$' <<< "$HOST") - cpu=$(sed 's$-.*$$' <<< ${HOST}) -else os=$(uname -s) - cpu=$(uname -m) -fi - -case $(tr A-Z a-z <<< $cpu) in - unknown) - defmacro U3_OS_ENDIAN_little 1 - ;; - i386) - defmacro U3_OS_ENDIAN_little 1 - ;; - i686) - defmacro U3_OS_ENDIAN_little 1 - ;; - x86_64 | amd64) - defmacro U3_OS_ENDIAN_little 1 - ;; - arm64|aarch64) - defmacro U3_OS_ENDIAN_little 1 - defmacro U3_CPU_aarch64 1 - ;; - *) - echo "Unknown or unsupported CPU: '$cpu'" >&2 - exit 1 - ;; -esac - -# TODO Determine if the target cpu is little or big endian. -case $(tr A-Z a-z <<< $os) in - *mingw*) - # mingw builds are static-only - # - opt_static=1 - - # ensure required mingw packages are installed - mpkgs=(cmake curl gcc jq make) - pacman -S --needed autoconf automake-wrapper libtool patch ${mpkgs[@]/#/mingw-w64-x86_64-} - - gnumake=mingw32-make - - . compat/poor-mans-nix-shell.sh mingw - compat/create-include-files.sh 'stat -c %s' /etc/pki/ca-trust/extracted/openssl/ca-bundle.trust.crt - - defmacro U3_OS_mingw 1 - - deps="${deps/sigsegv}" - compat="${compat-} mingw" - ;; - m1brew) - # ensure required packages are installed - brew install -q autoconf automake bash cmake coreutils gmp jq libsigsegv libtool libuv openssl pkgconfig - - if (( ${BASH_VERSION%%.*} < 5 )) - then - echo Running bash version $BASH_VERSION is too low, please restart bash to use freshly installed one - exit 1 - fi - - # for some reason pkg-config does not pick up openssl - export PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig:${PKG_CONFIG_PATH-}" - - . compat/poor-mans-nix-shell.sh m1brew - compat/create-include-files.sh 'stat -f %z' /etc/ssl/cert.pem - - defmacro U3_OS_osx 1 - - compat="${compat-} posix m1brew" - ;; - *linux*) - defmacro U3_OS_linux 1 - defmacro U3_OS_PROF 1 - ;; - *darwin*) - defmacro U3_OS_osx 1 - defmacro U3_OS_PROF 1 - ;; - *apple*) - defmacro U3_OS_osx 1 - defmacro U3_OS_PROF 1 - ;; - *freebsd*) - defmacro U3_OS_bsd 1 - deps="$deps kvm" # XX use new compat.mk pattern - ;; - *openbsd*) - # pkg_add bash automake libtool jq gtar cmake gmake libsigsegv gmp - # Tested versions: - # bash-5.1.8 automake-1.16.3 (autoconf-2.69p3) libtool-2.4.2p2 - # jq-1.6p0 gtar-1.34-static cmake-3.20.3p0v0 gmake-4.3 libsigsegv-2.12 - # gmp-6.2.1p0 - - gnutar=gtar - gnumake=gmake - sha256tool=sha256 - build_openssl=yes - export AUTOCONF_VERSION="${AUTOCONF_VERSION-2.69}" - export AUTOMAKE_VERSION="${AUTOMAKE_VERSION-1.16}" - . compat/poor-mans-nix-shell.sh openbsd - compat/create-include-files.sh 'stat -f %z' /etc/ssl/cert.pem - - defmacro U3_OS_bsd 1 - defmacro U3_OS_no_ubc 1 - - export PKG_CONFIG_PATH="${PKG_CONFIG_PATH-}" - deps="$deps aes_siv secp256k1" - - compat="${compat-} posix openbsd" - ;; - *) - echo "Unknown or unsupported OS: '$os'" >&2 - exit 1 - ;; -esac - -PKG_CONFIG="${PKG_CONFIG-pkg-config}" - -if [ -n "${opt_static-}" ] -then - CFLAGS="${CFLAGS-} -static" - # XX can't set -static here due libuv's -ldl on MacOS - # - # LDFLAGS="${LDFLAGS-} -static" - PKG_CONFIG="$PKG_CONFIG --static" -fi - -CFLAGS="${CFLAGS-} $($PKG_CONFIG --cflags $pkgc_deps)" -LDFLAGS="${LDFLAGS-} $($PKG_CONFIG --libs $pkgc_deps)" - -for dep in $deps; do - LDFLAGS="${LDFLAGS-} -l$dep" -done - -compat="${compat-posix}" -for citem in $compat; do - CFLAGS="${CFLAGS-} -Icompat/$citem" -done - -cat >config.mk <&2 -cat config.mk >&2 - -echo == include/config.h == >&2 -cat include/config.h >&2 diff --git a/pkg/urbit/daemon/main.c b/pkg/urbit/daemon/main.c deleted file mode 100644 index 491485f6d..000000000 --- a/pkg/urbit/daemon/main.c +++ /dev/null @@ -1,2283 +0,0 @@ -/* vere/main.c -** -*/ -#define U3_GLOBAL -#define C3_GLOBAL -#include "all.h" -#include "vere/ivory.h" -#include "ur/ur.h" -#include "rsignal.h" -#include -#include "vere/vere.h" -#if !defined(U3_OS_mingw) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ca-bundle.h" -#include "whereami.h" - -// serf module state -// -static u3_serf u3V; // one serf per process -static u3_moat inn_u; // input stream -static u3_mojo out_u; // output stream -static u3_cue_xeno* sil_u; // cue handle - -#undef SERF_TRACE_JAM -#undef SERF_TRACE_CUE - -/* Require unsigned char - */ -STATIC_ASSERT(( 0 == CHAR_MIN && UCHAR_MAX == CHAR_MAX ), - "unsigned char required"); - -/* _main_self_path(): get binary self-path. -*/ -static void -_main_self_path(void) -{ - c3_c* pat_c; - c3_i len_i, pat_i; - - if ( 0 < (len_i = wai_getExecutablePath(NULL, 0, &pat_i)) ) { - pat_c = c3_malloc( 1 + len_i ); - wai_getExecutablePath(pat_c, len_i, &pat_i); - pat_c[len_i] = 0; - - u3_Host.dem_c = pat_c; - } - else { - fprintf(stderr, "unable to get binary self path\r\n"); - exit(1); - - // XX continue? - // - // u3_Host.dem_c = strdup(bin_c); - } -} - -/* _main_readw(): parse a word from a string. -*/ -static u3_noun -_main_readw(const c3_c* str_c, c3_w max_w, c3_w* out_w) -{ - c3_c* end_c; - c3_w par_w = strtoul(str_c, &end_c, 0); - - if ( *str_c != '\0' && *end_c == '\0' && par_w < max_w ) { - *out_w = par_w; - return c3y; - } - else return c3n; -} - -/* _main_presig(): prefix optional sig. -*/ -c3_c* -_main_presig(c3_c* txt_c) -{ - c3_c* new_c = c3_malloc(2 + strlen(txt_c)); - - if ( '~' == *txt_c ) { - strcpy(new_c, txt_c); - } else { - new_c[0] = '~'; - strcpy(new_c + 1, txt_c); - } - return new_c; -} - -/* _main_repath(): canonicalize path, using dirname if needed. -*/ -c3_c* -_main_repath(c3_c* pax_c) -{ - c3_c* rel_c; - c3_c* fas_c; - c3_c* dir_c; - c3_w len_w; - c3_i wit_i; - - c3_assert(pax_c); - if ( 0 != (rel_c = realpath(pax_c, 0)) ) { - return rel_c; - } - fas_c = strrchr(pax_c, '/'); - if ( !fas_c ) { - c3_c rec_c[2048]; - - wit_i = snprintf(rec_c, sizeof(rec_c), "./%s", pax_c); - c3_assert(sizeof(rec_c) > wit_i); - return _main_repath(rec_c); - } - c3_assert(u3_unix_cane(fas_c + 1)); - *fas_c = 0; - dir_c = realpath(pax_c, 0); - *fas_c = '/'; - if ( 0 == dir_c ) { - return 0; - } - len_w = strlen(dir_c) + strlen(fas_c) + 1; - rel_c = c3_malloc(len_w); - wit_i = snprintf(rel_c, len_w, "%s%s", dir_c, fas_c); - c3_assert(len_w == wit_i + 1); - c3_free(dir_c); - return rel_c; -} - -/* _main_init(): initialize globals -*/ -static void -_main_init(void) -{ - u3_Host.nex_o = c3n; - u3_Host.pep_o = c3n; - - u3_Host.ops_u.abo = c3n; - u3_Host.ops_u.dem = c3n; - u3_Host.ops_u.dry = c3n; - u3_Host.ops_u.gab = c3n; - u3_Host.ops_u.git = c3n; - - // always disable hashboard - // XX temporary, remove once hashes are added - // - u3_Host.ops_u.has = c3y; - - u3_Host.ops_u.net = c3y; - u3_Host.ops_u.lit = c3n; - u3_Host.ops_u.nuu = c3n; - u3_Host.ops_u.pro = c3n; - u3_Host.ops_u.qui = c3n; - u3_Host.ops_u.rep = c3n; - u3_Host.ops_u.tem = c3n; - u3_Host.ops_u.tex = c3n; - u3_Host.ops_u.tra = c3n; - u3_Host.ops_u.veb = c3n; - u3_Host.ops_u.puf_c = "jam"; - u3_Host.ops_u.hap_w = 50000; - u3_Host.ops_u.kno_w = DefaultKernel; - - u3_Host.ops_u.lut_y = u3a_bits + 1; - u3_Host.ops_u.lom_y = u3a_bits + 1; -} - -/* _main_pier_run(): get pier from binary path (argv[0]), if appropriate -*/ -static c3_c* -_main_pier_run(c3_c* bin_c) -{ - c3_c* dir_c = 0; - c3_w bin_w = strlen(bin_c); - c3_w len_w = strlen(U3_BIN_ALIAS); - - // no args, argv[0] == $pier/.run - // - if ( (len_w <= bin_w) - && (0 == strcmp(bin_c + (bin_w - len_w), U3_BIN_ALIAS)) ) - { - bin_c = strdup(bin_c); // dirname can modify - dir_c = _main_repath(dirname(bin_c)); - c3_free(bin_c); - } - - return dir_c; -} - -/* _main_getopt(): extract option map from command line. -*/ -static u3_noun -_main_getopt(c3_i argc, c3_c** argv) -{ - c3_i ch_i, lid_i; - c3_w arg_w; - - static struct option lop_u[] = { - { "arvo", required_argument, NULL, 'A' }, - { "abort", no_argument, NULL, 'a' }, - { "bootstrap", required_argument, NULL, 'B' }, - { "http-ip", required_argument, NULL, 'b' }, - { "memo-cache-limit", required_argument, NULL, 'C' }, - { "pier", required_argument, NULL, 'c' }, - { "replay", no_argument, NULL, 'D' }, - { "daemon", no_argument, NULL, 'd' }, - { "ethereum", required_argument, NULL, 'e' }, - { "fake", required_argument, NULL, 'F' }, - { "key-string", required_argument, NULL, 'G' }, - { "gc", no_argument, NULL, 'g' }, - { "dns-root", required_argument, NULL, 'H' }, - { "inject", required_argument, NULL, 'I' }, - { "import", required_argument, NULL, 'i' }, - { "ivory-pill", required_argument, NULL, 'J' }, - { "json-trace", no_argument, NULL, 'j' }, - { "kernel-stage", required_argument, NULL, 'K' }, - { "key-file", required_argument, NULL, 'k' }, - { "loom", required_argument, NULL, c3__loom }, - { "local", no_argument, NULL, 'L' }, - { "lite-boot", no_argument, NULL, 'l' }, - { "replay-to", required_argument, NULL, 'n' }, - { "profile", no_argument, NULL, 'P' }, - { "ames-port", required_argument, NULL, 'p' }, - { "http-port", required_argument, NULL, c3__http }, - { "https-port", required_argument, NULL, c3__htls }, - { "no-conn", no_argument, NULL, c3__noco }, - { "no-dock", no_argument, NULL, c3__nodo }, - { "quiet", no_argument, NULL, 'q' }, - { "versions", no_argument, NULL, 'R' }, - { "replay-from", required_argument, NULL, 'r' }, - { "skip-battery-hashes", no_argument, NULL, 'S' }, - { "autoselect-pill", no_argument, NULL, 's' }, - { "no-tty", no_argument, NULL, 't' }, - { "bootstrap-url", required_argument, NULL, 'u' }, - { "verbose", no_argument, NULL, 'v' }, - { "name", required_argument, NULL, 'w' }, - { "scry", required_argument, NULL, 'X' }, - { "exit", no_argument, NULL, 'x' }, - { "scry-into", required_argument, NULL, 'Y' }, - { "scry-format", required_argument, NULL, 'Z' }, - // - { "urth-loom", required_argument, NULL, 5 }, - // - { NULL, 0, NULL, 0 }, - }; - - while ( -1 != (ch_i=getopt_long(argc, argv, - "A:B:C:DF:G:H:I:J:K:LPRSX:Y:Z:ab:cde:gi:jk:ln:p:qr:stu:vw:x", - lop_u, &lid_i)) ) - { - switch ( ch_i ) { - case 5: { // urth-loom - c3_w lut_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lut_w); - if ( (c3n == res_o) || (lut_w < 20) ) { - fprintf(stderr, "error: --urth-loom must be >= 20 and <= %u\r\n", u3a_bits + 2); - return c3n; - } - - u3_Host.ops_u.lut_y = lut_w; - break; - } - case 'X': { - u3_Host.ops_u.pek_c = strdup(optarg); - break; - } - case 'Y': { - u3_Host.ops_u.puk_c = strdup(optarg); - break; - } - case 'Z': { - u3_Host.ops_u.puf_c = strdup(optarg); - break; - } - case 'J': { - u3_Host.ops_u.lit_c = _main_repath(optarg); - break; - } - case 'B': { - u3_Host.ops_u.pil_c = _main_repath(optarg); - break; - } - case 'b': { - u3_Host.ops_u.bin_c = strdup(optarg); - break; - } - case 'G': { - u3_Host.ops_u.gen_c = strdup(optarg); - break; - } - case 'A': { - u3_Host.ops_u.arv_c = _main_repath(optarg); - break; - } - case 'H': { - u3_Host.ops_u.dns_c = strdup(optarg); - break; - } - case 'I': { - u3_Host.ops_u.jin_c = _main_repath(optarg); - break; - } - case 'C': { - if ( c3n == _main_readw(optarg, 1000000000, &u3_Host.ops_u.hap_w) ) { - return c3n; - } - break; - } - case 'e': { - u3_Host.ops_u.eth_c = strdup(optarg); - break; - } - case 'F': { - u3_Host.ops_u.fak_c = _main_presig(optarg); - u3_Host.ops_u.net = c3n; - break; - } - case 'w': { - u3_Host.ops_u.who_c = _main_presig(optarg); - u3_Host.ops_u.nuu = c3y; - break; - } - case 'u': { - u3_Host.ops_u.url_c = strdup(optarg); - break; - } - case 'x': { - u3_Host.ops_u.tex = c3y; - break; - } - case 'K': { - if ( c3n == _main_readw(optarg, 256, &u3_Host.ops_u.kno_w) ) { - return c3n; - } - break; - } - case 'k': { - u3_Host.ops_u.key_c = _main_repath(optarg); - break; - } - case 'n': { - u3_Host.ops_u.til_c = strdup(optarg); - break; - } - case 'p': { - if ( c3n == _main_readw(optarg, 65536, &arg_w) ) { - return c3n; - } else u3_Host.ops_u.por_s = arg_w; - break; - } - case c3__http: { - if ( c3n == _main_readw(optarg, 65536, &arg_w) ) { - return c3n; - } else u3_Host.ops_u.per_s = arg_w; - break; - } - case c3__htls: { - if ( c3n == _main_readw(optarg, 65536, &arg_w) ) { - return c3n; - } else u3_Host.ops_u.pes_s = arg_w; - break; - } - case c3__loom: { - c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); - if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); - return c3n; - } - u3_Host.ops_u.lom_y = lom_w; - break; - } - case c3__noco: { - u3_Host.ops_u.con = c3n; - break; - } - case c3__nodo: { - u3_Host.ops_u.doc = c3n; - break; - } - case 'R': { - u3_Host.ops_u.rep = c3y; - return c3y; - } - case 'r': { - u3_Host.ops_u.roc_c = strdup(optarg); - break; - } - case 'i': { - u3_Host.ops_u.imp_c = _main_repath(optarg); - break; - } - case 'L': { u3_Host.ops_u.net = c3n; break; } - case 'l': { u3_Host.ops_u.lit = c3y; break; } - case 'j': { u3_Host.ops_u.tra = c3y; break; } - case 'a': { u3_Host.ops_u.abo = c3y; break; } - case 'c': { u3_Host.ops_u.nuu = c3y; break; } - case 'd': { u3_Host.ops_u.dem = c3y; break; } - case 'g': { u3_Host.ops_u.gab = c3y; break; } - case 'P': { u3_Host.ops_u.pro = c3y; break; } - case 'D': { u3_Host.ops_u.dry = c3y; break; } - case 'q': { u3_Host.ops_u.qui = c3y; break; } - case 'v': { u3_Host.ops_u.veb = c3y; break; } - case 's': { u3_Host.ops_u.git = c3y; break; } - case 'S': { u3_Host.ops_u.has = c3y; break; } - case 't': { u3_Host.ops_u.tem = c3y; break; } - case '?': default: { - return c3n; - } - } - } - -#if !defined(U3_OS_PROF) - if (u3_Host.ops_u.pro == c3y) { - fprintf(stderr, "profiling isn't yet supported on your OS\r\n"); - return c3n; - } -#endif - - if ( 0 != u3_Host.ops_u.fak_c ) { - if ( 28 < strlen(u3_Host.ops_u.fak_c) ) { - fprintf(stderr, "fake comets are disallowed\r\n"); - return c3n; - } - - u3_Host.ops_u.who_c = strdup(u3_Host.ops_u.fak_c); - u3_Host.ops_u.has = c3y; /* no battery hashing on fake ships. */ - u3_Host.ops_u.net = c3n; /* no networking on fake ships. */ - u3_Host.ops_u.nuu = c3y; - } - - if ( argc != (optind + 1) ) { - if ( u3_Host.ops_u.who_c != 0 ) { - u3_Host.dir_c = strdup(1 + u3_Host.ops_u.who_c); - } - // no trailing positional arg, argv[0] != $pier/.run, invalid command - // - else if ( !(u3_Host.dir_c = _main_pier_run(argv[0])) ) { - return c3n; - } - } - else { - { - c3_c* ash_c; - - if ( (ash_c = strrchr(argv[optind], '/')) && (ash_c[1] == 0) ) { - *ash_c = 0; - } - } - - u3_Host.dir_c = _main_repath(argv[optind]); - } - - // daemon mode (-d) implies disabling terminal assumptions (-t) - // - if ( c3y == u3_Host.ops_u.dem ) { - u3_Host.ops_u.tem = c3y; - } - - // make -c optional, catch invalid boot of existing pier - // - { - struct stat s; - if ( 0 != stat(u3_Host.dir_c, &s) ) { - if ( c3n == u3_Host.ops_u.nuu ) { - u3_Host.ops_u.nuu = c3y; - } - } - else if ( c3y == u3_Host.ops_u.nuu ) { - fprintf(stderr, "tried to create, but %s already exists\n", u3_Host.dir_c); - fprintf(stderr, "normal usage: %s %s\n", argv[0], u3_Host.dir_c); - exit(1); - } - else if ( 0 != access(u3_Host.dir_c, W_OK) ) { - fprintf(stderr, "urbit: write permissions are required for %s\n", u3_Host.dir_c); - exit(1); - } - } - - if ( u3_Host.ops_u.gen_c != 0 && u3_Host.ops_u.nuu == c3n ) { - fprintf(stderr, "-G only makes sense when bootstrapping a new instance\n"); - return c3n; - } - - if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.who_c != 0) { - fprintf(stderr, "-w only makes sense when creating a new ship\n"); - return c3n; - } - - if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.pil_c != 0) { - fprintf(stderr, "-B only makes sense when creating a new ship\n"); - return c3n; - } - - struct sockaddr_in t; - if ( u3_Host.ops_u.bin_c != 0 && inet_pton(AF_INET, u3_Host.ops_u.bin_c, &t.sin_addr) == 0 ) { - fprintf(stderr, "-b invalid IP address\n"); - return c3n; - } - - if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.dns_c != 0) { - fprintf(stderr, "-H only makes sense when bootstrapping a new instance\n"); - return c3n; - } - - if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.pil_c != 0) { - fprintf(stderr, "-B only makes sense when bootstrapping a new instance\n"); - return c3n; - } - - if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.key_c != 0) { - fprintf(stderr, "-k only makes sense when bootstrapping a new instance\n"); - return c3n; - } - - if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.url_c != 0 ) { - fprintf(stderr, "-u only makes sense when bootstrapping a new instance\n"); - return c3n; - } - - if ( u3_Host.ops_u.url_c != 0 && u3_Host.ops_u.pil_c != 0 ) { - fprintf(stderr, "-B and -u cannot be used together\n"); - return c3n; - } - else if ( u3_Host.ops_u.nuu == c3y - && u3_Host.ops_u.url_c == 0 - && u3_Host.ops_u.git == c3n ) { - u3_Host.ops_u.url_c = - "https://bootstrap.urbit.org/urbit-v" URBIT_VERSION ".pill"; - } - else if ( u3_Host.ops_u.nuu == c3y - && u3_Host.ops_u.url_c == 0 - && u3_Host.ops_u.arv_c == 0 ) { - - fprintf(stderr, "-s only makes sense with -A\n"); - return c3n; - } - - if ( u3_Host.ops_u.pil_c != 0 ) { - struct stat s; - if ( stat(u3_Host.ops_u.pil_c, &s) != 0 ) { - fprintf(stderr, "pill %s not found\n", u3_Host.ops_u.pil_c); - return c3n; - } - } - - if ( u3_Host.ops_u.key_c != 0 ) { - struct stat s; - if ( stat(u3_Host.ops_u.key_c, &s) != 0 ) { - fprintf(stderr, "keyfile %s not found\n", u3_Host.ops_u.key_c); - return c3n; - } - } - - return c3y; -} - -/* _cert_store: decoded CA certificates - */ -static STACK_OF(X509_INFO)* _cert_store; - -/* _setup_cert_store(): decodes embedded CA certificates - */ -static void -_setup_cert_store() -{ - BIO* cbio = BIO_new_mem_buf(include_ca_bundle_crt, include_ca_bundle_crt_len); - if ( !cbio || !(_cert_store = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL)) ) { - u3l_log("boot: failed to decode embedded CA certificates"); - exit(1); - } - - BIO_free(cbio); -} - -/* _setup_ssl_x509(): adds embedded CA certificates to a X509_STORE - */ -static void -_setup_ssl_x509(void* arg) -{ - X509_STORE* cts = arg; - int i; - for ( i = 0; i < sk_X509_INFO_num(_cert_store); i++ ) { - X509_INFO *itmp = sk_X509_INFO_value(_cert_store, i); - if(itmp->x509) { - X509_STORE_add_cert(cts, itmp->x509); - } - if(itmp->crl) { - X509_STORE_add_crl(cts, itmp->crl); - } - } -} - -/* _curl_ssl_ctx_cb(): curl SSL context callback - */ -static CURLcode -_curl_ssl_ctx_cb(CURL* curl, SSL_CTX* sslctx, void* param) -{ - X509_STORE* cts = SSL_CTX_get_cert_store(sslctx); - if (!cts || !_cert_store) - return CURLE_ABORTED_BY_CALLBACK; - - _setup_ssl_x509(cts); - return CURLE_OK; -} - -/* _setup_ssl_curl(): adds embedded CA certificates to a curl context - */ -static void -_setup_ssl_curl(void* arg) -{ - CURL* curl = arg; - curl_easy_setopt(curl, CURLOPT_CAINFO, NULL); - curl_easy_setopt(curl, CURLOPT_CAPATH, NULL); - curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, _curl_ssl_ctx_cb); -} - -/* _cw_usage(): print utility usage. -*/ -static void -_cw_usage(c3_c* bin_c) -{ - c3_c *use_c[] = { - "utilities:\n", - " %s cram %.*s jam state:\n", - " %s dock %.*s copy binary:\n", - " %s grab %.*s measure memory usage:\n", - " %s info %.*s print pier info:\n", - " %s meld %.*s deduplicate snapshot:\n", - " %s pack %.*s defragment snapshot:\n", - " %s prep %.*s prepare for upgrade:\n", - " %s next %.*s request upgrade:\n", - " %s queu %.*s cue state:\n", - " %s vere ARGS download binary:\n", - "\n run as a 'serf':\n", - " %s serf " -#ifdef U3_OS_mingw - " " -#endif - "\n", - 0 - }; - - c3_c* d = _main_pier_run(bin_c); - c3_i i; - - for ( i=0; use_c[i]; i++ ) { - fprintf(stderr, use_c[i], bin_c, d ? 0 : 7, " "); - } - - c3_free(d); -} - -/* u3_ve_usage(): print usage and exit. -*/ -static void -u3_ve_usage(c3_i argc, c3_c** argv) -{ - c3_c *use_c[] = { - "Urbit: a personal server operating function\n", - "https://urbit.org\n", - "Version " URBIT_VERSION "\n", - "\n", - "Usage: %s [options...] ship_name\n", - "where ship_name is a @p phonetic representation of an urbit address\n", - "without the leading '~', and options is some subset of the following:\n", - "\n", - "-A, --arvo DIR Use dir for initial clay sync\n", - "-a, --abort Abort aggressively\n", - "-B, --bootstrap PILL Bootstrap from this pill\n", - "-b, --http-ip IP Bind HTTP server to this IP address\n", - "-C, --memo-cache-limit LIMIT Set memo cache max size; 0 means uncapped\n", - "-c, --pier PIER Create a new urbit in pier/\n", - "-D, --replay Recompute from events\n", - "-d, --daemon Daemon mode; implies -t\n", - "-e, --ethereum URL Ethereum gateway\n", - "-F, --fake SHIP Fake keys; also disables networking\n", - "-G, --key-string STRING Private key string (@uw, see also -k)\n" - "-g, --gc Set GC flag\n", - "-I, --inject FILE Inject event from jamfile\n", - "-i, --import FILE Import pier state from jamfile\n", - "-J, --ivory-pill PILL Use custom ivory pill\n", - "-j, --json-trace Create json trace file in .urb/put/trace\n", - "-K, --kernel-stage STAGE Start at Hoon kernel version stage\n", - "-k, --key-file KEYS Private key file (see also -G)\n", - "-L, --local Local networking only\n", - " --loom Set loom to binary exponent (31 == 2GB)\n" - "-l, --lite-boot Most-minimal startup\n", - "-n, --replay-to NUMBER Replay up to event\n", - "-P, --profile Profiling\n", - "-p, --ames-port PORT Set the ames port to bind to\n", - " --http-port PORT Set the http port to bind to\n", - " --https-port PORT Set the https port to bind to\n", - "-q, --quiet Quiet\n", - "-R, --versions Report urbit build info\n", - "-r, --replay-from NUMBER Load snapshot from event\n", - "-S, --skip-battery-hashes Disable battery hashing\n", - // XX find a way to re-enable - // "-s, --autoselect-pill Pill URL from arvo git hash\n", - "-t, --no-tty Disable terminal/tty assumptions\n", - "-u, --bootstrap-url URL URL from which to download pill\n", - "-v, --verbose Verbose\n", - "-w, --name NAME Boot as ~name\n", - "-X, --scry PATH Scry, write to file, then exit\n", - "-x, --exit Exit immediately\n", - "-Y, --scry-into FILE Optional name of file (for -X)\n", - "-Z, --scry-format FORMAT Optional file format ('jam', or aura, for -X)\n", - " --no-conn Do not run control plane\n", - " --no-dock Skip binary \"docking\" on boot\n", - "\n", - "Development Usage:\n", - " To create a development ship, use a fakezod:\n", - " %s -F zod -A /path/to/arvo/folder -B /path/to/pill -c zod\n", - "\n", - " For more information about developing on urbit, see:\n", - " https://github.com/urbit/urbit/blob/master/CONTRIBUTING.md\n", - "\n", - "Simple Usage: \n", - " %s -c to create a comet (anonymous urbit)\n", - " %s -w -k if you own a planet\n", - " %s to restart an existing urbit\n", - 0 - }; - - c3_i i; - for ( i=0; use_c[i]; i++ ) { - fprintf(stderr, use_c[i], argv[0]); - } - _cw_usage(argv[0]); - exit(1); -} - -#if 0 -/* u3_ve_panic(): panic and exit. -*/ -static void -u3_ve_panic(c3_i argc, c3_c** argv) -{ - fprintf(stderr, "%s: gross system failure\n", argv[0]); - exit(1); -} -#endif - -/* u3_ve_sysopt(): apply option map to system state. -*/ -static void -u3_ve_sysopt() -{ - u3_Local = strdup(u3_Host.dir_c); -} - -static void -report(void) -{ - printf("urbit %s\n", URBIT_VERSION); - printf("gmp: %s\n", gmp_version); -#if !defined(U3_OS_mingw) - printf("sigsegv: %d.%d\n", - (libsigsegv_version >> 8) & 0xff, - libsigsegv_version & 0xff); -#endif - printf("openssl: %s\n", SSLeay_version(SSLEAY_VERSION)); - printf("libuv: %s\n", uv_version_string()); - printf("libh2o: %d.%d.%d\n", - H2O_LIBRARY_VERSION_MAJOR, - H2O_LIBRARY_VERSION_MINOR, - H2O_LIBRARY_VERSION_PATCH); - printf("lmdb: %d.%d.%d\n", - MDB_VERSION_MAJOR, - MDB_VERSION_MINOR, - MDB_VERSION_PATCH); - printf("curl: %d.%d.%d\n", - LIBCURL_VERSION_MAJOR, - LIBCURL_VERSION_MINOR, - LIBCURL_VERSION_PATCH); -} - -/* _stop_exit(): exit immediately. -*/ -static void -_stop_exit(c3_i int_i) -{ - // explicit fprintf to avoid allocation in u3l_log - // - fprintf(stderr, "\r\n[received keyboard stop signal, exiting]\r\n"); - u3_king_bail(); -} - -/* _stop_on_boot_completed_cb(): exit gracefully after boot is complete -*/ -static void -_stop_on_boot_completed_cb() -{ - u3_king_exit(); -} - -/* _cw_serf_fail(): failure stub. -*/ -static void -_cw_serf_fail(void* ptr_v, ssize_t err_i, const c3_c* err_c) -{ - if ( UV_EOF == err_i ) { - fprintf(stderr, "serf: pier unexpectedly shut down\r\n"); - } - else { - fprintf(stderr, "serf: pier error: %s\r\n", err_c); - } - - exit(1); -} - -/* _cw_serf_send(): send plea back to daemon. -*/ -static void -_cw_serf_send(u3_noun pel) -{ - c3_d len_d; - c3_y* byt_y; - -#ifdef SERF_TRACE_JAM - u3t_event_trace("serf ipc jam", 'B'); -#endif - - u3s_jam_xeno(pel, &len_d, &byt_y); - -#ifdef SERF_TRACE_JAM - u3t_event_trace("serf ipc jam", 'E'); -#endif - - u3_newt_send(&out_u, len_d, byt_y); - u3z(pel); -} - -/* _cw_serf_send_slog(): send hint output (hod is [priority tank]). -*/ -static void -_cw_serf_send_slog(u3_noun hod) -{ - _cw_serf_send(u3nc(c3__slog, hod)); -} - -/* _cw_serf_send_stdr(): send stderr output (%flog) -*/ -static void -_cw_serf_send_stdr(c3_c* str_c) -{ - _cw_serf_send(u3nc(c3__flog, u3i_string(str_c))); -} - - -/* _cw_serf_step_trace(): initialize or rotate trace file. -*/ -static void -_cw_serf_step_trace(void) -{ - if ( u3C.wag_w & u3o_trace ) { - if ( u3_Host.tra_u.con_w == 0 && u3_Host.tra_u.fun_w == 0 ) { - u3t_trace_open(u3V.dir_c); - } - else if ( u3_Host.tra_u.con_w >= 100000 ) { - u3t_trace_close(); - u3t_trace_open(u3V.dir_c); - } - } -} - -/* _cw_serf_writ(): process a command from the king. -*/ -static void -_cw_serf_writ(void* vod_p, c3_d len_d, c3_y* byt_y) -{ - u3_weak jar; - u3_noun ret; - - _cw_serf_step_trace(); - -#ifdef SERF_TRACE_CUE - u3t_event_trace("serf ipc cue", 'B'); -#endif - - jar = u3s_cue_xeno_with(sil_u, len_d, byt_y); - -#ifdef SERF_TRACE_CUE - u3t_event_trace("serf ipc cue", 'E'); -#endif - - if ( (u3_none == jar) - || (c3n == u3_serf_writ(&u3V, jar, &ret)) ) - { - _cw_serf_fail(0, -1, "bad jar"); - } - else { - _cw_serf_send(ret); - - // all references must now be counted, and all roots recorded - // - u3_serf_post(&u3V); - } -} - -/* _cw_serf_stdio(): fix up std io handles -*/ -static void -_cw_serf_stdio(c3_i* inn_i, c3_i* out_i) -{ - // the serf is spawned with [FD 0] = events and [FD 1] = effects - // we dup [FD 0 & 1] so we don't accidently use them for something else - // we replace [FD 0] (stdin) with a fd pointing to /dev/null - // we replace [FD 1] (stdout) with a dup of [FD 2] (stderr) - // - c3_i nul_i = c3_open(c3_dev_null, O_RDWR, 0); - - *inn_i = dup(0); - *out_i = dup(1); - - dup2(nul_i, 0); - dup2(2, 1); - - close(nul_i); - - // set stream I/O to unbuffered because it's now a pipe not a console - // - setvbuf(stdout, NULL, _IONBF, 0); - setvbuf(stderr, NULL, _IONBF, 0); -} - -/* _cw_serf_stdio(): cleanup on serf exit. -*/ -static void -_cw_serf_exit(void) -{ - u3s_cue_xeno_done(sil_u); - u3t_trace_close(); -} - -/* _cw_init_io(): initialize i/o streams. -*/ -static void -_cw_init_io(uv_loop_t* lup_u) -{ - // mars is spawned with [FD 0] = events and [FD 1] = effects - // we dup [FD 0 & 1] so we don't accidently use them for something else - // we replace [FD 0] (stdin) with a fd pointing to /dev/null - // we replace [FD 1] (stdout) with a dup of [FD 2] (stderr) - // - c3_i nul_i = c3_open(c3_dev_null, O_RDWR, 0); - c3_i inn_i = dup(0); - c3_i out_i = dup(1); - - dup2(nul_i, 0); - dup2(2, 1); - - close(nul_i); - - // set stream I/O to unbuffered because it's now a pipe not a console - // - setvbuf(stdout, NULL, _IONBF, 0); - setvbuf(stderr, NULL, _IONBF, 0); - - // Ignore SIGPIPE signals. - // -#ifndef U3_OS_mingw - { - struct sigaction sig_s = {{0}}; - sigemptyset(&(sig_s.sa_mask)); - sig_s.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &sig_s, 0); - } -#endif - - // configure pipe to daemon process - // - { - c3_i err_i; - err_i = uv_timer_init(lup_u, &inn_u.tim_u); - c3_assert(!err_i); - err_i = uv_pipe_init(lup_u, &inn_u.pyp_u, 0); - c3_assert(!err_i); - uv_pipe_open(&inn_u.pyp_u, inn_i); - err_i = uv_pipe_init(lup_u, &out_u.pyp_u, 0); - c3_assert(!err_i); - uv_pipe_open(&out_u.pyp_u, out_i); - - uv_stream_set_blocking((uv_stream_t*)&out_u.pyp_u, 1); - } -} - -#ifdef U3_OS_mingw -/* _cw_intr_win_cb(): invoked when urth signals ctrl-c. -*/ -static void -_cw_intr_win_cb(PVOID param, BOOLEAN timedOut) -{ - rsignal_raise(SIGINT); -} - -/* _cw_intr_win(): initialize ctrl-c handling. -*/ -static void -_cw_intr_win(c3_c* han_c) -{ - HANDLE h; - if ( 1 != sscanf(han_c, "%" PRIu64, &h) ) { - fprintf(stderr, "mars: ctrl-c event: bad handle %s: %s\r\n", - han_c, strerror(errno)); - } - else { - if ( !RegisterWaitForSingleObject(&h, h, _cw_intr_win_cb, - NULL, INFINITE, 0) ) - { - fprintf(stderr, - "mars: ctrl-c event: RegisterWaitForSingleObject(%u) failed (%d)\r\n", - h, GetLastError()); - } - } -} -#endif - -/* _cw_serf_commence(): initialize and run serf -*/ -static void -_cw_serf_commence(c3_i argc, c3_c* argv[]) -{ -#ifdef U3_OS_mingw - if ( 9 > argc ) { -#else - if ( 8 > argc ) { -#endif - fprintf(stderr, "serf: missing args\n"); - exit(1); - } - - c3_d eve_d = 0; - uv_loop_t* lup_u = u3_Host.lup_u = uv_default_loop(); - c3_c* dir_c = argv[2]; - c3_c* key_c = argv[3]; // XX use passkey - c3_c* wag_c = argv[4]; - c3_c* hap_c = argv[5]; - c3_c* lom_c = argv[6]; - c3_w lom_w; - c3_c* eve_c = argv[7]; -#ifdef U3_OS_mingw - c3_c* han_c = argv[8]; - _cw_intr_win(han_c); -#endif - - _cw_init_io(lup_u); - - memset(&u3V, 0, sizeof(u3V)); - memset(&u3_Host.tra_u, 0, sizeof(u3_Host.tra_u)); - - // load passkey - // - // XX and then ... use passkey - // - { - sscanf(key_c, "%" PRIx64 ":%" PRIx64 ":%" PRIx64 ":%" PRIx64, - &u3V.key_d[0], - &u3V.key_d[1], - &u3V.key_d[2], - &u3V.key_d[3]); - } - - // load runtime config - // - { - sscanf(wag_c, "%" SCNu32, &u3C.wag_w); - sscanf(hap_c, "%" SCNu32, &u3_Host.ops_u.hap_w); - sscanf(lom_c, "%" SCNu32, &lom_w); - - if ( 1 != sscanf(eve_c, "%" PRIu64, &eve_d) ) { - fprintf(stderr, "serf: rock: invalid number '%s'\r\n", argv[4]); - } - } - - sil_u = u3s_cue_xeno_init(); - - // set up writing - // - out_u.ptr_v = &u3V; - out_u.bal_f = _cw_serf_fail; - - // set up reading - // - inn_u.ptr_v = &u3V; - inn_u.pok_f = _cw_serf_writ; - inn_u.bal_f = _cw_serf_fail; - - // setup loom - // - { - u3V.dir_c = strdup(dir_c); - u3V.sen_d = u3V.dun_d = u3m_boot(dir_c, (size_t)1 << lom_w); - - if ( eve_d ) { - // XX need not be fatal, need a u3m_reboot equivalent - // XX can spuriously fail do to corrupt memory-image checkpoint, - // need a u3m_half_boot equivalent - // workaround is to delete/move the checkpoint in case of corruption - // - if ( c3n == u3u_uncram(u3V.dir_c, eve_d) ) { - fprintf(stderr, "serf (%" PRIu64 "): rock load failed\r\n", eve_d); - exit(1); - } - } - } - - // set up logging - // - // XX must be after u3m_boot due to u3l_log - // - { - u3C.stderr_log_f = _cw_serf_send_stdr; - u3C.slog_f = _cw_serf_send_slog; - } - - u3V.xit_f = _cw_serf_exit; - -#if defined(SERF_TRACE_JAM) || defined(SERF_TRACE_CUE) - u3t_trace_open(u3V.dir_c); -#endif - - // start serf - // - { - _cw_serf_send(u3_serf_init(&u3V)); - } - - // start reading - // - u3_newt_read_sync(&inn_u); - - // enter loop - // - uv_run(lup_u, UV_RUN_DEFAULT); - u3m_stop(); -} - -/* _cw_disk_init(): open event log -*/ -static u3_disk* -_cw_disk_init(c3_c* dir_c) -{ - u3_disk_cb cb_u = {0}; - u3_disk* log_u = u3_disk_init(dir_c, cb_u); - - if ( !log_u ) { - fprintf(stderr, "unable to open event log\n"); - exit(1); - } - - return log_u; -} - -/* _cw_dock(): copy binary into pier -*/ -static void -_cw_dock(c3_i argc, c3_c* argv[]) -{ - switch ( argc ) { - case 2: { - if ( !(u3_Host.dir_c = _main_pier_run(argv[0])) ) { - fprintf(stderr, "unable to find pier\r\n"); - exit (1); - } - } break; - - case 3: { - u3_Host.dir_c = argv[2]; - } break; - - default: { - fprintf(stderr, "invalid command\r\n"); - exit(1); - } break; - } - - _main_self_path(); - - u3_king_dock(U3_VERE_PACE); -} - -/* _cw_eval_get_input(): read file til EOF and return a malloc'd string -*/ -c3_c* -_cw_eval_get_input(FILE* fil_u, size_t siz_i) -{ - c3_i car_i; - size_t len_i = 0; - c3_c* str_c = c3_realloc(NULL, siz_i);//size is start size - - while( EOF != (car_i = fgetc(fil_u)) ){ - str_c[len_i++] = car_i; - if( len_i == siz_i ){ - siz_i += 16; - str_c = c3_realloc(str_c, siz_i); - } - } - - str_c[len_i++]='\0'; - - return c3_realloc(str_c, len_i); -} - -/* _cw_eval(): initialize and run the hoon evaluator -*/ -static void -_cw_eval(c3_i argc, c3_c* argv[]) -{ - c3_i ch_i, lid_i; - c3_w arg_w; - - static struct option lop_u[] = { - { "loom", required_argument, NULL, c3__loom }, - { NULL, 0, NULL, 0 } - }; - - while ( -1 != (ch_i=getopt_long(argc, argv, "", lop_u, &lid_i)) ) { - switch ( ch_i ) { - case c3__loom: { - c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); - if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); - exit(1); - } - u3_Host.ops_u.lom_y = lom_w; - } break; - - case '?': { - fprintf(stderr, "invalid argument\r\n"); - exit(1); - } break; - } - } - - // argv[optind] is always "eval" - // - - if ( optind + 1 != argc ) { - fprintf(stderr, "invalid command\r\n"); - exit(1); - } - - c3_c* evl_c = _cw_eval_get_input(stdin, 10); - - // initialize the Loom and load the Ivory Pill - // - { - c3_d len_d = u3_Ivory_pill_len; - c3_y* byt_y = u3_Ivory_pill; - u3_cue_xeno* sil_u; - u3_weak pil; - - u3C.wag_w |= u3o_hashless; - u3m_boot_lite((size_t)1 << u3_Host.ops_u.lom_y); - sil_u = u3s_cue_xeno_init_with(ur_fib27, ur_fib28); - if ( u3_none == (pil = u3s_cue_xeno_with(sil_u, len_d, byt_y)) ) { - printf("lite: unable to cue ivory pill\r\n"); - exit(1); - } - u3s_cue_xeno_done(sil_u); - if ( c3n == u3v_boot_lite(pil) ) { - u3l_log("lite: boot failed"); - exit(1); - } - } - - printf("eval:\n"); - - // +wish for an eval gate (virtualized twice for pretty-printing) - // - u3_noun gat = u3v_wish("|=(a=@t (sell (slap !>(+>.$) (rain /eval a))))"); - u3_noun res; - { - u3_noun sam = u3i_string(evl_c); - u3_noun cor = u3nc(u3k(u3h(gat)), u3nc(sam, u3k(u3t(u3t(gat))))); - res = u3m_soft(0, u3n_kick_on, cor); - } - - - if ( 0 == u3h(res) ) { // successful execution, print output - u3_pier_tank(0, 0, u3k(u3t(res))); - } - else { // error, print stack trace - u3_pier_punt_goof("eval", u3k(res)); - } - - u3z(res); - u3z(gat); - free(evl_c); -} - -/* _cw_info(): print pier info -*/ -static void -_cw_info(c3_i argc, c3_c* argv[]) -{ - switch ( argc ) { - case 2: { - if ( !(u3_Host.dir_c = _main_pier_run(argv[0])) ) { - fprintf(stderr, "unable to find pier\r\n"); - exit (1); - } - } break; - - case 3: { - u3_Host.dir_c = argv[2]; - } break; - - default: { - fprintf(stderr, "invalid command\r\n"); - exit(1); - } break; - } - - c3_d eve_d = u3m_boot(u3_Host.dir_c, u3a_bytes); - u3_disk* log_u = _cw_disk_init(u3_Host.dir_c); - - fprintf(stderr, "\r\nurbit: %s at event %" PRIu64 "\r\n", - u3_Host.dir_c, eve_d); - - u3_disk_slog(log_u); - printf("\n"); - u3_lmdb_stat(log_u->mdb_u, stdout); - u3_disk_exit(log_u); - - u3m_stop(); -} - -/* _cw_grab(): gc pier. -*/ -static void -_cw_grab(c3_i argc, c3_c* argv[]) -{ - switch ( argc ) { - case 2: { - if ( !(u3_Host.dir_c = _main_pier_run(argv[0])) ) { - fprintf(stderr, "unable to find pier\r\n"); - exit (1); - } - } break; - - case 3: { - u3_Host.dir_c = argv[2]; - } break; - - default: { - fprintf(stderr, "invalid command\r\n"); - exit(1); - } break; - } - - u3m_boot(u3_Host.dir_c, u3a_bytes); - u3C.wag_w |= u3o_hashless; - u3_serf_grab(); - u3m_stop(); -} - -/* _cw_cram(): jam persistent state (rock), and exit. -*/ -static void -_cw_cram(c3_i argc, c3_c* argv[]) -{ - c3_i ch_i, lid_i; - c3_w arg_w; - - static struct option lop_u[] = { - { "loom", required_argument, NULL, c3__loom }, - { NULL, 0, NULL, 0 } - }; - - u3_Host.dir_c = _main_pier_run(argv[0]); - - while ( -1 != (ch_i=getopt_long(argc, argv, "", lop_u, &lid_i)) ) { - switch ( ch_i ) { - case c3__loom: { - c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); - if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); - exit(1); - } - u3_Host.ops_u.lom_y = lom_w; - } break; - - case '?': { - fprintf(stderr, "invalid argument\r\n"); - exit(1); - } break; - } - } - - // argv[optind] is always "cram" - // - - if ( !u3_Host.dir_c ) { - if ( optind + 1 < argc ) { - u3_Host.dir_c = argv[optind + 1]; - } - else { - fprintf(stderr, "invalid command, pier required\r\n"); - exit(1); - } - - optind++; - } - - if ( optind + 1 != argc ) { - fprintf(stderr, "invalid command\r\n"); - exit(1); - } - - c3_d eve_d = u3m_boot(u3_Host.dir_c, (size_t)1 << u3_Host.ops_u.lom_y); - u3_disk* log_u = _cw_disk_init(u3_Host.dir_c); // XX s/b try_aquire lock - c3_o ret_o; - - fprintf(stderr, "urbit: cram: preparing\r\n"); - - if ( c3n == (ret_o = u3u_cram(u3_Host.dir_c, eve_d)) ) { - fprintf(stderr, "urbit: cram: unable to jam state\r\n"); - } - else { - fprintf(stderr, "urbit: cram: rock saved at event %" PRIu64 "\r\n", eve_d); - } - - // save even on failure, as we just did all the work of deduplication - // - u3e_save(); - u3_disk_exit(log_u); - - if ( c3n == ret_o ) { - exit(1); - } - - u3m_stop(); -} - -/* _cw_queu(): cue rock, save, and exit. -*/ -static void -_cw_queu(c3_i argc, c3_c* argv[]) -{ - c3_i ch_i, lid_i; - c3_w arg_w; - - static struct option lop_u[] = { - { "loom", required_argument, NULL, c3__loom }, - { NULL, 0, NULL, 0 } - }; - - u3_Host.dir_c = _main_pier_run(argv[0]); - - while ( -1 != (ch_i=getopt_long(argc, argv, "", lop_u, &lid_i)) ) { - switch ( ch_i ) { - case c3__loom: { - c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); - if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); - exit(1); - } - u3_Host.ops_u.lom_y = lom_w; - } break; - - case '?': { - fprintf(stderr, "invalid argument\r\n"); - exit(1); - } break; - } - } - - // argv[optind] is always "queu" - // - - if ( !u3_Host.dir_c ) { - if ( optind + 1 < argc ) { - u3_Host.dir_c = argv[optind + 1]; - } - else { - fprintf(stderr, "invalid command, pier required\r\n"); - exit(1); - } - - optind++; - } - - if ( optind + 1 != argc ) { - fprintf(stderr, "invalid command\r\n"); - exit(1); - } - - c3_c* eve_c; - c3_d eve_d; - - if ( 1 != sscanf(eve_c, "%" PRIu64 "", &eve_d) ) { - fprintf(stderr, "urbit: queu: invalid number '%s'\r\n", eve_c); - exit(1); - } - else { - u3_disk* log_u = _cw_disk_init(u3_Host.dir_c); // XX s/b try_aquire lock - - fprintf(stderr, "urbit: queu: preparing\r\n"); - - u3m_boot(u3_Host.dir_c, (size_t)1 << u3_Host.ops_u.lom_y); - - // XX can spuriously fail do to corrupt memory-image checkpoint, - // need a u3m_half_boot equivalent - // workaround is to delete/move the checkpoint in case of corruption - // - if ( c3n == u3u_uncram(u3_Host.dir_c, eve_d) ) { - fprintf(stderr, "urbit: queu: failed\r\n"); - exit(1); - } - - u3e_save(); - u3_disk_exit(log_u); - - fprintf(stderr, "urbit: queu: rock loaded at event %" PRIu64 "\r\n", eve_d); - u3m_stop(); - } -} - -/* _cw_uniq(): deduplicate persistent nouns -*/ -static void -_cw_meld(c3_i argc, c3_c* argv[]) -{ - c3_i ch_i, lid_i; - c3_w arg_w; - - static struct option lop_u[] = { - { "loom", required_argument, NULL, c3__loom }, - { NULL, 0, NULL, 0 } - }; - - u3_Host.dir_c = _main_pier_run(argv[0]); - - while ( -1 != (ch_i=getopt_long(argc, argv, "", lop_u, &lid_i)) ) { - switch ( ch_i ) { - case c3__loom: { - c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); - if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); - exit(1); - } - u3_Host.ops_u.lom_y = lom_w; - } break; - - case '?': { - fprintf(stderr, "invalid argument\r\n"); - exit(1); - } break; - } - } - - // argv[optind] is always "meld" - // - - if ( !u3_Host.dir_c ) { - if ( optind + 1 < argc ) { - u3_Host.dir_c = argv[optind + 1]; - } - else { - fprintf(stderr, "invalid command, pier required\r\n"); - exit(1); - } - - optind++; - } - - if ( optind + 1 != argc ) { - fprintf(stderr, "invalid command\r\n"); - exit(1); - } - - u3_disk* log_u = _cw_disk_init(u3_Host.dir_c); // XX s/b try_aquire lock - c3_w pre_w; - - u3C.wag_w |= u3o_hashless; - u3m_boot(u3_Host.dir_c, (size_t)1 << u3_Host.ops_u.lom_y); - - pre_w = u3a_open(u3R); - u3u_meld(); - u3a_print_memory(stderr, "urbit: meld: gained", (u3a_open(u3R) - pre_w)); - - u3e_save(); - u3_disk_exit(log_u); - u3m_stop(); -} - -/* _cw_next(): request upgrade -*/ -static void -_cw_next(c3_i argc, c3_c* argv[]) -{ - c3_i ch_i, lid_i; - c3_w arg_w; - - static struct option lop_u[] = { - { "arch", required_argument, NULL, 'a' }, - { "loom", required_argument, NULL, c3__loom }, - { NULL, 0, NULL, 0 } - }; - - u3_Host.dir_c = _main_pier_run(argv[0]); - - while ( -1 != (ch_i=getopt_long(argc, argv, "a:", lop_u, &lid_i)) ) { - switch ( ch_i ) { - case 'a': { - u3_Host.arc_c = strdup(optarg); - } break; - - case c3__loom: { - c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); - if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); - exit(1); - } - u3_Host.ops_u.lom_y = lom_w; - } break; - - case '?': { - fprintf(stderr, "invalid argument\r\n"); - exit(1); - } break; - } - } - - // argv[optind] is always "next" - // - - if ( !u3_Host.dir_c ) { - if ( optind + 1 < argc ) { - u3_Host.dir_c = argv[optind + 1]; - } - else { - fprintf(stderr, "invalid command, pier required\r\n"); - exit(1); - } - - optind++; - } - - if ( optind + 1 != argc ) { - fprintf(stderr, "invalid command\r\n"); - exit(1); - } - - u3_Host.pep_o = c3y; - u3_Host.nex_o = c3y; - u3_Host.ops_u.tem = c3y; -} - -/* _cw_pack(): compact memory, save, and exit. -*/ -static void -_cw_pack(c3_i argc, c3_c* argv[]) -{ - c3_i ch_i, lid_i; - c3_w arg_w; - - static struct option lop_u[] = { - { "loom", required_argument, NULL, c3__loom }, - { NULL, 0, NULL, 0 } - }; - - u3_Host.dir_c = _main_pier_run(argv[0]); - - while ( -1 != (ch_i=getopt_long(argc, argv, "", lop_u, &lid_i)) ) { - switch ( ch_i ) { - case c3__loom: { - c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); - if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); - exit(1); - } - u3_Host.ops_u.lom_y = lom_w; - } break; - - case '?': { - fprintf(stderr, "invalid argument\r\n"); - exit(1); - } break; - } - } - - // argv[optind] is always "pack" - // - - if ( !u3_Host.dir_c ) { - if ( optind + 1 < argc ) { - u3_Host.dir_c = argv[optind + 1]; - } - else { - fprintf(stderr, "invalid command, pier required\r\n"); - exit(1); - } - - optind++; - } - - if ( optind + 1 != argc ) { - fprintf(stderr, "invalid command\r\n"); - exit(1); - } - - u3_disk* log_u = _cw_disk_init(u3_Host.dir_c); // XX s/b try_aquire lock - - u3m_boot(u3_Host.dir_c, (size_t)1 << u3_Host.ops_u.lom_y); - u3a_print_memory(stderr, "urbit: pack: gained", u3m_pack()); - - u3e_save(); - u3_disk_exit(log_u); - u3m_stop(); -} - -/* _cw_prep(): prepare for upgrade -*/ -static void -_cw_prep(c3_i argc, c3_c* argv[]) -{ - c3_i ch_i, lid_i; - c3_w arg_w; - - static struct option lop_u[] = { - { "loom", required_argument, NULL, c3__loom }, - { NULL, 0, NULL, 0 } - }; - - u3_Host.dir_c = _main_pier_run(argv[0]); - - while ( -1 != (ch_i=getopt_long(argc, argv, "", lop_u, &lid_i)) ) { - switch ( ch_i ) { - case c3__loom: { - c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); - if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); - exit(1); - } - u3_Host.ops_u.lom_y = lom_w; - } break; - - case '?': { - fprintf(stderr, "invalid argument\r\n"); - exit(1); - } break; - } - } - - // argv[optind] is always "prep" - // - - if ( !u3_Host.dir_c ) { - if ( optind + 1 < argc ) { - u3_Host.dir_c = argv[optind + 1]; - } - else { - fprintf(stderr, "invalid command, pier required\r\n"); - exit(1); - } - - optind++; - } - - if ( optind + 1 != argc ) { - fprintf(stderr, "invalid command\r\n"); - exit(1); - } - - u3_Host.pep_o = c3y; - u3_Host.ops_u.tem = c3y; -} - -/* _cw_vere(): download vere -*/ -static void -_cw_vere(c3_i argc, c3_c* argv[]) -{ - c3_c* pac_c = "live"; - c3_c* arc_c = 0; - c3_c* ver_c = 0; - c3_c* dir_c; - - c3_i ch_i, lid_i; - c3_w arg_w; - - static struct option lop_u[] = { - { "arch", required_argument, NULL, 'a' }, - { "pace", required_argument, NULL, 'p' }, - { "version", required_argument, NULL, 'v' }, - { NULL, 0, NULL, 0 } - }; - - while ( -1 != (ch_i=getopt_long(argc, argv, "a:p:v:", lop_u, &lid_i)) ) { - switch ( ch_i ) { - case 'a': { - arc_c = strdup(optarg); - } break; - - case 'p': { - pac_c = strdup(optarg); - } break; - - case 'v': { - ver_c = strdup(optarg); - } break; - - case '?': { - exit(1); - } break; - } - } - - // argv[optind] is always "vere"/"fetch-vere" - // - - if ( optind + 1 < argc ) { - dir_c = argv[optind + 1]; - optind++; - } - else { - fprintf(stderr, "invalid command, output directory required\r\n"); - exit(1); - } - - if ( optind + 1 != argc ) { - fprintf(stderr, "invalid command\r\n"); - exit(1); - } - - if ( !arc_c ) { -#ifdef U3_OS_ARCH - arc_c = U3_OS_ARCH; -#else - fprintf(stderr, "unknown architecture, --arch required\r\n"); - exit(1); -#endif - } - - // Initialize OpenSSL for client and server - // - { - SSL_library_init(); - SSL_load_error_strings(); - } - - // initialize curl - // - if ( 0 != curl_global_init(CURL_GLOBAL_DEFAULT) ) { - u3l_log("boot: curl initialization failed"); - exit(1); - } - - _setup_cert_store(); - u3K.ssl_curl_f = _setup_ssl_curl; - u3K.ssl_x509_f = _setup_ssl_x509; - - if ( !ver_c ) { - switch ( u3_king_next(pac_c, &ver_c) ) { - case -2: { - fprintf(stderr, "vere: unable to check for next version\n"); - exit(1); - } break; - - case -1: { - fprintf(stderr, "you're already running it!\n"); - exit(0); - } break; - - case 0: { - fprintf(stderr, "vere: next (%%%s): %s\n", pac_c, ver_c); - } break; - - default: c3_assert(0); - } - } - - - if ( u3_king_vere(pac_c, ver_c, arc_c, dir_c, 0) ) { - u3l_log("vere: download failed"); - exit(1); - } - - u3l_log("vere: download succeeded"); -} - -/* _cw_vile(): generatoe/print keyfile -*/ -static void -_cw_vile(c3_i argc, c3_c* argv[]) -{ - c3_i ch_i, lid_i; - c3_w arg_w; - - static struct option lop_u[] = { - { "loom", required_argument, NULL, c3__loom }, - { NULL, 0, NULL, 0 } - }; - - u3_Host.dir_c = _main_pier_run(argv[0]); - - while ( -1 != (ch_i=getopt_long(argc, argv, "", lop_u, &lid_i)) ) { - switch ( ch_i ) { - case c3__loom: { - c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); - if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); - exit(1); - } - u3_Host.ops_u.lom_y = lom_w; - } break; - - case '?': { - fprintf(stderr, "invalid argument\r\n"); - exit(1); - } break; - } - } - - // argv[optind] is always "vile" - // - - if ( !u3_Host.dir_c ) { - if ( optind + 1 < argc ) { - u3_Host.dir_c = argv[optind + 1]; - } - else { - fprintf(stderr, "invalid command, pier required\r\n"); - exit(1); - } - - optind++; - } - - if ( optind + 1 != argc ) { - fprintf(stderr, "invalid command\r\n"); - exit(1); - } - - // XX check if snapshot is stale? - // - c3_d eve_d = u3m_boot(u3_Host.dir_c, (size_t)1 << u3_Host.ops_u.lom_y); - u3_noun sam = u3nc(u3nc(u3_nul, u3_nul), - u3nc(c3n, u3nq(c3__once, 'j', c3__vile, u3_nul))); - u3_noun res = u3v_soft_peek(0, sam); - - - switch ( u3h(res) ) { - default: c3_assert(0); - - case c3n: { - fprintf(stderr, "vile: unable to retrieve key file\r\n"); - u3_pier_punt_goof("foo", u3k(u3t(res))); - } - case c3y: { - u3_noun dat, vil, out; - c3_c* out_c; - - if ( (u3_nul != u3h(u3t(res))) - || (c3n == u3r_pq(u3t(u3t(res)), c3__omen, 0, &dat)) - || (c3n == u3r_p(dat, c3__atom, &vil)) - || (c3n == u3a_is_atom(vil)) ) - { - fprintf(stderr, "vile: unable to extract key file\r\n"); - u3m_p("vil", res); - } - else { - out = u3dc("scot", c3__uw, u3k(vil)); - out_c = u3r_string(out); - puts(out_c); - c3_free(out_c); - u3z(out); - } - } - } - - u3z(res); -} - -/* _cw_utils(): "worker" utilities and "serf" entrypoint -*/ -static c3_i -_cw_utils(c3_i argc, c3_c* argv[]) -{ - // utility commands and positional arguments, by analogy - // - // $@ ~ :: usage - // $% [%cram dir=@t] :: jam state - // [%dock dir=@t] :: copy binary - // [?(%grab %mass) dir=@t] :: gc - // [%info dir=@t] :: print - // [%meld dir=@t] :: deduplicate - // [?(%next %upgrade) dir=@t] :: upgrade - // [%pack dir=@t] :: defragment - // [%prep dir=@t] :: prep upgrade - // [%queu dir=@t eve=@ud] :: cue state - // [?(%vere %fetch-vere) dir=@t] :: download vere - // [%vile dir=@t] :: extract keys - // :: :: ipc: - // $: %serf :: compute - // dir=@t key=@t wag=@t hap=@ud :: - // lom=@ud eve=@ud :: - // == == :: - // - // NB: don't print to anything other than stderr; - // other streams may be used for ipc. - // - c3_m mot_m = 0; - - if ( 2 <= argc ) { - if ( 4 == strlen(argv[1]) ) { - c3_c* s = argv[1]; - mot_m = c3_s4(s[0], s[1], s[2], s[3]); - } - else if ( 0 == strcmp(argv[1], "upgrade") ) { - mot_m = c3__next; - } - else if ( 0 == strcmp(argv[1], "fetch-vere") ) { - mot_m = c3__vere; - } - } - - switch ( mot_m ) { - case c3__cram: _cw_cram(argc, argv); return 1; - case c3__dock: _cw_dock(argc, argv); return 1; - case c3__eval: _cw_eval(argc, argv); return 1; - - case c3__mass: - case c3__grab: _cw_grab(argc, argv); return 1; - - case c3__info: _cw_info(argc, argv); return 1; - case c3__meld: _cw_meld(argc, argv); return 1; - case c3__next: _cw_next(argc, argv); return 2; // continue on - case c3__pack: _cw_pack(argc, argv); return 1; - case c3__prep: _cw_prep(argc, argv); return 2; // continue on - case c3__queu: _cw_queu(argc, argv); return 1; - case c3__vere: _cw_vere(argc, argv); return 1; - case c3__vile: _cw_vile(argc, argv); return 1; - - case c3__serf: _cw_serf_commence(argc, argv); return 1; - } - - return 0; -} - -c3_i -main(c3_i argc, - c3_c** argv) -{ - if ( argc <= 0 ) { - fprintf(stderr, "nice try, fbi\r\n"); - exit(1); - } - - _main_init(); - - c3_c* bin_c = strdup(argv[0]); - - // parse for subcommands - // - switch ( _cw_utils(argc, argv) ) { - default: c3_assert(0); - - // no matching subcommand, parse arguments - // - case 0: { - if ( c3n == _main_getopt(argc, argv) ) { - u3_ve_usage(argc, argv); - return 1; - } - } break; - - // ran subcommand - case 1: { - return 0; - } - - // found subcommand, continue - // - case 2: break; - } - - _main_self_path(); - - // XX add argument - // - if ( !u3_Host.wrk_c ) { - u3_Host.wrk_c = bin_c; - } - else { - c3_free(bin_c); - } - - if ( c3y == u3_Host.ops_u.dem ) { - // In daemon mode, run the urbit as a background process, but don't - // exit from the parent process until the ship is finished booting. - // - u3_daemon_init(); - } - - if ( c3y == u3_Host.ops_u.rep ) { - report(); - return 0; - } - - if ( c3y == u3_Host.ops_u.tex ) { - u3_Host.bot_f = _stop_on_boot_completed_cb; - } - -#if 0 - if ( 0 == getuid() ) { - chroot(u3_Host.dir_c); - u3_Host.dir_c = "/"; - } -#endif - u3_ve_sysopt(); - - // Block profiling signal, which should be delivered to exactly one thread. - // - // XX review, may be unnecessary due to similar in u3m_init() - // -#if defined(U3_OS_PROF) - if ( _(u3_Host.ops_u.pro) ) { - sigset_t set; - - sigemptyset(&set); - sigaddset(&set, SIGPROF); - if ( 0 != pthread_sigmask(SIG_BLOCK, &set, NULL) ) { - u3l_log("boot: thread mask SIGPROF: %s", strerror(errno)); - exit(1); - } - } -#endif - - #if !defined(U3_OS_mingw) - // Handle SIGTSTP as if it was SIGTERM. - // - // Configured here using signal() so as to be immediately available. - // - signal(SIGTSTP, _stop_exit); - #endif - - printf("~\n"); - // printf("welcome.\n"); - printf("urbit %s\n", URBIT_VERSION); - printf("boot: home is %s\n", u3_Host.dir_c); - // printf("vere: hostname is %s\n", u3_Host.ops_u.nam_c); - - if ( c3y == u3_Host.ops_u.dem ) { - printf("boot: running as daemon\n"); - } - - // Instantiate process globals. - { - /* Boot the image and checkpoint. Set flags. - */ - { - /* Set pier directory. - */ - u3C.dir_c = u3_Host.dir_c; - - /* Logging that doesn't interfere with console output. - */ - u3C.stderr_log_f = u3_term_io_log; - - /* Set GC flag. - */ - if ( _(u3_Host.ops_u.gab) ) { - u3C.wag_w |= u3o_debug_ram; - } - - /* Set profile flag. - */ - if ( _(u3_Host.ops_u.pro) ) { - u3C.wag_w |= u3o_debug_cpu; - } - - /* Set verbose flag. - */ - if ( _(u3_Host.ops_u.veb) ) { - u3C.wag_w |= u3o_verbose; - } - - /* Set quiet flag. - */ - if ( _(u3_Host.ops_u.qui) ) { - u3C.wag_w |= u3o_quiet; - } - - /* Set dry-run flag. - ** - ** XX also exit immediately? - */ - if ( _(u3_Host.ops_u.dry) ) { - u3C.wag_w |= u3o_dryrun; - } - - /* Set hashboard flag - */ - if ( _(u3_Host.ops_u.has) ) { - u3C.wag_w |= u3o_hashless; - } - - /* Set tracing flag - */ - if ( _(u3_Host.ops_u.tra) ) { - u3C.wag_w |= u3o_trace; - u3_Host.tra_u.nid_w = 0; - u3_Host.tra_u.fil_u = NULL; - u3_Host.tra_u.con_w = 0; - u3_Host.tra_u.fun_w = 0; - } - } - -#ifdef U3_OS_mingw - // Initialize event used to transmit Ctrl-C to worker process - // - { - SECURITY_ATTRIBUTES sa = {sizeof(sa), NULL, TRUE}; - if ( NULL == (u3_Host.cev_u = CreateEvent(&sa, FALSE, FALSE, NULL)) ) { - u3l_log("boot: failed to create Ctrl-C event: %d", GetLastError()); - exit(1); - } - } -#endif - - // starting u3m configures OpenSSL memory functions, so we must do it - // before any OpenSSL allocations - // - u3m_boot_lite((size_t)1 << u3_Host.ops_u.lut_y); - - // Initialize OpenSSL for client and server - // - { - SSL_library_init(); - SSL_load_error_strings(); - } - - // initialize curl - // - if ( 0 != curl_global_init(CURL_GLOBAL_DEFAULT) ) { - u3l_log("boot: curl initialization failed"); - exit(1); - } - - _setup_cert_store(); - u3K.ssl_curl_f = _setup_ssl_curl; - u3K.ssl_x509_f = _setup_ssl_x509; - - u3_king_commence(); - - // uninitialize curl - // - curl_global_cleanup(); - - // uninitialize OpenSSL - // - // see https://wiki.openssl.org/index.php/Library_Initialization - // - { - ENGINE_cleanup(); - CONF_modules_unload(1); - EVP_cleanup(); - CRYPTO_cleanup_all_ex_data(); - SSL_COMP_free_compression_methods(); - ERR_free_strings(); - } - } - - return 0; -} diff --git a/pkg/urbit/daemon/whereami.c b/pkg/urbit/daemon/whereami.c deleted file mode 100644 index 290005766..000000000 --- a/pkg/urbit/daemon/whereami.c +++ /dev/null @@ -1,673 +0,0 @@ -// (‑●‑●)> released under the WTFPL v2 license, by Gregory Pakosz (@gpakosz) -// https://github.com/gpakosz/whereami - -// in case you want to #include "whereami.c" in a larger compilation unit -#if !defined(WHEREAMI_H) -#include "whereami.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC) -#include -#endif - -#if !defined(WAI_MALLOC) -#define WAI_MALLOC(size) malloc(size) -#endif - -#if !defined(WAI_FREE) -#define WAI_FREE(p) free(p) -#endif - -#if !defined(WAI_REALLOC) -#define WAI_REALLOC(p, size) realloc(p, size) -#endif - -#ifndef WAI_NOINLINE -#if defined(_MSC_VER) -#define WAI_NOINLINE __declspec(noinline) -#elif defined(__GNUC__) -#define WAI_NOINLINE __attribute__((noinline)) -#else -#error unsupported compiler -#endif -#endif - -#if defined(_MSC_VER) -#define WAI_RETURN_ADDRESS() _ReturnAddress() -#elif defined(__GNUC__) -#define WAI_RETURN_ADDRESS() __builtin_extract_return_addr(__builtin_return_address(0)) -#else -#error unsupported compiler -#endif - -#if defined(_WIN32) - -#define WIN32_LEAN_AND_MEAN -#if defined(_MSC_VER) -#pragma warning(push, 3) -#endif -#include -#include -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -static int WAI_PREFIX(getModulePath_)(HMODULE module, char* out, int capacity, int* dirname_length) -{ - wchar_t buffer1[MAX_PATH]; - wchar_t buffer2[MAX_PATH]; - wchar_t* path = NULL; - int length = -1; - - for (;;) - { - DWORD size; - int length_, length__; - - size = GetModuleFileNameW(module, buffer1, sizeof(buffer1) / sizeof(buffer1[0])); - - if (size == 0) - break; - else if (size == (DWORD)(sizeof(buffer1) / sizeof(buffer1[0]))) - { - DWORD size_ = size; - do - { - wchar_t* path_; - - path_ = (wchar_t*)WAI_REALLOC(path, sizeof(wchar_t) * size_ * 2); - if (!path_) - break; - size_ *= 2; - path = path_; - size = GetModuleFileNameW(module, path, size_); - } - while (size == size_); - - if (size == size_) - break; - } - else - path = buffer1; - - if (!_wfullpath(buffer2, path, MAX_PATH)) - break; - length_ = (int)wcslen(buffer2); - length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_ , out, capacity, NULL, NULL); - - if (length__ == 0) - length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_, NULL, 0, NULL, NULL); - if (length__ == 0) - break; - - if (length__ <= capacity && dirname_length) - { - int i; - - for (i = length__ - 1; i >= 0; --i) - { - if (out[i] == '\\') - { - *dirname_length = i; - break; - } - } - } - - length = length__; - - break; - } - - if (path != buffer1) - WAI_FREE(path); - - return length; -} - -WAI_NOINLINE WAI_FUNCSPEC -int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) -{ - return WAI_PREFIX(getModulePath_)(NULL, out, capacity, dirname_length); -} - -WAI_NOINLINE WAI_FUNCSPEC -int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length) -{ - HMODULE module; - int length = -1; - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable: 4054) -#endif - if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)WAI_RETURN_ADDRESS(), &module)) -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - { - length = WAI_PREFIX(getModulePath_)(module, out, capacity, dirname_length); - } - - return length; -} - -#elif defined(__linux__) || defined(__CYGWIN__) || defined(__sun) - -#include -#include -#include -#if defined(__linux__) -#include -#else -#include -#endif -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif -#include - -#if !defined(WAI_PROC_SELF_EXE) -#if defined(__sun) -#define WAI_PROC_SELF_EXE "/proc/self/path/a.out" -#else -#define WAI_PROC_SELF_EXE "/proc/self/exe" -#endif -#endif - -WAI_FUNCSPEC -int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) -{ - char buffer[PATH_MAX]; - char* resolved = NULL; - int length = -1; - - for (;;) - { - resolved = realpath(WAI_PROC_SELF_EXE, buffer); - if (!resolved) - break; - - length = (int)strlen(resolved); - if (length <= capacity) - { - memcpy(out, resolved, length); - - if (dirname_length) - { - int i; - - for (i = length - 1; i >= 0; --i) - { - if (out[i] == '/') - { - *dirname_length = i; - break; - } - } - } - } - - break; - } - - return length; -} - -#if !defined(WAI_PROC_SELF_MAPS_RETRY) -#define WAI_PROC_SELF_MAPS_RETRY 5 -#endif - -#if !defined(WAI_PROC_SELF_MAPS) -#if defined(__sun) -#define WAI_PROC_SELF_MAPS "/proc/self/map" -#else -#define WAI_PROC_SELF_MAPS "/proc/self/maps" -#endif -#endif - -#if defined(__ANDROID__) || defined(ANDROID) -#include -#include -#include -#endif - -WAI_NOINLINE WAI_FUNCSPEC -int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length) -{ - int length = -1; - FILE* maps = NULL; - - for (int r = 0; r < WAI_PROC_SELF_MAPS_RETRY; ++r) - { - maps = fopen(WAI_PROC_SELF_MAPS, "r"); - if (!maps) - break; - - for (;;) - { - char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX]; - uint64_t low, high; - char perms[5]; - uint64_t offset; - uint32_t major, minor; - char path[PATH_MAX]; - uint32_t inode; - - if (!fgets(buffer, sizeof(buffer), maps)) - break; - - if (sscanf(buffer, "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " %x:%x %u %s\n", &low, &high, perms, &offset, &major, &minor, &inode, path) == 8) - { - uint64_t addr = (uintptr_t)WAI_RETURN_ADDRESS(); - if (low <= addr && addr <= high) - { - char* resolved; - - resolved = realpath(path, buffer); - if (!resolved) - break; - - length = (int)strlen(resolved); -#if defined(__ANDROID__) || defined(ANDROID) - if (length > 4 - &&buffer[length - 1] == 'k' - &&buffer[length - 2] == 'p' - &&buffer[length - 3] == 'a' - &&buffer[length - 4] == '.') - { - int fd = open(path, O_RDONLY); - char* begin; - char* p; - - begin = (char*)mmap(0, offset, PROT_READ, MAP_SHARED, fd, 0); - p = begin + offset; - - while (p >= begin) // scan backwards - { - if (*((uint32_t*)p) == 0x04034b50UL) // local file header found - { - uint16_t length_ = *((uint16_t*)(p + 26)); - - if (length + 2 + length_ < (int)sizeof(buffer)) - { - memcpy(&buffer[length], "!/", 2); - memcpy(&buffer[length + 2], p + 30, length_); - length += 2 + length_; - } - - break; - } - - p -= 4; - } - - munmap(begin, offset); - close(fd); - } -#endif - if (length <= capacity) - { - memcpy(out, resolved, length); - - if (dirname_length) - { - int i; - - for (i = length - 1; i >= 0; --i) - { - if (out[i] == '/') - { - *dirname_length = i; - break; - } - } - } - } - - break; - } - } - } - - fclose(maps); - maps = NULL; - - if (length != -1) - break; - } - - if (maps) - fclose(maps); - - return length; -} - -#elif defined(__APPLE__) - -#define _DARWIN_BETTER_REALPATH -#include -#include -#include -#include -#include - -WAI_FUNCSPEC -int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) -{ - char buffer1[PATH_MAX]; - char buffer2[PATH_MAX]; - char* path = buffer1; - char* resolved = NULL; - int length = -1; - - for (;;) - { - uint32_t size = (uint32_t)sizeof(buffer1); - if (_NSGetExecutablePath(path, &size) == -1) - { - path = (char*)WAI_MALLOC(size); - if (!_NSGetExecutablePath(path, &size)) - break; - } - - resolved = realpath(path, buffer2); - if (!resolved) - break; - - length = (int)strlen(resolved); - if (length <= capacity) - { - memcpy(out, resolved, length); - - if (dirname_length) - { - int i; - - for (i = length - 1; i >= 0; --i) - { - if (out[i] == '/') - { - *dirname_length = i; - break; - } - } - } - } - - break; - } - - if (path != buffer1) - WAI_FREE(path); - - return length; -} - -WAI_NOINLINE WAI_FUNCSPEC -int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length) -{ - char buffer[PATH_MAX]; - char* resolved = NULL; - int length = -1; - - for(;;) - { - Dl_info info; - - if (dladdr(WAI_RETURN_ADDRESS(), &info)) - { - resolved = realpath(info.dli_fname, buffer); - if (!resolved) - break; - - length = (int)strlen(resolved); - if (length <= capacity) - { - memcpy(out, resolved, length); - - if (dirname_length) - { - int i; - - for (i = length - 1; i >= 0; --i) - { - if (out[i] == '/') - { - *dirname_length = i; - break; - } - } - } - } - } - - break; - } - - return length; -} - -#elif defined(__QNXNTO__) - -#include -#include -#include -#include -#include - -#if !defined(WAI_PROC_SELF_EXE) -#define WAI_PROC_SELF_EXE "/proc/self/exefile" -#endif - -WAI_FUNCSPEC -int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) -{ - char buffer1[PATH_MAX]; - char buffer2[PATH_MAX]; - char* resolved = NULL; - FILE* self_exe = NULL; - int length = -1; - - for (;;) - { - self_exe = fopen(WAI_PROC_SELF_EXE, "r"); - if (!self_exe) - break; - - if (!fgets(buffer1, sizeof(buffer1), self_exe)) - break; - - resolved = realpath(buffer1, buffer2); - if (!resolved) - break; - - length = (int)strlen(resolved); - if (length <= capacity) - { - memcpy(out, resolved, length); - - if (dirname_length) - { - int i; - - for (i = length - 1; i >= 0; --i) - { - if (out[i] == '/') - { - *dirname_length = i; - break; - } - } - } - } - - break; - } - - fclose(self_exe); - - return length; -} - -WAI_FUNCSPEC -int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length) -{ - char buffer[PATH_MAX]; - char* resolved = NULL; - int length = -1; - - for(;;) - { - Dl_info info; - - if (dladdr(WAI_RETURN_ADDRESS(), &info)) - { - resolved = realpath(info.dli_fname, buffer); - if (!resolved) - break; - - length = (int)strlen(resolved); - if (length <= capacity) - { - memcpy(out, resolved, length); - - if (dirname_length) - { - int i; - - for (i = length - 1; i >= 0; --i) - { - if (out[i] == '/') - { - *dirname_length = i; - break; - } - } - } - } - } - - break; - } - - return length; -} - -#elif defined(__DragonFly__) || defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || defined(__NetBSD__) - -#include -#include -#include -#include -#include -#include - -WAI_FUNCSPEC -int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) -{ - char buffer1[PATH_MAX]; - char buffer2[PATH_MAX]; - char* path = buffer1; - char* resolved = NULL; - int length = -1; - - for (;;) - { - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; - size_t size = sizeof(buffer1); - - if (sysctl(mib, (u_int)(sizeof(mib) / sizeof(mib[0])), path, &size, NULL, 0) != 0) - break; - - resolved = realpath(path, buffer2); - if (!resolved) - break; - - length = (int)strlen(resolved); - if (length <= capacity) - { - memcpy(out, resolved, length); - - if (dirname_length) - { - int i; - - for (i = length - 1; i >= 0; --i) - { - if (out[i] == '/') - { - *dirname_length = i; - break; - } - } - } - } - - break; - } - - if (path != buffer1) - WAI_FREE(path); - - return length; -} - -WAI_NOINLINE WAI_FUNCSPEC -int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length) -{ - char buffer[PATH_MAX]; - char* resolved = NULL; - int length = -1; - - for(;;) - { - Dl_info info; - - if (dladdr(WAI_RETURN_ADDRESS(), &info)) - { - resolved = realpath(info.dli_fname, buffer); - if (!resolved) - break; - - length = (int)strlen(resolved); - if (length <= capacity) - { - memcpy(out, resolved, length); - - if (dirname_length) - { - int i; - - for (i = length - 1; i >= 0; --i) - { - if (out[i] == '/') - { - *dirname_length = i; - break; - } - } - } - } - } - - break; - } - - return length; -} - -#else - -#error unsupported platform - -#endif - -#ifdef __cplusplus -} -#endif diff --git a/pkg/urbit/daemon/whereami.h b/pkg/urbit/daemon/whereami.h deleted file mode 100644 index 6c81af818..000000000 --- a/pkg/urbit/daemon/whereami.h +++ /dev/null @@ -1,65 +0,0 @@ -// (‑●‑●)> released under the WTFPL v2 license, by Gregory Pakosz (@gpakosz) -// https://github.com/gpakosz/whereami - -#ifndef WHEREAMI_H -#define WHEREAMI_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WAI_FUNCSPEC - #define WAI_FUNCSPEC -#endif -#ifndef WAI_PREFIX -#define WAI_PREFIX(function) wai_##function -#endif - -/** - * Returns the path to the current executable. - * - * Usage: - * - first call `int length = wai_getExecutablePath(NULL, 0, NULL);` to - * retrieve the length of the path - * - allocate the destination buffer with `path = (char*)malloc(length + 1);` - * - call `wai_getExecutablePath(path, length, NULL)` again to retrieve the - * path - * - add a terminal NUL character with `path[length] = '\0';` - * - * @param out destination buffer, optional - * @param capacity destination buffer capacity - * @param dirname_length optional recipient for the length of the dirname part - * of the path. - * - * @return the length of the executable path on success (without a terminal NUL - * character), otherwise `-1` - */ -WAI_FUNCSPEC -int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length); - -/** - * Returns the path to the current module - * - * Usage: - * - first call `int length = wai_getModulePath(NULL, 0, NULL);` to retrieve - * the length of the path - * - allocate the destination buffer with `path = (char*)malloc(length + 1);` - * - call `wai_getModulePath(path, length, NULL)` again to retrieve the path - * - add a terminal NUL character with `path[length] = '\0';` - * - * @param out destination buffer, optional - * @param capacity destination buffer capacity - * @param dirname_length optional recipient for the length of the dirname part - * of the path. - * - * @return the length of the module path on success (without a terminal NUL - * character), otherwise `-1` - */ -WAI_FUNCSPEC -int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length); - -#ifdef __cplusplus -} -#endif - -#endif // #ifndef WHEREAMI_H diff --git a/pkg/urbit/include/all.h b/pkg/urbit/include/all.h deleted file mode 100644 index ae647d865..000000000 --- a/pkg/urbit/include/all.h +++ /dev/null @@ -1,32 +0,0 @@ -# include "config.h" - /** c3: C environment. - **/ -# include "c/portable.h" // C and OS portability -# include "c/types.h" // c3 types -# include "c/defs.h" // c3 macros -# include "c/motes.h" // c3 constants - - /** u3: noun environment. - **/ -# include "noun/aliases.h" // general u3 - -# include "noun/allocate.h" // u3a: allocation -# include "noun/events.h" // u3e: persistence -# include "noun/hashtable.h" // u3h: hashtables -# include "noun/imprison.h" // u3i: noun construction -# include "noun/jets.h" // u3j: jet control -# include "noun/log.h" // u3l: logging -# include "noun/manage.h" // u3m: master state -# include "noun/nock.h" // u3n: nock execution -# include "noun/options.h" // u3o: config options -# include "noun/retrieve.h" // u3r: noun access (error returns) -# include "noun/serial.h" // u3s: serialization -# include "noun/trace.h" // u3t: profiling / tracing -# include "noun/xtract.h" // u3x: noun access (error crashes) -# include "noun/urth.h" // u3u: off-loom integration -# include "noun/vortex.h" // u3v: arvo kernel -# include "noun/zave.h" // u3z: memoization - -# include "jets/k.h" // u3k: jets (transfer, args) -# include "jets/q.h" // u3q: jets (retain, args) -# include "jets/w.h" // u3w: jets (retain, core) diff --git a/pkg/urbit/include/c/defs.h b/pkg/urbit/include/c/defs.h deleted file mode 100644 index b649a8866..000000000 --- a/pkg/urbit/include/c/defs.h +++ /dev/null @@ -1,160 +0,0 @@ -#ifndef C3_DEFS_H -#define C3_DEFS_H - - /** Loobeans - inverse booleans to match nock. - **/ -# define c3y 0 -# define c3n 1 - -# define _(x) (c3y == (x)) -# define __(x) ((x) ? c3y : c3n) -# define c3a(x, y) __(_(x) && _(y)) -# define c3o(x, y) __(_(x) || _(y)) - - - /** Random useful C macros. - **/ - /* Assert. Good to capture. - */ - -# if defined(ASAN_ENABLED) && defined(__clang__) -# define c3_assert(x) \ - do { \ - if (!(x)) { \ - c3_cooked(); \ - assert(x); \ - } \ - } while(0) -# else -# define c3_assert(x) \ - do { \ - if (!(x)) { \ - fflush(stderr); \ - fprintf(stderr, "\rAssertion '%s' " \ - "failed in %s:%d\r\n", \ - #x, __FILE__, __LINE__); \ - c3_cooked(); \ - assert(x); \ - } \ - } while(0) -#endif - - /* Stub. - */ -# define c3_stub c3_assert(!"stub") - - /* Size in words. - */ -# define c3_wiseof(x) (((sizeof (x)) + 3) >> 2) - - /* Bit counting. - */ -# define c3_bits_word(w) ((w) ? (32 - __builtin_clz(w)) : 0) - - /* Min and max. - */ -# define c3_max(x, y) ( ((x) > (y)) ? (x) : (y) ) -# define c3_min(x, y) ( ((x) < (y)) ? (x) : (y) ) - - -//! Round up/down (respectively). -//! -//! @param[in] x Integer to round. -//! @param[in] n Multiple to round to. Must be power of 2. -//! -//! @return `x` rounded to the nearest multiple of `n`. -# define c3_rop(x, n) (((x) + ((n) - 1)) & (~((n) - 1))) -# define c3_rod(x, n) ((x) & ~((n) - 1)) - - /* Rotate. - */ -# define c3_rotw(r, x) ( ((x) << (r)) | ((x) >> (32 - (r))) ) - - /* Emergency stdio fix. - */ - int - c3_cooked(); - - /* Fill 16 words (64 bytes) with high-quality entropy. - */ - void - c3_rand(c3_w* rad_w); - - /* Short integers. - */ -# define c3_s1(a) ( (a) ) -# define c3_s2(a, b) ( ((b) << 8) | c3_s1(a) ) -# define c3_s3(a, b, c) ( ((c) << 16) | c3_s2(a, b) ) -# define c3_s4(a, b, c, d) ( ((d) << 24) | c3_s3(a, b, c) ) - -# define c3_s5(a, b, c, d, e) \ - ( ((uint64_t)c3_s1(e) << 32ULL) | c3_s4(a, b, c, d) ) -# define c3_s6(a, b, c, d, e, f) \ - ( ((uint64_t)c3_s2(e, f) << 32ULL) | c3_s4(a, b, c, d) ) -# define c3_s7(a, b, c, d, e, f, g) \ - ( ((uint64_t)c3_s3(e, f, g) << 32ULL) | c3_s4(a, b, c, d) ) -# define c3_s8(a, b, c, d, e, f, g, h) \ - ( ((uint64_t)c3_s4(e, f, g, h) << 32ULL) | c3_s4(a, b, c, d) ) - - /* Byte-order twiddling. - */ -# define c3_flip32(w) \ - ( (((w) >> 24) & 0xff) \ - | (((w) >> 16) & 0xff) << 8 \ - | (((w) >> 8) & 0xff) << 16 \ - | ( (w) & 0xff) << 24 ) - - /* Asserting allocators. - */ -# define c3_free(s) free(s) -# define c3_malloc(s) ({ \ - void* rut = malloc(s); \ - if ( 0 == rut ) { \ - fprintf(stderr, "c3_malloc(%" PRIu64 ") failed\r\n", \ - (c3_d)s); \ - c3_assert(!"memory lost"); \ - } \ - rut;}) -# define c3_calloc(s) ({ \ - void* rut = calloc(1,s); \ - if ( 0 == rut ) { \ - fprintf(stderr, "c3_calloc(%" PRIu64 ") failed\r\n", \ - (c3_d)s); \ - c3_assert(!"memory lost"); \ - } \ - rut;}) -# define c3_realloc(a, b) ({ \ - void* rut = realloc(a, b); \ - if ( 0 == rut ) { \ - fprintf(stderr, "c3_realloc(%" PRIu64 ") failed\r\n", \ - (c3_d)b); \ - c3_assert(!"memory lost"); \ - } \ - rut;}) - - /* Asserting unix fs wrappers. - ** - ** these all crash the process if passed a non-canonical - ** path (i.e., one containing '.', '..', or the empty path - ** component), so make sure you don't pass them one. if you - ** find yourself fighting with them, then please delete them - ** and do a sed search-and-replace to remove the `c3_` from - ** their call sites; their goal is to decrease maintenance - ** burden, not increase it. - */ - // defined in vere/io/unix.c. - c3_t u3_unix_cane(const c3_c* pax_c); -# define c3_open(a, ...) ({ \ - open(a, __VA_ARGS__);}) -# define c3_opendir(a) ({ \ - opendir(a);}) -# define c3_mkdir(a, b) ({ \ - mkdir(a, b);}) -# define c3_rmdir(a) ({ \ - rmdir(a);}) -# define c3_unlink(a) ({ \ - unlink(a);}) -# define c3_fopen(a, b) ({ \ - fopen(a, b);}) - -#endif /* ifndef C3_DEFS_H */ diff --git a/pkg/urbit/include/c/motes.h b/pkg/urbit/include/c/motes.h deleted file mode 100644 index b253362b7..000000000 --- a/pkg/urbit/include/c/motes.h +++ /dev/null @@ -1,1345 +0,0 @@ -#ifndef C3_MOTES_H -#define C3_MOTES_H - - /** Definitions. - **/ - -# define c3__a c3_s1('a') -# define c3__a50 c3_s3('a','5','0') -# 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') -# define c3__aka c3_s3('a','k','a') -# define c3__all c3_s3('a','l','l') -# define c3__alrm c3_s4('a','l','r','m') -# define c3__amat c3_s4('a','m','a','t') -# define c3__ames c3_s4('a','m','e','s') -# define c3__and c3_s3('a','n','d') -# define c3__ankh c3_s4('a','n','k','h') -# define c3__any c3_s3('a','n','y') -# define c3__ap c3_s2('a','p') -# define c3__apen c3_s4('a','p','e','n') -# define c3__aro c3_s3('a','r','o') -# define c3__arvo c3_s4('a','r','v','o') -# define c3__ash c3_s3('a','s','h') -# define c3__at c3_s2('a','t') -# define c3__atom c3_s4('a','t','o','m') -# define c3__auth c3_s4('a','u','t','h') -# define c3__auto c3_s4('a','u','t','o') -# define c3__avow c3_s4('a','v','o','w') -# define c3__ax c3_s2('a','x') -# 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') -# define c3__bail c3_s4('b','a','i','l') -# define c3__ball c3_s4('b','a','l','l') -# define c3__band c3_s4('b','a','n','d') -# define c3__bank c3_s4('b','a','n','k') -# define c3__bar c3_s3('b','a','r') -# define c3__bark c3_s4('b','a','r','k') -# define c3__barn c3_s4('b','a','r','n') -# define c3__base c3_s4('b','a','s','e') -# define c3__bask c3_s4('b','a','s','k') -# define c3__basp c3_s4('b','a','s','p') -# 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__bcdt c3_s4('b','c','d','t') -# define c3__bckt c3_s4('b','c','k','t') -# define c3__bclc c3_s4('b','c','l','c') -# define c3__bcmt c3_s4('b','c','m','t') -# define c3__bcpm c3_s4('b','c','p','m') -# define c3__bcpt c3_s4('b','c','p','t') -# 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') -# define c3__bede c3_s4('b','e','d','e') -# define c3__bee c3_s3('b','e','e') -# define c3__behn c3_s4('b','e','h','n') -# define c3__bel c3_s3('b','e','l') -# define c3__belt c3_s4('b','e','l','t') -# define c3__bend c3_s4('b','e','n','d') -# define c3__ber c3_s3('b','e','r') -# define c3__bias c3_s4('b','i','a','s') -# define c3__bic c3_s3('b','i','c') -# define c3__bind c3_s4('b','i','n','d') -# define c3__bink c3_s4('b','i','n','k') -# define c3__bird c3_s4('b','i','r','d') -# define c3__bit c3_s3('b','i','t') -# define c3__bl c3_s2('b','l') -# define c3__blan c3_s4('b','l','a','n') -# define c3__blap c3_s4('b','l','a','p') -# define c3__bleb c3_s4('b','l','e','b') -# define c3__blem c3_s4('b','l','e','m') -# define c3__blew c3_s4('b','l','e','w') -# define c3__blin c3_s4('b','l','i','n') -# define c3__blit c3_s4('b','l','i','t') -# define c3__blob c3_s4('b','l','o','b') -# define c3__blob c3_s4('b','l','o','b') -# define c3__blog c3_s4('b','l','o','g') -# define c3__bloq c3_s4('b','l','o','q') -# define c3__blot c3_s4('b','l','o','t') -# define c3__blow c3_s4('b','l','o','w') -# define c3__blue c3_s4('b','l','u','e') -# define c3__blur c3_s4('b','l','u','r') -# define c3__bndl c3_s4('b','n','d','l') -# define c3__bndp c3_s4('b','n','d','p') -# define c3__bnld c3_s4('b','n','l','d') -# define c3__bnnp c3_s4('b','n','n','p') -# define c3__bnpd c3_s4('b','n','p','d') -# define c3__bnps c3_s4('b','n','p','s') -# define c3__bnsp c3_s4('b','n','s','p') -# define c3__boat c3_s4('b','o','a','t') -# define c3__boce c3_s4('b','o','c','e') -# define c3__boil c3_s4('b','o','i','l') -# define c3__boin c3_s4('b','o','i','n') -# define c3__bolt c3_s4('b','o','l','t') -# define c3__bond c3_s4('b','o','n','d') -# define c3__bone c3_s4('b','o','n','e') -# define c3__bong c3_s4('b','o','n','g') -# define c3__book c3_s4('b','o','o','k') -# define c3__bool c3_s4('b','o','o','l') -# define c3__boot c3_s4('b','o','o','t') -# define c3__born c3_s4('b','o','r','n') -# define c3__both c3_s4('b','o','t','h') -# define c3__bout c3_s4('b','o','u','t') -# define c3__box c3_s3('b','o','x') -# define c3__br c3_s2('b','r') -# 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__brcl c3_s4('b','r','c','l') -# 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') -# define c3__brdl c3_s4('b','r','d','l') -# define c3__brdp c3_s4('b','r','d','p') -# define c3__brdt c3_s4('b','r','d','t') -# define c3__brhp c3_s4('b','r','h','p') -# define c3__brip c3_s4('b','r','i','p') -# define c3__brkt c3_s4('b','r','k','t') -# define c3__brlc c3_s4('b','r','l','c') -# define c3__brld c3_s4('b','r','l','d') -# define c3__brls c3_s4('b','r','l','s') -# define c3__brms c3_s4('b','r','m','s') -# define c3__brmt c3_s4('b','r','m','t') -# define c3__brnp c3_s4('b','r','n','p') -# define c3__broc c3_s4('b','r','o','c') -# define c3__bron c3_s4('b','r','o','n') -# define c3__brop c3_s4('b','r','o','p') -# define c3__brov c3_s4('b','r','o','v') -# define c3__brpd c3_s4('b','r','p','d') -# define c3__brps c3_s4('b','r','p','s') -# define c3__brrt c3_s4('b','r','r','t') -# define c3__brsg c3_s4('b','r','s','g') -# define c3__brsp c3_s4('b','r','s','p') -# 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__brvt c3_s4('b','r','v','t') -# 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') -# define c3__bump c3_s4('b','u','m','p') -# define c3__bund c3_s4('b','u','n','d') -# define c3__bung c3_s4('b','u','n','g') -# define c3__bunk c3_s4('b','u','n','k') -# define c3__bunt c3_s4('b','u','n','t') -# define c3__bunx c3_s4('b','u','n','x') -# define c3__burn c3_s4('b','u','r','n') -# define c3__busk c3_s4('b','u','s','k') -# define c3__bust c3_s4('b','u','s','t') -# 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') -# define c3__card c3_s4('c','a','r','d') -# define c3__carp c3_s4('c','a','r','p') -# define c3__cary c3_s4('c','a','r','y') -# define c3__case c3_s4('c','a','s','e') -# define c3__cash c3_s4('c','a','s','h') -# define c3__cast c3_s4('c','a','s','t') -# define c3__cat c3_s3('c','a','t') -# define c3__cato c3_s4('c','a','t','o') -# define c3__cay c3_s3('c','a','y') -# define c3__cbbn c3_s4('c','b','b','n') -# define c3__cbbr c3_s4('c','b','b','r') -# define c3__cbdg c3_s4('c','b','d','g') -# define c3__cbkt c3_s4('c','b','k','t') -# define c3__cblc c3_s4('c','b','l','c') -# define c3__cbmt c3_s4('c','b','m','t') -# define c3__cbpm c3_s4('c','b','p','m') -# define c3__cbtr c3_s4('c','b','t','r') -# define c3__cdr c3_s3('c','d','r') -# define c3__ce c3_s2('c','e') -# define c3__cell c3_s4('c','e','l','l') -# define c3__chaf c3_s4('c','h','a','f') -# define c3__chan c3_s4('c','h','a','n') -# define c3__chew c3_s4('c','h','e','w') -# define c3__chis c3_s4('c','h','i','s') -# define c3__chob c3_s4('c','h','o','b') -# define c3__chug c3_s4('c','h','u','g') -# define c3__claf c3_s4('c','l','a','f') -# define c3__clam c3_s4('c','l','a','m') -# 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') -# define c3__clip c3_s4('c','l','i','p') -# define c3__clkt c3_s4('c','l','k','t') -# define c3__clls c3_s4('c','l','l','s') -# define c3__clms c3_s4('c','l','m','s') -# define c3__clr c3_s3('c','l','r') -# define c3__clsg c3_s4('c','l','s','g') -# define c3__clsp c3_s4('c','l','s','p') -# 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') -# define c3__cnhs c3_s4('c','n','h','s') -# define c3__cnhx c3_s4('c','n','h','x') -# define c3__cnkt c3_s4('c','n','k','t') -# define c3__cnls c3_s4('c','n','l','s') -# define c3__cnms c3_s4('c','n','m','s') -# define c3__cnpm c3_s4('c','n','p','m') -# define c3__cnsg c3_s4('c','n','s','g') -# define c3__cntr c3_s4('c','n','t','r') -# define c3__cnts c3_s4('c','n','t','s') -# define c3__cnzy c3_s4('c','n','z','y') -# define c3__cnzz c3_s4('c','n','z','z') -# define c3__coat c3_s4('c','o','a','t') -# define c3__code c3_s4('c','o','d','e') -# define c3__coin c3_s4('c','o','i','n') -# define c3__colb c3_s4('c','o','l','b') -# define c3__cold c3_s4('c','o','l','d') -# define c3__comb c3_s4('c','o','m','b') -# define c3__come c3_s4('c','o','m','e') -# define c3__con c3_s3('c','o','n') -# define c3__cone c3_s4('c','o','n','e') -# define c3__cong c3_s4('c','o','n','g') -# define c3__conn c3_s4('c','o','n','n') -# define c3__cons c3_s4('c','o','n','s') -# define c3__cook c3_s4('c','o','o','k') -# define c3__cool c3_s4('c','o','o','l') -# define c3__core c3_s4('c','o','r','e') -# define c3__corm c3_s4('c','o','r','m') -# define c3__corp c3_s4('c','o','r','p') -# define c3__corp c3_s4('c','o','r','p') -# define c3__cow c3_s3('c','o','w') -# define c3__cpu c3_s3('c','p','u') -# define c3__crad c3_s4('c','r','a','d') -# define c3__cram c3_s4('c','r','a','m') -# define c3__crap c3_s4('c','r','a','p') -# define c3__cret c3_s4('c','r','e','t') -# define c3__crib c3_s4('c','r','i','b') -# define c3__crof c3_s4('c','r','o','f') -# define c3__crop c3_s4('c','r','o','p') -# define c3__crot c3_s4('c','r','o','t') -# define c3__crud c3_s4('c','r','u','d') -# define c3__csbn c3_s4('c','s','b','n') -# define c3__csbr c3_s4('c','s','b','r') -# define c3__csdg c3_s4('c','s','d','g') -# define c3__csdl c3_s4('c','s','d','l') -# define c3__csdp c3_s4('c','s','d','p') -# define c3__csdt c3_s4('c','s','d','t') -# define c3__csin c3_s4('c','s','i','n') -# define c3__csip c3_s4('c','s','i','p') -# define c3__cslc c3_s4('c','s','l','c') -# define c3__csld c3_s4('c','s','l','d') -# define c3__csnp c3_s4('c','s','n','p') -# define c3__cspm c3_s4('c','s','p','m') -# define c3__csps c3_s4('c','s','p','s') -# define c3__csrt c3_s4('c','s','r','t') -# define c3__cssg c3_s4('c','s','s','g') -# define c3__cssp c3_s4('c','s','s','p') -# define c3__cstg c3_s4('c','s','t','g') -# define c3__cstr c3_s4('c','s','t','r') -# define c3__cszp c3_s4('c','s','z','p') -# define c3__ctl c3_s3('c','t','l') -# define c3__cttp c3_s4('c','t','t','p') -# define c3__cube c3_s4('c','u','b','e') -# define c3__cull c3_s4('c','u','l','l') -# define c3__curd c3_s4('c','u','r','d') -# define c3__cut c3_s3('c','u','t') -# define c3__cyl c3_s3('c','y','l') -# define c3__czar c3_s4('c','z','a','r') -# define c3__d c3_s1('d') -# define c3__da c3_s2('d','a') -# define c3__dago c3_s4('d','a','g','o') -# define c3__dant c3_s4('d','a','n','t') -# define c3__dast c3_s4('d','a','s','t') -# define c3__data c3_s4('d','a','t','a') -# define c3__dawn c3_s4('d','a','w','n') -# define c3__dbug c3_s4('d','b','u','g') -# define c3__dec c3_s3('d','e','c') -# define c3__deem c3_s4('d','e','e','m') -# define c3__deep c3_s4('d','e','e','p') -# define c3__defn c3_s4('d','e','f','n') -# define c3__del c3_s3('d','e','l') -# define c3__delc c3_s4('d','e','l','c') -# define c3__delt c3_s4('d','e','l','t') -# define c3__dept c3_s4('d','e','p','t') -# define c3__dext c3_s4('d','e','x','t') -# define c3__dgdp c3_s4('d','g','d','p') -# define c3__dgkt c3_s4('d','g','k','t') -# define c3__dgnp c3_s4('d','g','n','p') -# define c3__dgpd c3_s4('d','g','p','d') -# define c3__dgps c3_s4('d','g','p','s') -# define c3__dgrt c3_s4('d','g','r','t') -# define c3__dgsg c3_s4('d','g','s','g') -# define c3__dgsp c3_s4('d','g','s','p') -# define c3__dgtg c3_s4('d','g','t','g') -# define c3__dgtr c3_s4('d','g','t','r') -# define c3__dice c3_s4('d','i','c','e') -# define c3__die c3_s3('d','i','e') -# define c3__dill c3_s4('d','i','l','l') -# define c3__dire c3_s4('d','i','r','e') -# define c3__dirk c3_s4('d','i','r','k') -# define c3__dis c3_s3('d','i','s') -# define c3__dish c3_s4('d','i','s','h') -# define c3__disk c3_s4('d','i','s','k') -# define c3__div c3_s3('d','i','v') -# define c3__dmal c3_s4('d','m','a','l') -# define c3__do c3_s2('d','o') -# define c3__doc c3_s3('d','o','c') -# define c3__dock c3_s4('d','o','c','k') -# define c3__docs c3_s4('d','o','c','s') -# define c3__dogo c3_s4('d','o','g','o') -# define c3__dojo c3_s4('d','o','j','o') -# define c3__dome c3_s4('d','o','m','e') -# define c3__done c3_s4('d','o','n','e') -# define c3__doom c3_s4('d','o','o','m') -# define c3__door c3_s4('d','o','o','r') -# define c3__dorn c3_s4('d','o','r','n') -# define c3__dost c3_s4('d','o','s','t') -# define c3__dot c3_s3('d','o','t') -# define c3__doze c3_s4('d','o','z','e') -# define c3__drag c3_s4('d','r','a','g') -# define c3__draz c3_s4('d','r','a','z') -# define c3__drib c3_s4('d','r','i','b') -# define c3__drol c3_s4('d','r','o','l') -# define c3__dron c3_s4('d','r','o','n') -# define c3__drop c3_s4('d','r','o','p') -# define c3__drun c3_s4('d','r','u','n') -# define c3__dry c3_s3('d','r','y') -# define c3__dtbn c3_s4('d','t','b','n') -# define c3__dtcs c3_s4('d','t','c','s') -# define c3__dtdt c3_s4('d','t','d','t') -# define c3__dthx c3_s4('d','t','h','x') -# define c3__dtkt c3_s4('d','t','k','t') -# define c3__dtlc c3_s4('d','t','l','c') -# define c3__dtls c3_s4('d','t','l','s') -# define c3__dtpd c3_s4('d','t','p','d') -# define c3__dtps c3_s4('d','t','p','s') -# define c3__dtpt c3_s4('d','t','p','t') -# define c3__dtrt c3_s4('d','t','r','t') -# define c3__dtsg c3_s4('d','t','s','g') -# define c3__dttg c3_s4('d','t','t','g') -# define c3__dttr c3_s4('d','t','t','r') -# define c3__dtts c3_s4('d','t','t','s') -# define c3__dtwt c3_s4('d','t','w','t') -# define c3__dtzy c3_s4('d','t','z','y') -# define c3__dtzz c3_s4('d','t','z','z') -# define c3__dub c3_s3('d','u','b') -# define c3__duct c3_s4('d','u','c','t') -# define c3__duke c3_s4('d','u','k','e') -# define c3__dumb c3_s4('d','u','m','b') -# define c3__dump c3_s4('d','u','m','p') -# define c3__dust c3_s4('d','u','s','t') -# define c3__dxkt c3_s4('d','x','k','t') -# define c3__e c3_s1('e') -# define c3__earl c3_s4('e','a','r','l') -# define c3__east c3_s4('e','a','s','t') -# define c3__echo c3_s4('e','c','h','o') -# define c3__edge c3_s4('e','d','g','e') -# define c3__edit c3_s4('e','d','i','t') -# define c3__elm c3_s3('e','l','m') -# define c3__else c3_s4('e','l','s','e') -# define c3__emph c3_s4('e','m','p','h') -# define c3__end c3_s3('e','n','d') -# define c3__eq c3_s2('e','q') -# define c3__ergo c3_s4('e','r','g','o') -# define c3__esh c3_s3('e','s','h') -# define c3__etch c3_s4('e','t','c','h') -# define c3__eval c3_s4('e','v','a','l') -# define c3__evil c3_s4('e','v','i','l') -# define c3__ex c3_s2('e','x') -# define c3__exit c3_s4('e','x','i','t') -# define c3__eyre c3_s4('e','y','r','e') -# define c3__f c3_s1('f') -# define c3__fab c3_s3('f','a','b') -# define c3__face c3_s4('f','a','c','e') -# define c3__fail c3_s4('f','a','i','l') -# define c3__fair c3_s4('f','a','i','r') -# define c3__fake c3_s4('f','a','k','e') -# define c3__fan c3_s3('f','a','n') -# define c3__farg c3_s4('f','a','r','g') -# define c3__fast c3_s4('f','a','s','t') -# define c3__fdec c3_s4('f','d','e','c') -# define c3__felk c3_s4('f','e','l','k') -# define c3__feng c3_s4('f','e','n','g') -# define c3__fent c3_s4('f','e','n','t') -# define c3__ferd c3_s4('f','e','r','d') -# define c3__fhex c3_s4('f','h','e','x') -# define c3__file c3_s4('f','i','l','e') -# define c3__film c3_s4('f','i','l','m') -# define c3__find c3_s4('f','i','n','d') -# define c3__fine c3_s4('f','i','n','e') -# define c3__fing c3_s4('f','i','n','g') -# define c3__fink c3_s4('f','i','n','k') -# define c3__fino c3_s4('f','i','n','o') -# define c3__fir c3_s3('f','i','r') -# define c3__fire c3_s4('f','i','r','e') -# define c3__firm c3_s4('f','i','r','m') -# define c3__fish c3_s4('f','i','s','h') -# define c3__fist c3_s4('f','i','s','t') -# define c3__fit c3_s3('f','i','t') -# define c3__fits c3_s4('f','i','t','s') -# define c3__fix c3_s3('f','i','x') -# define c3__fl c3_s2('f','l') -# define c3__flac c3_s4('f','l','a','c') -# define c3__flag c3_s4('f','l','a','g') -# define c3__flat c3_s4('f','l','a','t') -# define c3__flec c3_s4('f','l','e','c') -# define c3__flet c3_s4('f','l','e','t') -# define c3__flic c3_s4('f','l','i','c') -# define c3__flip c3_s4('f','l','i','p') -# define c3__flit c3_s4('f','l','i','t') -# define c3__flog c3_s4('f','l','o','g') -# define c3__flot c3_s4('f','l','o','t') -# define c3__flow c3_s4('f','l','o','w') -# define c3__fon c3_s3('f','o','n') -# define c3__fond c3_s4('f','o','n','d') -# define c3__for c3_s3('f','o','r') -# define c3__forb c3_s4('f','o','r','b') -# define c3__fore c3_s4('f','o','r','e') -# define c3__fork c3_s4('f','o','r','k') -# define c3__form c3_s4('f','o','r','m') -# define c3__forq c3_s4('f','o','r','q') -# define c3__foul c3_s4('f','o','u','l') -# define c3__frag c3_s4('f','r','a','g') -# define c3__free c3_s4('f','r','e','e') -# define c3__frez c3_s4('f','r','e','z') -# define c3__frit c3_s4('f','r','i','t') -# define c3__frog c3_s4('f','r','o','g') -# define c3__from c3_s4('f','r','o','m') -# define c3__fron c3_s4('f','r','o','n') -# define c3__fry c3_s3('f','r','y') -# define c3__fuge c3_s4('f','u','g','e') -# define c3__full c3_s4('f','u','l','l') -# define c3__fume c3_s4('f','u','m','e') -# define c3__fun c3_s3('f','u','n') -# define c3__fund c3_s4('f','u','n','d') -# define c3__fung c3_s4('f','u','n','g') -# define c3__funk c3_s4('f','u','n','k') -# define c3__fuse c3_s4('f','u','s','e') -# define c3__fuss c3_s4('f','u','s','s') -# define c3__fyrd c3_s4('f','y','r','d') -# define c3__gab c3_s3('g','a','b') -# define c3__galb c3_s4('g','a','l','b') -# define c3__gald c3_s4('g','a','l','d') -# define c3__galk c3_s4('g','a','l','k') -# define c3__game c3_s4('g','a','m','e') -# define c3__gamp c3_s4('g','a','m','p') -# define c3__gant c3_s4('g','a','n','t') -# define c3__garc c3_s4('g','a','r','c') -# define c3__gate c3_s4('g','a','t','e') -# define c3__gath c3_s4('g','a','t','h') -# define c3__ge c3_s2('g','e') -# define c3__gear c3_s4('g','e','a','r') -# define c3__gen c3_s3('g','e','n') -# define c3__gene c3_s4('g','e','n','e') -# define c3__germ c3_s4('g','e','r','m') -# define c3__get c3_s3('g','e','t') -# define c3__give c3_s4('g','i','v','e') -# define c3__glax c3_s4('g','l','a','x') -# define c3__glaz c3_s4('g','l','a','z') -# define c3__gleb c3_s4('g','l','e','b') -# define c3__glem c3_s4('g','l','e','m') -# define c3__glid c3_s4('g','l','i','d') -# define c3__glon c3_s4('g','l','o','n') -# define c3__glop c3_s4('g','l','o','p') -# define c3__gluc c3_s4('g','l','u','c') -# define c3__glue c3_s4('g','l','u','e') -# define c3__gnom c3_s4('g','n','o','m') -# define c3__gnum c3_s4('g','n','u','m') -# define c3__go c3_s2('g','o') -# define c3__goat c3_s4('g','o','a','t') -# define c3__gold c3_s4('g','o','l','d') -# define c3__good c3_s4('g','o','o','d') -# define c3__gorm c3_s4('g','o','r','m') -# define c3__goto c3_s4('g','o','t','o') -# define c3__grab c3_s4('g','r','a','b') -# define c3__grad c3_s4('g','r','a','d') -# define c3__gram c3_s4('g','r','a','m') -# define c3__gran c3_s4('g','r','a','n') -# define c3__grat c3_s4('g','r','a','t') -# define c3__gray c3_s4('g','r','a','y') -# define c3__grel c3_s4('g','r','e','l') -# define c3__gret c3_s4('g','r','e','t') -# define c3__grik c3_s4('g','r','i','k') -# define c3__gril c3_s4('g','r','i','l') -# define c3__grip c3_s4('g','r','i','p') -# define c3__grit c3_s4('g','r','i','t') -# define c3__griv c3_s4('g','r','i','v') -# define c3__grix c3_s4('g','r','i','x') -# define c3__grop c3_s4('g','r','o','p') -# define c3__grun c3_s4('g','r','u','n') -# define c3__gt c3_s2('g','t') -# define c3__gulf c3_s4('g','u','l','f') -# define c3__gull c3_s4('g','u','l','l') -# define c3__gult c3_s4('g','u','l','t') -# define c3__gund c3_s4('g','u','n','d') -# define c3__gunn c3_s4('g','u','n','n') -# define c3__hack c3_s4('h','a','c','k') -# define c3__hail c3_s4('h','a','i','l') -# define c3__hair c3_s4('h','a','i','r') -# define c3__hake c3_s4('h','a','k','e') -# define c3__halc c3_s4('h','a','l','c') -# 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') -# define c3__heal c3_s4('h','e','a','l') -# define c3__hear c3_s4('h','e','a','r') -# define c3__hela c3_s4('h','e','l','a') -# define c3__helm c3_s4('h','e','l','m') -# define c3__helo c3_s4('h','e','l','o') -# define c3__help c3_s4('h','e','l','p') -# 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') -# define c3__high c3_s4('h','i','g','h') -# define c3__hike c3_s4('h','i','k','e') -# define c3__hill c3_s4('h','i','l','l') -# define c3__hind c3_s4('h','i','n','d') -# define c3__hint c3_s4('h','i','n','t') -# define c3__hit c3_s3('h','i','t') -# define c3__hmal c3_s4('h','m','a','l') -# define c3__hold c3_s4('h','o','l','d') -# define c3__hole c3_s4('h','o','l','e') -# define c3__holt c3_s4('h','o','l','t') -# define c3__home c3_s4('h','o','m','e') -# define c3__homp c3_s4('h','o','m','p') -# define c3__hook c3_s4('h','o','o','k') -# define c3__hoon c3_s4('h','o','o','n') -# define c3__hop c3_s3('h','o','p') -# define c3__hosc c3_s4('h','o','s','c') -# define c3__hose c3_s4('h','o','s','e') -# define c3__howl c3_s4('h','o','w','l') -# define c3__hrul c3_s4('h','r','u','l') -# define c3__hsbn c3_s4('h','s','b','n') -# define c3__hsbr c3_s4('h','s','b','r') -# define c3__hscn c3_s4('h','s','c','n') -# define c3__hsdg c3_s4('h','s','d','g') -# define c3__hskt c3_s4('h','s','k','t') -# define c3__hslc c3_s4('h','s','l','c') -# define c3__hsmt c3_s4('h','s','m','t') -# define c3__hspm c3_s4('h','s','p','m') -# define c3__hssg c3_s4('h','s','s','g') -# define c3__hstr c3_s4('h','s','t','r') -# define c3__hsts c3_s4('h','s','t','s') -# define c3__htcn c3_s4('h','t','c','n') -# define c3__htls c3_s4('h','t','l','s') -# define c3__html c3_s4('h','t','m','l') -# define c3__htmt c3_s4('h','t','m','t') -# define c3__http c3_s4('h','t','t','p') -# define c3__hume c3_s4('h','u','m','e') -# define c3__hunk c3_s4('h','u','n','k') -# define c3__hxgl c3_s4('h','x','g','l') -# define c3__hxgr c3_s4('h','x','g','r') -# define c3__hxtr c3_s4('h','x','t','r') -# define c3__hxts c3_s4('h','x','t','s') -# define c3__i c3_s1('i') -# define c3__ic c3_s2('i','c') -# define c3__ice c3_s3('i','c','e') -# define c3__iced c3_s4('i','c','e','d') -# define c3__id c3_s2('i','d') -# define c3__if c3_s2('i','f') -# define c3__ifix c3_s4('i','f','i','x') -# define c3__in c3_s2('i','n') -# define c3__inc c3_s3('i','n','c') -# define c3__info c3_s4('i','n','f','o') -# define c3__init c3_s4('i','n','i','t') -# define c3__ins c3_s3('i','n','s') -# define c3__into c3_s4('i','n','t','o') -# define c3__intr c3_s4('i','n','t','r') -# define c3__inuk c3_s4('i','n','u','k') -# define c3__ipv4 c3_s4('i','p','v','4') -# define c3__iron c3_s4('i','r','o','n') -# define c3__is c3_s2('i','s') -# define c3__item c3_s4('i','t','e','m') -# define c3__ix c3_s2('i','x') -# define c3__j c3_s1('j') -# define c3__jack c3_s4('j','a','c','k') -# define c3__jam c3_s3('j','a','m') -# define c3__jamx c3_s4('j','a','m','x') -# define c3__jamz c3_s4('j','a','m','z') -# define c3__jato c3_s4('j','a','t','o') -# define c3__jet c3_s3('j','e','t') -# define c3__jetd c3_s4('j','e','t','d') -# define c3__just c3_s4('j','u','s','t') -# define c3__k c3_s1('k') -# define c3__khan c3_s4('k','h','a','n') -# define c3__keep c3_s4('k','e','e','p') -# define c3__kern c3_s4('k','e','r','n') -# define c3__key c3_s3('k','e','y') -# define c3__kgo c3_s3('k','g','o') -# define c3__kick c3_s4('k','i','c','k') -# define c3__king c3_s4('k','i','n','g') -# define c3__kit c3_s3('k','i','t') -# define c3__klr c3_s3('k','l','r') -# define c3__knit c3_s4('k','n','i','t') -# define c3__kno c3_s3('k','n','o') -# define c3__ktbc c3_s4('k','t','b','c') -# define c3__ktbn c3_s4('k','t','b','n') -# define c3__ktbr c3_s4('k','t','b','r') -# define c3__ktcb c3_s4('k','t','c','b') -# define c3__ktcl c3_s4('k','t','c','l') -# define c3__ktcn c3_s4('k','t','c','n') -# define c3__ktcs c3_s4('k','t','c','s') -# define c3__ktdg c3_s4('k','t','d','g') -# define c3__ktdl c3_s4('k','t','d','l') -# define c3__ktdp c3_s4('k','t','d','p') -# 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') -# define c3__ktms c3_s4('k','t','m','s') -# define c3__ktmt c3_s4('k','t','m','t') -# define c3__ktnp c3_s4('k','t','n','p') -# define c3__ktpd c3_s4('k','t','p','d') -# define c3__ktpm c3_s4('k','t','p','m') -# define c3__ktps c3_s4('k','t','p','s') -# define c3__ktpt c3_s4('k','t','p','t') -# define c3__ktrt c3_s4('k','t','r','t') -# define c3__ktsg c3_s4('k','t','s','g') -# define c3__ktsp c3_s4('k','t','s','p') -# define c3__kttg c3_s4('k','t','t','g') -# define c3__kttr c3_s4('k','t','t','r') -# define c3__ktts c3_s4('k','t','t','s') -# define c3__ktwt c3_s4('k','t','w','t') -# define c3__ktzp c3_s4('k','t','z','p') -# define c3__lamb c3_s4('l','a','m','b') -# define c3__lame c3_s4('l','a','m','e') -# define c3__lang c3_s4('l','a','n','g') -# define c3__lask c3_s4('l','a','s','k') -# define c3__last c3_s4('l','a','s','t') -# define c3__lcdl c3_s4('l','c','d','l') -# define c3__lcdp c3_s4('l','c','d','p') -# define c3__lcld c3_s4('l','c','l','d') -# define c3__lcnp c3_s4('l','c','n','p') -# define c3__lcpd c3_s4('l','c','p','d') -# define c3__lcps c3_s4('l','c','p','s') -# define c3__lcsp c3_s4('l','c','s','p') -# define c3__le c3_s2('l','e') -# define c3__lead c3_s4('l','e','a','d') -# define c3__leaf c3_s4('l','e','a','f') -# define c3__leap c3_s4('l','e','a','p') -# define c3__lect c3_s4('l','e','c','t') -# define c3__lee c3_s3('l','e','e') -# define c3__leg c3_s3('l','e','g') -# define c3__lest c3_s4('l','e','s','t') -# define c3__lg c3_s2('l','g') -# define c3__lib c3_s3('l','i','b') -# define c3__libd c3_s4('l','i','b','d') -# define c3__life c3_s4('l','i','f','e') -# define c3__lift c3_s4('l','i','f','t') -# define c3__like c3_s4('l','i','k','e') -# define c3__limb c3_s4('l','i','m','b') -# define c3__lin c3_s3('l','i','n') -# define c3__line c3_s4('l','i','n','e') -# define c3__link c3_s4('l','i','n','k') -# define c3__lint c3_s4('l','i','n','t') -# define c3__liqd c3_s4('l','i','q','d') -# define c3__lisc c3_s4('l','i','s','c') -# define c3__list c3_s4('l','i','s','t') -# define c3__lite c3_s4('l','i','t','e') -# define c3__live c3_s4('l','i','v','e') -# define c3__load c3_s4('l','o','a','d') -# define c3__loaf c3_s4('l','o','a','f') -# define c3__log c3_s3('l','o','g') -# define c3__logo c3_s4('l','o','g','o') -# define c3__lome c3_s4('l','o','m','e') -# define c3__lond c3_s4('l','o','n','d') -# define c3__lonk c3_s4('l','o','n','k') -# define c3__look c3_s4('l','o','o','k') -# define c3__loom c3_s4('l','o','o','m') -# define c3__loop c3_s4('l','o','o','p') -# define c3__lorb c3_s4('l','o','r','b') -# define c3__lord c3_s4('l','o','r','d') -# define c3__lort c3_s4('l','o','r','t') -# define c3__lose c3_s4('l','o','s','e') -# define c3__loss c3_s4('l','o','s','s') -# define c3__lost c3_s4('l','o','s','t') -# define c3__low c3_s3('l','o','w') -# define c3__lsh c3_s3('l','s','h') -# define c3__lt c3_s2('l','t') -# define c3__lull c3_s4('l','u','l','l') -# define c3__lunt c3_s4('l','u','n','t') -# define c3__mach c3_s4('m','a','c','h') -# define c3__mack c3_s4('m','a','c','k') -# define c3__main c3_s4('m','a','i','n') -# define c3__make c3_s4('m','a','k','e') -# define c3__malg c3_s4('m','a','l','g') -# define c3__malk c3_s4('m','a','l','k') -# define c3__mang c3_s4('m','a','n','g') -# define c3__many c3_s4('m','a','n','y') -# define c3__map c3_s3('m','a','p') -# define c3__marg c3_s4('m','a','r','g') -# define c3__mark c3_s4('m','a','r','k') -# define c3__marn c3_s4('m','a','r','n') -# define c3__mash c3_s4('m','a','s','h') -# define c3__mass c3_s4('m','a','s','s') -# define c3__mast c3_s4('m','a','s','t') -# define c3__mate c3_s4('m','a','t','e') -# define c3__mave c3_s4('m','a','v','e') -# define c3__mean c3_s4('m','e','a','n') -# define c3__mega c3_s4('m','e','g','a') -# define c3__meh c3_s3('m','e','h') -# define c3__meld c3_s4('m','e','l','d') -# define c3__melt c3_s4('m','e','l','t') -# define c3__meme c3_s4('m','e','m','e') -# define c3__memo c3_s4('m','e','m','o') -# define c3__menu c3_s4('m','e','n','u') -# define c3__mesh c3_s4('m','e','s','h') -# define c3__met c3_s3('m','e','t') -# define c3__meta c3_s4('m','e','t','a') -# define c3__mill c3_s4('m','i','l','l') -# define c3__mime c3_s4('m','i','m','e') -# define c3__mine c3_s4('m','i','n','e') -# define c3__mint c3_s4('m','i','n','t') -# define c3__mirt c3_s4('m','i','r','t') -# define c3__miss c3_s4('m','i','s','s') -# define c3__mix c3_s3('m','i','x') -# define c3__moat c3_s4('m','o','a','t') -# define c3__mod c3_s3('m','o','d') -# define c3__mold c3_s4('m','o','l','d') -# define c3__mong c3_s4('m','o','n','g') -# define c3__mono c3_s4('m','o','n','o') -# define c3__mook c3_s4('m','o','o','k') -# define c3__moot c3_s4('m','o','o','t') -# define c3__mor c3_s3('m','o','r') -# define c3__move c3_s4('m','o','v','e') -# define c3__moze c3_s4('m','o','z','e') -# define c3__mtbn c3_s4('m','t','b','n') -# define c3__mtbr c3_s4('m','t','b','r') -# define c3__mtdg c3_s4('m','t','d','g') -# define c3__mtdp c3_s4('m','t','d','p') -# define c3__mtdt c3_s4('m','t','d','t') -# define c3__mtkt c3_s4('m','t','k','t') -# define c3__mtlc c3_s4('m','t','l','c') -# define c3__mtnp c3_s4('m','t','n','p') -# define c3__mtpd c3_s4('m','t','p','d') -# define c3__mtps c3_s4('m','t','p','s') -# define c3__mtrt c3_s4('m','t','r','t') -# define c3__mtsg c3_s4('m','t','s','g') -# define c3__mtsp c3_s4('m','t','s','p') -# define c3__mttg c3_s4('m','t','t','g') -# define c3__mttr c3_s4('m','t','t','r') -# define c3__mul c3_s3('m','u','l') -# define c3__mull c3_s4('m','u','l','l') -# define c3__mung c3_s4('m','u','n','g') -# define c3__mut c3_s3('m','u','t') -# define c3__n c3_s1('n') -# define c3__na c3_s2('n','a') -# define c3__nail c3_s4('n','a','i','l') -# define c3__name c3_s4('n','a','m','e') -# define c3__nap c3_s3('n','a','p') -# define c3__nara c3_s4('n','a','r','a') -# define c3__narv c3_s4('n','a','r','v') -# define c3__ne c3_s2('n','e') -# define c3__need c3_s4('n','e','e','d') -# define c3__neft c3_s4('n','e','f','t') -# define c3__nel c3_s3('n','e','l') -# define c3__nest c3_s4('n','e','s','t') -# define c3__netd c3_s4('n','e','t','d') -# define c3__new c3_s3('n','e','w') -# define c3__news c3_s4('n','e','w','s') -# define c3__newt c3_s4('n','e','w','t') -# define c3__next c3_s4('n','e','x','t') -# define c3__nich c3_s4('n','i','c','h') -# define c3__nick c3_s4('n','i','c','k') -# 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__noco c3_s4('n','o','c','o') -# define c3__nodo c3_s4('n','o','d','o') -# define c3__none c3_s4('n','o','n','e') -# define c3__noop c3_s4('n','o','o','p') -# define c3__nop c3_s3('n','o','p') -# define c3__norm c3_s4('n','o','r','m') -# define c3__nost c3_s4('n','o','s','t') -# define c3__not c3_s3('n','o','t') -# define c3__note c3_s4('n','o','t','e') -# define c3__noun c3_s4('n','o','u','n') -# define c3__nt c3_s2('n','t') -# define c3__nub c3_s3('n','u','b') -# define c3__null c3_s4('n','u','l','l') -# define c3__nz c3_s2('n','z') -# define c3__oak c3_s3('o','a','k') -# define c3__of c3_s2('o','f') -# define c3__off c3_s3('o','f','f') -# define c3__ogre c3_s4('o','g','r','e') -# define c3__old c3_s3('o','l','d') -# define c3__omen c3_s4('o','m','e','n') -# define c3__on c3_s2('o','n') -# define c3__onan c3_s4('o','n','a','n') -# define c3__once c3_s4('o','n','c','e') -# define c3__one c3_s3('o','n','e') -# define c3__only c3_s4('o','n','l','y') -# define c3__oops c3_s4('o','o','p','s') -# define c3__op c3_s2('o','p') -# define c3__open c3_s4('o','p','e','n') -# define c3__opts c3_s4('o','p','t','s') -# define c3__or c3_s2('o','r') -# define c3__ord c3_s3('o','r','d') -# define c3__orth c3_s4('o','r','t','h') -# define c3__outd c3_s4('o','u','t','d') -# define c3__ov c3_s2('o','v') -# define c3__over c3_s4('o','v','e','r') -# define c3__ovum c3_s4('o','v','u','m') -# define c3__p c3_s1('p') -# define c3__pack c3_s4('p','a','c','k') -# define c3__pair c3_s4('p','a','i','r') -# define c3__palm c3_s4('p','a','l','m') -# define c3__palq c3_s4('p','a','l','q') -# define c3__palt c3_s4('p','a','l','t') -# define c3__pan c3_s3('p','a','n') -# define c3__pane c3_s4('p','a','n','e') -# define c3__pang c3_s4('p','a','n','g') -# define c3__pank c3_s4('p','a','n','k') -# define c3__para c3_s4('p','a','r','a') -# define c3__park c3_s4('p','a','r','k') -# define c3__parq c3_s4('p','a','r','q') -# define c3__part c3_s4('p','a','r','t') -# define c3__pass c3_s4('p','a','s','s') -# define c3__past c3_s4('p','a','s','t') -# define c3__pawn c3_s4('p','a','w','n') -# define c3__peek c3_s4('p','e','e','k') -# define c3__peel c3_s4('p','e','e','l') -# define c3__peep c3_s4('p','e','e','p') -# define c3__peft c3_s4('p','e','f','t') -# define c3__peg c3_s3('p','e','g') -# define c3__peld c3_s4('p','e','l','d') -# define c3__pen c3_s3('p','e','n') -# define c3__per c3_s3('p','e','r') -# define c3__perd c3_s4('p','e','r','d') -# define c3__pesk c3_s4('p','e','s','k') -# define c3__pfix c3_s4('p','f','i','x') -# define c3__pick c3_s4('p','i','c','k') -# define c3__pier c3_s4('p','i','e','r') -# define c3__pike c3_s4('p','i','k','e') -# define c3__pile c3_s4('p','i','l','e') -# define c3__pill c3_s4('p','i','l','l') -# define c3__ping c3_s4('p','i','n','g') -# define c3__pink c3_s4('p','i','n','k') -# define c3__pip c3_s3('p','i','p') -# define c3__pipe c3_s4('p','i','p','e') -# define c3__pith c3_s4('p','i','t','h') -# define c3__pitt c3_s4('p','i','t','t') -# define c3__plac c3_s4('p','l','a','c') -# define c3__plam c3_s4('p','l','a','m') -# define c3__plat c3_s4('p','l','a','t') -# define c3__play c3_s4('p','l','a','y') -# define c3__plaz c3_s4('p','l','a','z') -# define c3__plem c3_s4('p','l','e','m') -# define c3__plet c3_s4('p','l','e','t') -# define c3__plic c3_s4('p','l','i','c') -# define c3__plin c3_s4('p','l','i','n') -# define c3__plom c3_s4('p','l','o','m') -# define c3__plov c3_s4('p','l','o','v') -# define c3__plug c3_s4('p','l','u','g') -# define c3__plus c3_s4('p','l','u','s') -# define c3__pmbn c3_s4('p','m','b','n') -# define c3__pmcl c3_s4('p','m','c','l') -# define c3__pmcn c3_s4('p','m','c','n') -# define c3__pmdg c3_s4('p','m','d','g') -# define c3__pmdp c3_s4('p','m','d','p') -# define c3__pmdt c3_s4('p','m','d','t') -# define c3__pmlc c3_s4('p','m','l','c') -# define c3__pmls c3_s4('p','m','l','s') -# define c3__pmms c3_s4('p','m','m','s') -# define c3__pmmt c3_s4('p','m','m','t') -# define c3__pmpd c3_s4('p','m','p','d') -# define c3__pmps c3_s4('p','m','p','s') -# define c3__pmsp c3_s4('p','m','s','p') -# define c3__pmtr c3_s4('p','m','t','r') -# define c3__pmts c3_s4('p','m','t','s') -# define c3__pmzp c3_s4('p','m','z','p') -# define c3__pnut c3_s4('p','n','u','t') -# define c3__pock c3_s4('p','o','c','k') -# define c3__poke c3_s4('p','o','k','e') -# define c3__poll c3_s4('p','o','l','l') -# define c3__poly c3_s4('p','o','l','y') -# define c3__pont c3_s4('p','o','n','t') -# define c3__poos c3_s4('p','o','o','s') -# define c3__pop c3_s3('p','o','p') -# define c3__port c3_s4('p','o','r','t') -# define c3__pos c3_s3('p','o','s') -# define c3__pose c3_s4('p','o','s','e') -# define c3__post c3_s4('p','o','s','t') -# define c3__pray c3_s4('p','r','a','y') -# define c3__prec c3_s4('p','r','e','c') -# define c3__prep c3_s4('p','r','e','p') -# define c3__pret c3_s4('p','r','e','t') -# define c3__prex c3_s4('p','r','e','x') -# define c3__pril c3_s4('p','r','i','l') -# define c3__pro c3_s3('p','r','o') -# define c3__prod c3_s4('p','r','o','d') -# define c3__prof c3_s4('p','r','o','f') -# define c3__prox c3_s4('p','r','o','x') -# define c3__psdg c3_s4('p','s','d','g') -# define c3__puck c3_s4('p','u','c','k') -# define c3__pull c3_s4('p','u','l','l') -# define c3__pult c3_s4('p','u','l','t') -# define c3__pung c3_s4('p','u','n','g') -# define c3__punk c3_s4('p','u','n','k') -# define c3__punt c3_s4('p','u','n','t') -# define c3__pure c3_s4('p','u','r','e') -# define c3__push c3_s4('p','u','s','h') -# define c3__put c3_s3('p','u','t') -# define c3__quac c3_s4('q','u','a','c') -# define c3__qual c3_s4('q','u','a','l') -# define c3__quat c3_s4('q','u','a','t') -# define c3__quax c3_s4('q','u','a','x') -# define c3__quem c3_s4('q','u','e','m') -# define c3__ques c3_s4('q','u','e','s') -# define c3__quet c3_s4('q','u','e','t') -# define c3__queu c3_s4('q','u','e','u') -# define c3__quid c3_s4('q','u','i','d') -# define c3__quil c3_s4('q','u','i','l') -# define c3__quix c3_s4('q','u','i','x') -# define c3__quiz c3_s4('q','u','i','z') -# define c3__quol c3_s4('q','u','o','l') -# define c3__quop c3_s4('q','u','o','p') -# define c3__rack c3_s4('r','a','c','k') -# define c3__rald c3_s4('r','a','l','d') -# define c3__ramp c3_s4('r','a','m','p') -# define c3__rasp c3_s4('r','a','s','p') -# define c3__raw c3_s3('r','a','w') -# define c3__read c3_s4('r','e','a','d') -# define c3__reck c3_s4('r','e','c','k') -# define c3__reef c3_s4('r','e','e','f') -# define c3__resd c3_s4('r','e','s','d') -# define c3__rest c3_s4('r','e','s','t') -# define c3__ret c3_s3('r','e','t') -# define c3__revo c3_s4('r','e','v','o') -# define c3__rez c3_s3('r','e','z') -# define c3__rin c3_s3('r','i','n') -# define c3__ring c3_s4('r','i','n','g') -# define c3__ripe c3_s4('r','i','p','e') -# define c3__rite c3_s4('r','i','t','e') -# define c3__rock c3_s4('r','o','c','k') -# define c3__roll c3_s4('r','o','l','l') -# define c3__rolp c3_s4('r','o','l','p') -# define c3__rond c3_s4('r','o','n','d') -# define c3__root c3_s4('r','o','o','t') -# define c3__rose c3_s4('r','o','s','e') -# define c3__rsh c3_s3('r','s','h') -# define c3__rulf c3_s4('r','u','l','f') -# define c3__run c3_s3('r','u','n') -# define c3__safe c3_s4('s','a','f','e') -# define c3__sag c3_s3('s','a','g') -# define c3__sail c3_s4('s','a','i','l') -# define c3__same c3_s4('s','a','m','e') -# define c3__sand c3_s4('s','a','n','d') -# define c3__sard c3_s4('s','a','r','d') -# define c3__sav c3_s3('s','a','v') -# define c3__save c3_s4('s','a','v','e') -# define c3__scam c3_s4('s','c','a','m') -# define c3__scan c3_s4('s','c','a','n') -# define c3__scry c3_s4('s','c','r','y') -# define c3__scsg c3_s4('s','c','s','g') -# define c3__seal c3_s4('s','e','a','l') -# define c3__seat c3_s4('s','e','a','t') -# define c3__see c3_s3('s','e','e') -# define c3__seed c3_s4('s','e','e','d') -# define c3__seek c3_s4('s','e','e','k') -# define c3__seft c3_s4('s','e','f','t') -# define c3__sell c3_s4('s','e','l','l') -# define c3__semp c3_s4('s','e','m','p') -# define c3__send c3_s4('s','e','n','d') -# define c3__seq c3_s3('s','e','q') -# define c3__serd c3_s4('s','e','r','d') -# define c3__serf c3_s4('s','e','r','f') -# define c3__set c3_s3('s','e','t') -# define c3__sfix c3_s4('s','f','i','x') -# define c3__sgbc c3_s4('s','g','b','c') -# define c3__sgbn c3_s4('s','g','b','n') -# define c3__sgbr c3_s4('s','g','b','r') -# define c3__sgcb c3_s4('s','g','c','b') -# define c3__sgcl c3_s4('s','g','c','l') -# define c3__sgcn c3_s4('s','g','c','n') -# define c3__sgdg c3_s4('s','g','d','g') -# define c3__sgdl c3_s4('s','g','d','l') -# 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') -# define c3__sghs c3_s4('s','g','h','s') -# define c3__sghx c3_s4('s','g','h','x') -# define c3__sgkt c3_s4('s','g','k','t') -# define c3__sglc c3_s4('s','g','l','c') -# define c3__sgld c3_s4('s','g','l','d') -# define c3__sgls c3_s4('s','g','l','s') -# define c3__sgms c3_s4('s','g','m','s') -# define c3__sgmt c3_s4('s','g','m','t') -# define c3__sgpd c3_s4('s','g','p','d') -# define c3__sgpm c3_s4('s','g','p','m') -# define c3__sgps c3_s4('s','g','p','s') -# 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__shiv c3_s4('s','h','i','v') -# define c3__show c3_s4('s','h','o','w') -# define c3__shud c3_s4('s','h','u','d') -# define c3__shut c3_s4('s','h','u','t') -# define c3__sibl c3_s4('s','i','b','l') -# define c3__sift c3_s4('s','i','f','t') -# define c3__sing c3_s4('s','i','n','g') -# define c3__sist c3_s4('s','i','s','t') -# define c3__site c3_s4('s','i','t','e') -# define c3__sith c3_s4('s','i','t','h') -# define c3__size c3_s4('s','i','z','e') -# define c3__slam c3_s4('s','l','a','m') -# define c3__slap c3_s4('s','l','a','p') -# define c3__slat c3_s4('s','l','a','t') -# define c3__slax c3_s4('s','l','a','x') -# define c3__slem c3_s4('s','l','e','m') -# define c3__slet c3_s4('s','l','e','t') -# define c3__slex c3_s4('s','l','e','x') -# define c3__slid c3_s4('s','l','i','d') -# define c3__slip c3_s4('s','l','i','p') -# define c3__sliv c3_s4('s','l','i','v') -# define c3__sloc c3_s4('s','l','o','c') -# define c3__slog c3_s4('s','l','o','g') -# define c3__slon c3_s4('s','l','o','n') -# define c3__slop c3_s4('s','l','o','p') -# define c3__slos c3_s4('s','l','o','s') -# define c3__slow c3_s4('s','l','o','w') -# define c3__slur c3_s4('s','l','u','r') -# define c3__slux c3_s4('s','l','u','x') -# define c3__sm c3_s2('s','m') -# 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') -# define c3__sock c3_s4('s','o','c','k') -# define c3__soft c3_s4('s','o','f','t') -# define c3__sole c3_s4('s','o','l','e') -# define c3__some c3_s4('s','o','m','e') -# define c3__sort c3_s4('s','o','r','t') -# define c3__spal c3_s4('s','p','a','l') -# define c3__spar c3_s4('s','p','a','r') -# define c3__spig c3_s4('s','p','i','g') -# define c3__spil c3_s4('s','p','i','l') -# define c3__spin c3_s4('s','p','i','n') -# define c3__spit c3_s4('s','p','i','t') -# define c3__spot c3_s4('s','p','o','t') -# define c3__stam c3_s4('s','t','a','m') -# define c3__star c3_s4('s','t','a','r') -# define c3__stdr c3_s4('s','t','d','r') -# define c3__stem c3_s4('s','t','e','m') -# define c3__step c3_s4('s','t','e','p') -# define c3__stid c3_s4('s','t','i','d') -# define c3__stig c3_s4('s','t','i','g') -# define c3__stil c3_s4('s','t','i','l') -# define c3__stiv c3_s4('s','t','i','v') -# define c3__stix c3_s4('s','t','i','x') -# define c3__stol c3_s4('s','t','o','l') -# define c3__ston c3_s4('s','t','o','n') -# define c3__stop c3_s4('s','t','o','p') -# define c3__stub c3_s4('s','t','u','b') -# define c3__stur c3_s4('s','t','u','r') -# define c3__sub c3_s3('s','u','b') -# define c3__sunt c3_s4('s','u','n','t') -# define c3__sure c3_s4('s','u','r','e') -# define c3__susp c3_s4('s','u','s','p') -# define c3__swap c3_s4('s','w','a','p') -# define c3__sym c3_s3('s','y','m') -# define c3__sync c3_s4('s','y','n','c') -# define c3__sys c3_s3('s','y','s') -# define c3__ta c3_s2('t','a') -# define c3__tab c3_s3('t','a','b') -# define c3__tack c3_s4('t','a','c','k') -# define c3__tag c3_s3('t','a','g') -# define c3__tail c3_s4('t','a','i','l') -# define c3__take c3_s4('t','a','k','e') -# define c3__talk c3_s4('t','a','l','k') -# define c3__tame c3_s4('t','a','m','e') -# define c3__tang c3_s4('t','a','n','g') -# define c3__tank c3_s4('t','a','n','k') -# define c3__tap c3_s3('t','a','p') -# define c3__tarn c3_s4('t','a','r','n') -# define c3__tas c3_s3('t','a','s') -# define c3__tash c3_s4('t','a','s','h') -# define c3__teal c3_s4('t','e','a','l') -# define c3__teck c3_s4('t','e','c','k') -# define c3__tell c3_s4('t','e','l','l') -# define c3__terg c3_s4('t','e','r','g') -# define c3__term c3_s4('t','e','r','m') -# define c3__test c3_s4('t','e','s','t') -# define c3__text c3_s4('t','e','x','t') -# define c3__tgbn c3_s4('t','g','b','n') -# define c3__tgbr c3_s4('t','g','b','r') -# define c3__tgdg c3_s4('t','g','d','g') -# define c3__tgdl c3_s4('t','g','d','l') -# define c3__tgdp c3_s4('t','g','d','p') -# define c3__tgdx c3_s4('t','g','d','x') -# define c3__tgkt c3_s4('t','g','k','t') -# define c3__tglc c3_s4('t','g','l','c') -# define c3__tgld c3_s4('t','g','l','d') -# define c3__tgmt c3_s4('t','g','m','t') -# define c3__tgpd c3_s4('t','g','p','d') -# define c3__tgpm c3_s4('t','g','p','m') -# define c3__tgps c3_s4('t','g','p','s') -# define c3__tgsp c3_s4('t','g','s','p') -# define c3__that c3_s4('t','h','a','t') -# define c3__thee c3_s4('t','h','e','e') -# define c3__then c3_s4('t','h','e','n') -# define c3__they c3_s4('t','h','e','y') -# define c3__thin c3_s4('t','h','i','n') -# define c3__this c3_s4('t','h','i','s') -# define c3__thou c3_s4('t','h','o','u') -# define c3__thud c3_s4('t','h','u','d') -# define c3__thuo c3_s4('t','h','u','o') -# define c3__thus c3_s4('t','h','u','s') -# define c3__tick c3_s4('t','i','c','k') -# define c3__time c3_s4('t','i','m','e') -# define c3__tip c3_s3('t','i','p') -# define c3__tmbn c3_s4('t','m','b','n') -# define c3__tmdg c3_s4('t','m','d','g') -# define c3__tmdp c3_s4('t','m','d','p') -# define c3__tmlc c3_s4('t','m','l','c') -# define c3__tmnp c3_s4('t','m','n','p') -# define c3__tmpd c3_s4('t','m','p','d') -# define c3__tmps c3_s4('t','m','p','s') -# define c3__tmsg c3_s4('t','m','s','g') -# define c3__tmsp c3_s4('t','m','s','p') -# define c3__tmtr c3_s4('t','m','t','r') -# define c3__to c3_s2('t','o') -# define c3__toe c3_s3('t','o','e') -# define c3__tome c3_s4('t','o','m','e') -# define c3__tong c3_s4('t','o','n','g') -# define c3__tool c3_s4('t','o','o','l') -# define c3__top c3_s3('t','o','p') -# define c3__toy c3_s3('t','o','y') -# define c3__trac c3_s4('t','r','a','c') -# define c3__tram c3_s4('t','r','a','m') -# define c3__trap c3_s4('t','r','a','p') -# define c3__trel c3_s4('t','r','e','l') -# define c3__trex c3_s4('t','r','e','x') -# define c3__trib c3_s4('t','r','i','b') -# define c3__trim c3_s4('t','r','i','m') -# define c3__trip c3_s4('t','r','i','p') -# define c3__trol c3_s4('t','r','o','l') -# 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__tsbn c3_s4('t','s','b','n') -# define c3__tsbr c3_s4('t','s','b','r') -# define c3__tscl c3_s4('t','s','c','l') -# define c3__tscm c3_s4('t','s','c','m') -# 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__tshx c3_s4('t','s','h','x') -# 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') -# define c3__tule c3_s4('t','u','l','e') -# define c3__tulp c3_s4('t','u','l','p') -# define c3__tune c3_s4('t','u','n','e') -# define c3__tung c3_s4('t','u','n','g') -# define c3__tupl c3_s4('t','u','p','l') -# define c3__turd c3_s4('t','u','r','d') -# define c3__turf c3_s4('t','u','r','f') -# define c3__turn c3_s4('t','u','r','n') -# define c3__twig c3_s4('t','w','i','g') -# define c3__twix c3_s4('t','w','i','x') -# define c3__txt c3_s3('t','x','t') -# define c3__type c3_s4('t','y','p','e') -# define c3__u c3_s1('u') -# define c3__ubin c3_s4('u','b','i','n') -# define c3__ubit c3_s4('u','b','i','t') -# define c3__ud c3_s2('u','d') -# define c3__ulib c3_s4('u','l','i','b') -# define c3__un c3_s2('u','n') -# define c3__uniq c3_s4('u','n','i','q') -# define c3__unix c3_s4('u','n','i','x') -# define c3__unt c3_s3('u','n','t') -# define c3__up c3_s2('u','p') -# define c3__url c3_s3('u','r','l') -# define c3__urth c3_s4('u','r','t','h') -# define c3__use c3_s3('u','s','e') -# define c3__ut c3_s2('u','t') -# 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') -# define c3__veal c3_s4('v','e','a','l') -# define c3__veb c3_s3('v','e','b') -# define c3__veck c3_s4('v','e','c','k') -# define c3__veer c3_s4('v','e','e','r') -# define c3__vega c3_s4('v','e','g','a') -# define c3__velt c3_s4('v','e','l','t') -# define c3__vent c3_s4('v','e','n','t') -# define c3__verb c3_s4('v','e','r','b') -# define c3__vere c3_s4('v','e','r','e') -# define c3__vern c3_s4('v','e','r','n') -# define c3__very c3_s4('v','e','r','y') -# define c3__view c3_s4('v','i','e','w') -# define c3__vile c3_s4('v','i','l', 'e') -# define c3__vint c3_s4('v','i','n','t') -# define c3__void c3_s4('v','o','i','d') -# define c3__vorp c3_s4('v','o','r','p') -# define c3__wack c3_s4('w','a','c','k') -# define c3__wail c3_s4('w','a','i','l') -# define c3__wake c3_s4('w','a','k','e') -# define c3__walk c3_s4('w','a','l','k') -# define c3__wamp c3_s4('w','a','m','p') -# define c3__want c3_s4('w','a','n','t') -# define c3__warm c3_s4('w','a','r','m') -# define c3__warn c3_s4('w','a','r','n') -# define c3__warx c3_s4('w','a','r','x') -# define c3__wash c3_s4('w','a','s','h') -# define c3__watt c3_s4('w','a','t','t') -# define c3__way c3_s3('w','a','y') -# define c3__weak c3_s4('w','e','a','k') -# define c3__web c3_s3('w','e','b') -# define c3__wend c3_s4('w','e','n','d') -# define c3__werp c3_s4('w','e','r','p') -# define c3__west c3_s4('w','e','s','t') -# define c3__wet c3_s3('w','e','t') -# define c3__what c3_s4('w','h','a','t') -# define c3__whey c3_s4('w','h','e','y') -# define c3__who c3_s3('w','h','o') -# define c3__whom c3_s4('w','h','o','m') -# define c3__wild c3_s4('w','i','l','d') -# define c3__win c3_s3('w','i','n') -# define c3__wing c3_s4('w','i','n','g') -# define c3__wipe c3_s4('w','i','p','e') -# define c3__wise c3_s4('w','i','s','e') -# define c3__wish c3_s4('w','i','s','h') -# define c3__with c3_s4('w','i','t','h') -# define c3__wnut c3_s4('w','n','u','t') -# define c3__wood c3_s4('w','o','o','d') -# define c3__woot c3_s4('w','o','o','t') -# define c3__work c3_s4('w','o','r','k') -# define c3__wost c3_s4('w','o','s','t') -# define c3__wrap c3_s4('w','r','a','p') -# define c3__wtbr c3_s4('w','t','b','r') -# define c3__wtcb c3_s4('w','t','c','b') -# define c3__wtcl c3_s4('w','t','c','l') -# define c3__wtcn c3_s4('w','t','c','n') -# define c3__wtdt c3_s4('w','t','d','t') -# define c3__wtfs c3_s4('w','t','f','s') -# define c3__wtgl c3_s4('w','t','g','l') -# 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') -# define c3__wyp c3_s3('w','y','p') -# define c3__wyrd c3_s4('w','y','r','d') -# define c3__xray c3_s4('x','r','a','y') -# define c3__yell c3_s4('y','e','l','l') -# define c3__yelp c3_s4('y','e','l','p') -# define c3__z c3_s1('z') -# define c3__zact c3_s4('z','a','c','t') -# define c3__zalt c3_s4('z','a','l','t') -# define c3__zarb c3_s4('z','a','r','b') -# define c3__zect c3_s4('z','e','c','t') -# define c3__zemp c3_s4('z','e','m','p') -# define c3__zero c3_s4('z','e','r','o') -# define c3__zike c3_s4('z','i','k','e') -# define c3__zinc c3_s4('z','i','n','c') -# define c3__zole c3_s4('z','o','l','e') -# define c3__zond c3_s4('z','o','n','d') -# define c3__zoot c3_s4('z','o','o','t') -# define c3__zork c3_s4('z','o','r','k') -# define c3__zpbn c3_s4('z','p','b','n') -# define c3__zpcb c3_s4('z','p','c','b') -# define c3__zpcm c3_s4('z','p','c','m') -# define c3__zpcn c3_s4('z','p','c','n') -# 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__zphx c3_s4('z','p','h','x') -# define c3__zplc c3_s4('z','p','l','c') -# define c3__zpmc c3_s4('z','p','m','c') -# define c3__zpmt c3_s4('z','p','m','t') -# define c3__zpsg c3_s4('z','p','s','g') -# define c3__zpsk c3_s4('z','p','s','k') -# define c3__zpsm c3_s4('z','p','s','m') -# define c3__zptc c3_s4('z','p','t','c') -# define c3__zptm c3_s4('z','p','t','m') -# define c3__zpts c3_s4('z','p','t','s') -# define c3__zpvn c3_s4('z','p','v','n') -# define c3__zpvt c3_s4('z','p','v','t') -# define c3__zpzp c3_s4('z','p','z','p') -# define c3__zuse c3_s4('z','u','s','e') -# define c3__zush c3_s4('z','u','s','h') - -#endif /* ifndef C3_MOTES_H */ diff --git a/pkg/urbit/include/c/portable.h b/pkg/urbit/include/c/portable.h deleted file mode 100644 index 671db4d06..000000000 --- a/pkg/urbit/include/c/portable.h +++ /dev/null @@ -1,286 +0,0 @@ -#ifndef C3_PORTABLE_H -#define C3_PORTABLE_H - -#include "config.h" - -# ifndef __GNUC__ -# error "port me" -# endif -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# endif - - - /** System include files. - *** - *** Do not put include files that are only used in the - *** porting layer here. Include them directly in the - *** C file. - **/ -# if defined(U3_OS_linux) -# ifndef _XOPEN_SOURCE -# define _XOPEN_SOURCE 700 -# endif -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include - -# elif defined(U3_OS_osx) -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include - -# elif defined(U3_OS_bsd) -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include - -# elif defined(U3_OS_mingw) -# define signal mingw_has_no_usable_signal -# define raise mingw_has_no_usable_raise -# define _POSIX -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include "mman.h" -# include "compat.h" - -# else - #error "port: headers" -# endif - -# ifndef __has_feature -# define __has_feature(x) 0 -# endif - -# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) -# define ASAN_ENABLED -# endif - - /** Platform string. - **/ -# if defined(U3_OS_linux) -# ifdef __LP64__ -# ifdef U3_CPU_aarch64 -# define U3_OS_ARCH "aarch64-linux" -# else -# define U3_OS_ARCH "x86_64-linux" -# endif -# endif -# elif defined(U3_OS_mingw) -# define U3_OS_ARCH "x86_64-windows" -# elif defined(U3_OS_osx) -# ifdef __LP64__ -# ifdef U3_CPU_aarch64 -// XX not yet -//# define U3_OS_ARCH "aarch64-darwin" -# else -# define U3_OS_ARCH "x86_64-darwin" -# endif -# endif -# endif - - /** Binary alias. - **/ -# ifdef U3_OS_mingw -# define U3_BIN_SUFFIX ".exe" -# else -# define U3_BIN_SUFFIX "" -# endif - - - -# define U3_BIN_ALIAS ".run" U3_BIN_SUFFIX - - /** Address space layout. - *** - *** NB: 2^29 words == 2GB - **/ -# if defined(U3_OS_linux) -# ifdef __LP64__ -# ifdef ASAN_ENABLED -# define U3_OS_LoomBase 0x10007ffff000 -# else -# define U3_OS_LoomBase 0x200000000 -# endif -# else -# define U3_OS_LoomBase 0x36000000 -# endif -# define U3_OS_LoomBits 30 -# elif defined(U3_OS_mingw) -# define U3_OS_LoomBase 0x28000000000 -# define U3_OS_LoomBits 30 -# elif defined(U3_OS_osx) -# ifdef __LP64__ -# define U3_OS_LoomBase 0x28000000000 -# else -# define U3_OS_LoomBase 0x4000000 -# endif -# define U3_OS_LoomBits 30 -# elif defined(U3_OS_bsd) -# ifdef __LP64__ -# define U3_OS_LoomBase 0x200000000 -# else -# define U3_OS_LoomBase 0x4000000 -# endif -# define U3_OS_LoomBits 30 -# else -# error "port: LoomBase" -# endif - - /** Global variable control. - *** - *** To instantiate globals, #define c3_global as extern. - **/ -# ifndef c3_global -# define c3_global -# endif - - - /** External, OS-independent library dependencies. - **/ - /* The GMP (GNU arbitrary-precision arithmetic) library. - ** (Tested with version 4.0.1.) - */ -# include - - - /** Private C "extensions." - *** - *** Except for these and main(), any function, macro, or structure - *** names must be prefixed either by u3_/U3_ (for public names), - *** or _ (for static and other file-local names). - **/ - /* Endianness. - */ -# define c3_endian_little 0 -# define c3_endian_big 1 - -# ifdef U3_OS_ENDIAN_little -# define c3_endian c3_endian_little -# elif defined(U3_OS_ENDIAN_big) -# define c3_endian c3_endian_big -# else -# error "port: U3_OS_ENDIAN" -# endif - - /* Byte swapping. - */ -# if defined(U3_OS_linux) || defined(U3_OS_bsd) || defined(U3_OS_mingw) -# define c3_bswap_16(x) bswap_16(x) -# define c3_bswap_32(x) bswap_32(x) -# define c3_bswap_64(x) bswap_64(x) -# elif defined(U3_OS_osx) -# define c3_bswap_16(x) NXSwapShort(x) -# define c3_bswap_32(x) NXSwapInt(x) -# define c3_bswap_64(x) NXSwapLongLong(x) -# else -# error "port: byte swap" -# endif - - /* Sync. - */ -# if defined(U3_OS_linux) || defined(U3_OS_mingw) -# define c3_sync(fd) (fdatasync(fd)) -# elif defined(U3_OS_osx) -# define c3_sync(fd) (fcntl(fd, F_FULLFSYNC, 0)) -# elif defined(U3_OS_bsd) -# define c3_sync(fd) (fsync(fd)) -# else -# error "port: sync" -# endif - - /* Purge. - */ -# if defined(U3_OS_linux) -# include -# define c3_fpurge __fpurge -# elif defined(U3_OS_bsd) || defined(U3_OS_osx) || defined(U3_OS_mingw) -# define c3_fpurge fpurge -# else -# error "port: fpurge" -# endif - - /* Stat. - */ -# if defined(U3_OS_linux) || defined(U3_OS_mingw) -# define c3_stat_mtime(dp) (u3_time_t_in_ts((dp)->st_mtime)) -# elif defined(U3_OS_osx) -# define c3_stat_mtime(dp) (u3_time_in_ts(&((dp)->st_mtimespec))) -# define lseek64 lseek -# elif defined(U3_OS_bsd) -# define c3_stat_mtime(dp) (u3_time_in_ts(&((dp)->st_mtim))) -# define lseek64 lseek -# else -# error "port: timeconvert" -# endif - - /* Null. - */ -# if defined(U3_OS_linux) || defined(U3_OS_bsd) || defined(U3_OS_osx) -# define c3_dev_null "/dev/null" -# elif defined(U3_OS_mingw) -# define c3_dev_null "nul" -# else -# error "port: /dev/null" -# endif - - /* Static assertion. - */ -# define ASSERT_CONCAT_(a, b) a##b -# define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b) -# define STATIC_ASSERT(e,m) \ - ;enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(int)(!!(e)) } - -#endif /* ifndef C3_PORTABLE_H */ diff --git a/pkg/urbit/include/c/types.h b/pkg/urbit/include/c/types.h deleted file mode 100644 index b333ff115..000000000 --- a/pkg/urbit/include/c/types.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef C3_TYPES_H -#define C3_TYPES_H - - /** Integer typedefs. - **/ - /* Canonical integers. - */ - typedef uint64_t c3_d; - typedef int64_t c3_ds; - typedef uint32_t c3_w; - typedef int32_t c3_ws; - typedef uint16_t c3_s; - typedef int16_t c3_ss; - typedef uint8_t c3_y; // byte - typedef int8_t c3_ys; // signed byte - typedef uint8_t c3_b; // bit - - typedef uint8_t c3_t; // boolean - typedef uint8_t c3_o; // loobean - typedef uint8_t c3_g; // 32-bit log - 0-31 bits - typedef uint32_t c3_l; // little; 31-bit unsigned integer - typedef uint32_t c3_m; // mote; also c3_l; LSB first a-z 4-char string. - - /* Deprecated integers. - */ - typedef char c3_c; // does not match int8_t or uint8_t - typedef int c3_i; // int - really bad - typedef uintptr_t c3_p; // pointer-length uint - really really bad - typedef intptr_t c3_ps; // pointer-length int - really really bad - -#endif /* ifndef C3_TYPES_H */ diff --git a/pkg/urbit/include/jets/k.h b/pkg/urbit/include/jets/k.h deleted file mode 100644 index f8cce61cf..000000000 --- a/pkg/urbit/include/jets/k.h +++ /dev/null @@ -1,164 +0,0 @@ -#ifndef U3_JETS_K_H -#define U3_JETS_K_H - - /** Tier 1. - **/ - u3_noun u3ka_add(u3_noun a, u3_noun b); - u3_noun u3ka_dec(u3_atom a); - u3_noun u3ka_div(u3_noun a, u3_noun b); - u3_noun u3ka_sub(u3_noun a, u3_noun b); - u3_noun u3ka_mod(u3_noun a, u3_noun b); - u3_noun u3ka_mul(u3_noun a, u3_noun b); - u3_noun u3ka_gth(u3_noun a, u3_noun b); - u3_noun u3ka_lte(u3_noun a, u3_noun b); - - /** Tier 2. - **/ - u3_noun u3kb_lent(u3_noun a); - u3_noun u3kb_weld(u3_noun a, u3_noun b); - u3_noun u3kb_flop(u3_noun a); - -/* u3kc: tier 3 functions -*/ - /* u3kc_bex(): binary exponent. - */ - u3_noun - u3kc_bex(u3_atom); - - /* u3kc_con(): binary loobean conjunction. - */ - u3_noun - u3kc_con(u3_noun a, - u3_noun b); - - /* u3kc_mix(): binary xor. - */ - u3_noun - u3kc_mix(u3_atom a, u3_atom b); - - /* u3kc_lsh(): left shift. - */ - u3_noun - u3kc_lsh(u3_noun a, u3_noun b, u3_noun c); - - /* u3kc_rsh(): right shift. - */ - u3_noun - u3kc_rsh(u3_noun a, u3_noun b, u3_noun c); - - /* u3kc_rep(): assemble single. - */ - u3_noun - u3kc_rep(u3_atom a, - u3_atom b, - u3_noun c); - - /* u3kc_rip(): disassemble. - */ - u3_noun - u3kc_rip(u3_atom a, - u3_atom b, - u3_atom c); - - /* u3kc_rev(): reverse block order, accounting for leading zeroes. - */ - u3_noun - u3kc_rev(u3_atom boz, u3_atom len, u3_atom dat); - - /* u3kc_swp(): reverse block order. - */ - u3_noun - u3kc_swp(u3_atom a, u3_atom b); - -/* u3kd: tier 4 functions -*/ - /* u3kdb_get(): map get for key `b` in map `a` with u3_none. - */ - u3_weak - u3kdb_get(u3_noun a, u3_noun b); - - /* u3kdb_got(): map get for key `b` in map `a` with bail. - */ - u3_noun - u3kdb_got(u3_noun a, u3_noun b); - - /* u3kdb_put(): map put for key `b`, value `c` in map `a`. - */ - u3_weak - u3kdb_put(u3_noun a, u3_noun b, u3_noun c); - - /* u3kdb_has(): test for get. - */ - u3_noun - u3kdb_has(u3_noun a, u3_noun b); - - /* u3kdb_gas(): list to map. - */ - u3_noun - u3kdb_gas(u3_noun a, u3_noun b); - - /* u3kdb_uni(): map union. - */ - u3_noun - u3kdb_uni(u3_noun a, u3_noun b); - - /* u3kdi_gas(): list to map. - */ - u3_noun - u3kdi_gas(u3_noun a, u3_noun b); - - /* u3kdi_has(): test for presence. - */ - u3_noun - u3kdi_has(u3_noun a, u3_noun b); - - /* u3kdi_tap(): map/set convert to list. (solves by_tap also.) - */ - u3_noun - u3kdi_tap(u3_noun a); - - /* u3kdi_put(): put in set. - */ - u3_weak - u3kdi_put(u3_noun a, u3_noun b); - - /* u3kdi_uni(): set union. - */ - u3_noun - u3kdi_uni(u3_noun a, u3_noun b); - -# define u3kdb_tap(a) u3kdi_tap(a) - -/* u3ke: tier 5 functions -*/ - /* u3ke_cue(): expand saved pill. - */ - u3_noun - u3ke_cue(u3_atom a); - - /* u3ke_jam(): pack noun as atom. - */ - u3_atom - u3ke_jam(u3_noun a); - - /* u3ke_trip(): atom to tape. - */ - u3_noun - u3ke_trip(u3_noun a); - - /* u3kf_fork(): build %fork span. - */ - u3_noun - u3kf_fork(u3_noun yed); - - /* u3kz_fork(): build %fork span. - */ - u3_noun - u3kz_fork(u3_noun yed); - - /* u3kfu_repo(): - */ - u3_noun - u3kfu_repo(u3_noun, u3_noun); - -#endif /* ifndef U3_JETS_K_H */ diff --git a/pkg/urbit/include/jets/q.h b/pkg/urbit/include/jets/q.h deleted file mode 100644 index 305164fb8..000000000 --- a/pkg/urbit/include/jets/q.h +++ /dev/null @@ -1,244 +0,0 @@ -#ifndef U3_JETS_Q_H -#define U3_JETS_Q_H - - /** Tier 1. - **/ - u3_noun u3qa_add(u3_atom, u3_atom); - u3_noun u3qa_dec(u3_atom); - u3_noun u3qa_div(u3_atom, u3_atom); - u3_noun u3qa_gte(u3_atom, u3_atom); - u3_noun u3qa_gth(u3_atom, u3_atom); - u3_noun u3qa_inc(u3_atom); - u3_noun u3qa_lte(u3_atom, u3_atom); - u3_noun u3qa_lth(u3_atom, u3_atom); - u3_noun u3qa_mod(u3_atom, u3_atom); - u3_noun u3qa_mul(u3_atom, u3_atom); - u3_noun u3qa_sub(u3_atom, u3_atom); - - /** Tier 2. - **/ - u3_noun u3qb_bind(u3_noun, u3_noun); - u3_noun u3qb_clap(u3_noun, u3_noun, u3_noun); - u3_noun u3qb_drop(u3_noun); - u3_noun u3qb_flop(u3_noun); - u3_noun u3qb_lent(u3_noun); - u3_noun u3qb_levy(u3_noun, u3_noun); - u3_noun u3qb_lien(u3_noun, u3_noun); - u3_noun u3qb_murn(u3_noun, u3_noun); - u3_noun u3qb_need(u3_noun); - u3_noun u3qb_reap(u3_atom, u3_noun); - u3_noun u3qb_reel(u3_noun, u3_noun); - u3_noun u3qb_roll(u3_noun, u3_noun); - u3_noun u3qb_skid(u3_noun, u3_noun); - u3_noun u3qb_skim(u3_noun, u3_noun); - u3_noun u3qb_skip(u3_noun, u3_noun); - u3_noun u3qb_scag(u3_atom, u3_noun); - u3_noun u3qb_slag(u3_atom, u3_noun); - u3_noun u3qb_snag(u3_atom, u3_noun); - u3_noun u3qb_sort(u3_noun, u3_noun); - u3_noun u3qb_turn(u3_noun, u3_noun); - u3_noun u3qb_weld(u3_noun, u3_noun); - - /** Tier 3. - **/ - u3_noun u3qc_bex(u3_atom); - u3_noun u3qc_xeb(u3_atom); - u3_noun u3qc_can(u3_atom, u3_noun); - u3_noun u3qc_cap(u3_atom); - u3_noun u3qc_cat(u3_atom, u3_atom, u3_atom); - u3_noun u3qc_con(u3_atom, u3_atom); - u3_noun u3qc_cut(u3_atom, u3_atom, u3_atom, u3_atom); - u3_noun u3qc_dis(u3_atom, u3_atom); - u3_noun u3qc_dor(u3_atom, u3_atom); - u3_noun u3qc_dvr(u3_atom, u3_atom); - u3_noun u3qc_end(u3_atom, u3_atom, u3_atom); - u3_noun u3qc_gor(u3_atom, u3_atom); - u3_noun u3qc_lsh(u3_atom, u3_atom, u3_atom); - u3_noun u3qc_mas(u3_atom); - u3_noun u3qc_met(u3_atom, u3_atom); - u3_noun u3qc_mix(u3_atom, u3_atom); - u3_noun u3qc_mor(u3_atom, u3_atom); - u3_noun u3qc_muk(u3_atom, u3_atom, u3_atom); - u3_noun u3qc_peg(u3_atom, u3_atom); - u3_noun u3qc_pow(u3_atom, u3_atom); - u3_noun u3qc_rap(u3_atom, u3_noun); - u3_noun u3qc_rep(u3_atom, u3_atom, u3_noun); - u3_noun u3qc_rev(u3_atom, u3_atom, u3_atom); - u3_noun u3qc_rip(u3_atom, u3_atom, u3_atom); - u3_noun u3qc_rsh(u3_atom, u3_atom, u3_atom); - u3_noun u3qc_swp(u3_atom, u3_atom); - u3_noun u3qc_sqt(u3_atom); - - u3_noun u3_po_find_prefix(c3_y one, c3_y two, c3_y three); - u3_noun u3_po_find_suffix(c3_y one, c3_y two, c3_y three); - void u3_po_to_prefix(u3_noun id, c3_y* a, c3_y* b, c3_y* c); - void u3_po_to_suffix(u3_noun id, c3_y* a, c3_y* b, c3_y* c); - - /** Tier 4. - **/ - u3_noun u3qdb_all(u3_noun, u3_noun); - u3_noun u3qdb_any(u3_noun, u3_noun); - u3_noun u3qdb_apt(u3_noun); - u3_noun u3qdb_bif(u3_noun, u3_noun); - u3_noun u3qdb_dif(u3_noun, u3_noun); - u3_noun u3qdb_gas(u3_noun, u3_noun); - u3_noun u3qdb_get(u3_noun, u3_noun); - u3_noun u3qdb_has(u3_noun, u3_noun); - u3_noun u3qdb_int(u3_noun, u3_noun); - u3_noun u3qdb_key(u3_noun); - u3_noun u3qdb_put(u3_noun, u3_noun, u3_noun); - u3_noun u3qdb_run(u3_noun, u3_noun); -# define u3qdb_tap u3qdi_tap - u3_noun u3qdb_uni(u3_noun, u3_noun); - u3_noun u3qdb_urn(u3_noun, u3_noun); -# define u3qdb_wyt u3qdi_wyt - - u3_noun u3qdi_apt(u3_noun); - u3_noun u3qdi_bif(u3_noun, u3_noun); - u3_noun u3qdi_dif(u3_noun, u3_noun); - u3_noun u3qdi_gas(u3_noun, u3_noun); - u3_noun u3qdi_has(u3_noun, u3_noun); - u3_noun u3qdi_int(u3_noun, u3_noun); - u3_noun u3qdi_put(u3_noun, u3_noun); - u3_noun u3qdi_rep(u3_noun, u3_noun); - u3_noun u3qdi_run(u3_noun, u3_noun); - u3_noun u3qdi_tap(u3_noun); - u3_noun u3qdi_uni(u3_noun, u3_noun); - u3_noun u3qdi_wyt(u3_noun); - - /** Tier 5. - **/ - u3_noun u3qe_cue(u3_atom); - u3_noun u3qe_jam(u3_atom); - u3_noun u3qe_mat(u3_atom); - u3_noun u3qe_rub(u3_atom, u3_atom); - u3_noun u3qe_leer(u3_atom); - u3_noun u3qe_lore(u3_atom); - u3_noun u3qe_loss(u3_noun, u3_noun); - u3_noun u3qe_lune(u3_atom); - u3_noun u3qe_repg(u3_noun, u3_noun, u3_noun); - u3_noun u3qe_rexp(u3_noun, u3_noun); - u3_noun u3qe_trip(u3_atom); - - u3_noun u3qea_ecba_en(u3_atom, u3_atom); - u3_noun u3qea_ecba_de(u3_atom, u3_atom); - u3_noun u3qea_ecbb_en(u3_atom, u3_atom); - u3_noun u3qea_ecbb_de(u3_atom, u3_atom); - u3_noun u3qea_ecbc_en(u3_atom, u3_atom); - u3_noun u3qea_ecbc_de(u3_atom, u3_atom); - - u3_noun u3qea_cbca_en(u3_atom, u3_atom, u3_atom); - u3_noun u3qea_cbca_de(u3_atom, u3_atom, u3_atom); - u3_noun u3qea_cbcb_en(u3_atom, u3_atom, u3_atom); - u3_noun u3qea_cbcb_de(u3_atom, u3_atom, u3_atom); - u3_noun u3qea_cbcc_en(u3_atom, u3_atom, u3_atom); - u3_noun u3qea_cbcc_de(u3_atom, u3_atom, u3_atom); - - u3_noun u3qea_de(u3_atom, u3_atom); - u3_noun u3qea_en(u3_atom, u3_atom); - - u3_atom u3qe_fein_ob(u3_atom pyn); - u3_atom u3qe_fynd_ob(u3_atom pyn); - - u3_noun u3qe_hmac(u3_noun, u3_atom, u3_atom, - u3_atom, u3_atom, u3_atom, u3_atom); - - u3_noun u3qe_en_base16(u3_atom len, u3_atom dat); - u3_noun u3qe_de_base16(u3_atom inp); - - u3_noun u3qeo_raw(u3_atom, u3_atom); - - u3_noun u3qef_drg(u3_noun, u3_atom); - u3_noun u3qef_lug(u3_noun, u3_noun, u3_atom, u3_atom); - - u3_noun u3qer_add(u3_atom, u3_atom, u3_atom); - u3_noun u3qer_sub(u3_atom, u3_atom, u3_atom); - u3_noun u3qer_mul(u3_atom, u3_atom, u3_atom); - u3_noun u3qer_div(u3_atom, u3_atom, u3_atom); - u3_noun u3qer_sqt(u3_atom, u3_atom); - u3_noun u3qer_fma(u3_atom, u3_atom, u3_atom, u3_atom); - u3_noun u3qer_lth(u3_atom, u3_atom); - u3_noun u3qer_lte(u3_atom, u3_atom); - u3_noun u3qer_equ(u3_atom, u3_atom); - u3_noun u3qer_gte(u3_atom, u3_atom); - u3_noun u3qer_gth(u3_atom, u3_atom); - - u3_noun u3qet_add(u3_atom, u3_atom, u3_atom); - u3_noun u3qet_sub(u3_atom, u3_atom, u3_atom); - u3_noun u3qet_mul(u3_atom, u3_atom, u3_atom); - u3_noun u3qet_div(u3_atom, u3_atom, u3_atom); - u3_noun u3qet_sqt(u3_atom, u3_atom); - u3_noun u3qet_fma(u3_atom, u3_atom, u3_atom, u3_atom); - u3_noun u3qet_lth(u3_atom, u3_atom); - u3_noun u3qet_lte(u3_atom, u3_atom); - u3_noun u3qet_equ(u3_atom, u3_atom); - u3_noun u3qet_gte(u3_atom, u3_atom); - u3_noun u3qet_gth(u3_atom, u3_atom); - - u3_noun u3qeq_add(u3_atom, u3_atom, u3_atom); - u3_noun u3qeq_sub(u3_atom, u3_atom, u3_atom); - u3_noun u3qeq_mul(u3_atom, u3_atom, u3_atom); - u3_noun u3qeq_div(u3_atom, u3_atom, u3_atom); - u3_noun u3qeq_sqt(u3_atom, u3_atom); - u3_noun u3qeq_fma(u3_atom, u3_atom, u3_atom, u3_atom); - u3_noun u3qeq_lth(u3_atom, u3_atom); - u3_noun u3qeq_lte(u3_atom, u3_atom); - u3_noun u3qeq_equ(u3_atom, u3_atom); - u3_noun u3qeq_gte(u3_atom, u3_atom); - u3_noun u3qeq_gth(u3_atom, u3_atom); - - u3_noun u3qes_add(u3_atom, u3_atom, u3_atom); - u3_noun u3qes_sub(u3_atom, u3_atom, u3_atom); - u3_noun u3qes_mul(u3_atom, u3_atom, u3_atom); - u3_noun u3qes_div(u3_atom, u3_atom, u3_atom); - u3_noun u3qes_sqt(u3_atom, u3_atom); - u3_noun u3qes_fma(u3_atom, u3_atom, u3_atom, u3_atom); - u3_noun u3qes_lth(u3_atom, u3_atom); - u3_noun u3qes_lte(u3_atom, u3_atom); - u3_noun u3qes_equ(u3_atom, u3_atom); - u3_noun u3qes_gte(u3_atom, u3_atom); - u3_noun u3qes_gth(u3_atom, u3_atom); - - /** Tier 6. - **/ - u3_noun u3qf_bull(u3_noun, u3_noun); - u3_noun u3qf_cell(u3_noun, u3_noun); - u3_noun u3qf_comb(u3_noun, u3_noun); - u3_noun u3qf_cons(u3_noun, u3_noun); - u3_noun u3qf_core(u3_noun, u3_noun); - u3_noun u3qf_cube(u3_noun, u3_noun); - u3_noun u3qf_face(u3_noun, u3_noun); - u3_noun u3qf_fine(u3_noun, u3_noun, u3_noun); - u3_noun u3qf_fitz(u3_noun, u3_noun); - u3_noun u3qf_flan(u3_noun, u3_noun); - u3_noun u3qf_flay(u3_noun); - u3_noun u3qf_flip(u3_noun); - u3_noun u3qf_flor(u3_noun, u3_noun); - u3_noun u3qf_forq(u3_noun, u3_noun); - u3_noun u3qf_fork(u3_noun); - u3_noun u3qf_grof(u3_noun); - u3_noun u3qf_hint(u3_noun, u3_noun); - u3_noun u3qf_hike(u3_noun, u3_noun); - u3_noun u3qf_look(u3_noun, u3_noun); - u3_noun u3qf_loot(u3_noun, u3_noun); - u3_noun u3qf_slot(u3_atom, u3_noun); - u3_noun u3qf_type(u3_noun); - - u3_noun u3qfl_bunt(u3_noun, u3_noun); - u3_noun u3qfl_whip(u3_noun, u3_noun, u3_noun); - - u3_noun u3qfr_fish(u3_noun, u3_noun, u3_noun, u3_noun); - - u3_noun u3qfp_hack(u3_noun, u3_noun); - u3_noun u3qfp_late(u3_noun); - u3_noun u3qfp_open(u3_noun, u3_noun, u3_noun); - u3_noun u3qfp_nepo(u3_noun, u3_noun); - u3_noun u3qfp_rake(u3_noun); - -# define u3qfu_van_fan 28 -# define u3qfu_van_rib 58 -# define u3qfu_van_vet 59 - - void u3qf_test(const c3_c*, u3_noun); - -#endif /* ifndef U3_JETS_Q_H */ diff --git a/pkg/urbit/include/jets/w.h b/pkg/urbit/include/jets/w.h deleted file mode 100644 index ec66d96b3..000000000 --- a/pkg/urbit/include/jets/w.h +++ /dev/null @@ -1,324 +0,0 @@ -#ifndef U3_JETS_W_H -#define U3_JETS_W_H - - /** Tier 1. - **/ - u3_noun u3wa_add(u3_noun); - u3_noun u3wa_dec(u3_noun); - u3_noun u3wa_div(u3_noun); - u3_noun u3wa_gte(u3_noun); - u3_noun u3wa_gth(u3_noun); - u3_noun u3wa_lte(u3_noun); - u3_noun u3wa_lth(u3_noun); - u3_noun u3wa_mod(u3_noun); - u3_noun u3wa_mul(u3_noun); - u3_noun u3wa_sub(u3_noun); - - /** Tier 2. - **/ - u3_noun u3wb_bind(u3_noun); - u3_noun u3wb_clap(u3_noun); - u3_noun u3wb_drop(u3_noun); - u3_noun u3wb_find(u3_noun); - u3_noun u3wb_flop(u3_noun); - u3_noun u3wb_lent(u3_noun); - u3_noun u3wb_levy(u3_noun); - u3_noun u3wb_lien(u3_noun); - u3_noun u3wb_murn(u3_noun); - u3_noun u3wb_need(u3_noun); - u3_noun u3wb_reap(u3_noun); - u3_noun u3wb_reel(u3_noun); - u3_noun u3wb_roll(u3_noun); - u3_noun u3wb_skid(u3_noun); - u3_noun u3wb_skim(u3_noun); - u3_noun u3wb_skip(u3_noun); - u3_noun u3wb_scag(u3_noun); - u3_noun u3wb_slag(u3_noun); - u3_noun u3wb_snag(u3_noun); - u3_noun u3wb_sort(u3_noun); - u3_noun u3wb_turn(u3_noun); - u3_noun u3wb_weld(u3_noun); -# define u3wb_welp u3wb_weld - u3_noun u3wb_zing(u3_noun); - - /** Tier 3. - **/ - u3_noun u3wc_bex(u3_noun); - u3_noun u3wc_xeb(u3_noun); - u3_noun u3wc_can(u3_noun); - u3_noun u3wc_cap(u3_noun); - u3_noun u3wc_cat(u3_noun); - u3_noun u3wc_con(u3_noun); - u3_noun u3wc_cut(u3_noun); - u3_noun u3wc_dis(u3_noun); - u3_noun u3wc_dor(u3_noun); - u3_noun u3wc_dvr(u3_noun); - u3_noun u3wc_end(u3_noun); - u3_noun u3wc_gor(u3_noun); - u3_noun u3wc_lsh(u3_noun); - u3_noun u3wc_mas(u3_noun); - u3_noun u3wc_met(u3_noun); - u3_noun u3wc_mix(u3_noun); - u3_noun u3wc_mor(u3_noun); - u3_noun u3wc_mug(u3_noun); - u3_noun u3wc_muk(u3_noun); - u3_noun u3wc_peg(u3_noun); - u3_noun u3wc_pow(u3_noun); - u3_noun u3wc_rap(u3_noun); - u3_noun u3wc_rep(u3_noun); - u3_noun u3wc_rev(u3_noun); - u3_noun u3wc_rip(u3_noun); - u3_noun u3wc_rsh(u3_noun); - u3_noun u3wc_swp(u3_noun); - u3_noun u3wc_sqt(u3_noun); - - u3_noun u3wcp_ins(u3_noun); - u3_noun u3wcp_ind(u3_noun); - u3_noun u3wcp_tos(u3_noun); - u3_noun u3wcp_tod(u3_noun); - - /** Tier 4. - **/ - u3_noun u3wdb_all(u3_noun); - u3_noun u3wdb_any(u3_noun); - u3_noun u3wdb_apt(u3_noun); - u3_noun u3wdb_bif(u3_noun); - u3_noun u3wdb_del(u3_noun); - u3_noun u3wdb_dif(u3_noun); - u3_noun u3wdb_gas(u3_noun); - u3_noun u3wdb_get(u3_noun); - u3_noun u3wdb_has(u3_noun); - u3_noun u3wdb_int(u3_noun); - u3_noun u3wdb_jab(u3_noun); - u3_noun u3wdb_key(u3_noun); - u3_noun u3wdb_put(u3_noun); -# define u3wdb_tap u3wdi_tap - u3_noun u3wdb_uni(u3_noun); - u3_noun u3wdb_urn(u3_noun); -# define u3wdb_rep u3wdi_rep - u3_noun u3wdb_run(u3_noun); -# define u3wdb_wyt u3wdi_wyt - - u3_noun u3wdi_apt(u3_noun); - u3_noun u3wdi_bif(u3_noun); - u3_noun u3wdi_del(u3_noun); - u3_noun u3wdi_dif(u3_noun); - u3_noun u3wdi_gas(u3_noun); - u3_noun u3wdi_has(u3_noun); - u3_noun u3wdi_int(u3_noun); - u3_noun u3wdi_put(u3_noun); - u3_noun u3wdi_rep(u3_noun); - u3_noun u3wdi_run(u3_noun); - u3_noun u3wdi_tap(u3_noun); - u3_noun u3wdi_uni(u3_noun); - u3_noun u3wdi_wyt(u3_noun); - - /** Tier 5. - **/ - u3_noun u3we_cue(u3_noun); - u3_noun u3we_jam(u3_noun); - u3_noun u3we_mat(u3_noun); - u3_noun u3we_rub(u3_noun); - u3_noun u3we_leer(u3_noun); - u3_noun u3we_lore(u3_noun); - u3_noun u3we_loss(u3_noun); - u3_noun u3we_lune(u3_noun); - u3_noun u3we_mink(u3_noun); - u3_noun u3we_mole(u3_noun); - u3_noun u3we_mule(u3_noun); - u3_noun u3we_repg(u3_noun); - u3_noun u3we_rexp(u3_noun); - u3_noun u3we_trip(u3_noun); - - u3_noun u3we_scow(u3_noun); - u3_noun u3we_scot(u3_noun); - u3_noun u3we_slaw(u3_noun); - - u3_noun u3we_pfix(u3_noun); - u3_noun u3we_plug(u3_noun); - u3_noun u3we_pose(u3_noun); - u3_noun u3we_sfix(u3_noun); - - u3_noun u3wea_ecba_en(u3_noun); - u3_noun u3wea_ecba_de(u3_noun); - u3_noun u3wea_ecbb_en(u3_noun); - u3_noun u3wea_ecbb_de(u3_noun); - u3_noun u3wea_ecbc_en(u3_noun); - u3_noun u3wea_ecbc_de(u3_noun); - - u3_noun u3wea_cbca_en(u3_noun); - u3_noun u3wea_cbca_de(u3_noun); - u3_noun u3wea_cbcb_en(u3_noun); - u3_noun u3wea_cbcb_de(u3_noun); - u3_noun u3wea_cbcc_en(u3_noun); - u3_noun u3wea_cbcc_de(u3_noun); - - u3_noun u3wea_siva_en(u3_noun); - u3_noun u3wea_siva_de(u3_noun); - u3_noun u3wea_sivb_en(u3_noun); - u3_noun u3wea_sivb_de(u3_noun); - u3_noun u3wea_sivc_en(u3_noun); - u3_noun u3wea_sivc_de(u3_noun); - - u3_noun u3wea_de(u3_noun); - u3_noun u3wea_en(u3_noun); - - u3_noun u3wes_hsh(u3_noun); - u3_noun u3wes_hsl(u3_noun); - u3_noun u3wes_pbk(u3_noun); - u3_noun u3wes_pbl(u3_noun); - - u3_noun u3we_shax(u3_noun); - u3_noun u3we_shay(u3_noun); - u3_noun u3we_shas(u3_noun); - u3_noun u3we_shal(u3_noun); - u3_noun u3we_sha1(u3_noun); - - u3_noun u3we_fein_ob(u3_noun); - u3_noun u3we_fynd_ob(u3_noun); - - u3_noun u3weo_raw(u3_noun); - - u3_noun u3wee_puck(u3_noun); - u3_noun u3wee_sign(u3_noun); - u3_noun u3wee_veri(u3_noun); - u3_noun u3wee_shar(u3_noun); - u3_noun u3wee_point_add(u3_noun); - u3_noun u3wee_scalarmult(u3_noun); - u3_noun u3wee_scalarmult_base(u3_noun); - u3_noun u3wee_add_scalarmult_scalarmult_base(u3_noun); - u3_noun u3wee_add_double_scalarmult(u3_noun); - - u3_noun u3we_hmac(u3_noun); - - u3_noun u3we_kecc224(u3_noun); - u3_noun u3we_kecc256(u3_noun); - u3_noun u3we_kecc384(u3_noun); - u3_noun u3we_kecc512(u3_noun); - - u3_noun u3we_argon2(u3_noun); - - u3_noun u3we_blake(u3_noun); - - u3_noun u3we_ripe(u3_noun); - - u3_noun u3we_make(u3_noun); - u3_noun u3we_sign(u3_noun); - u3_noun u3we_reco(u3_noun); - - u3_noun u3we_sosi(u3_noun); - u3_noun u3we_sove(u3_noun); - - u3_noun u3we_en_base16(u3_noun); - u3_noun u3we_de_base16(u3_noun); - - u3_noun u3we_bend_fun(u3_noun); - u3_noun u3we_cold_fun(u3_noun); - u3_noun u3we_cook_fun(u3_noun); - u3_noun u3we_comp_fun(u3_noun); - u3_noun u3we_easy_fun(u3_noun); - u3_noun u3we_glue_fun(u3_noun); - u3_noun u3we_here_fun(u3_noun); - u3_noun u3we_just_fun(u3_noun); - u3_noun u3we_mask_fun(u3_noun); - u3_noun u3we_shim_fun(u3_noun); - u3_noun u3we_stag_fun(u3_noun); - u3_noun u3we_stew_fun(u3_noun); - u3_noun u3we_stir_fun(u3_noun); - - u3_noun u3wef_drg(u3_noun); - u3_noun u3wef_lug(u3_noun); - - u3_noun u3wer_add(u3_noun); - u3_noun u3wer_sub(u3_noun); - u3_noun u3wer_mul(u3_noun); - u3_noun u3wer_div(u3_noun); - u3_noun u3wer_sqt(u3_noun); - u3_noun u3wer_fma(u3_noun); - u3_noun u3wer_lth(u3_noun); - u3_noun u3wer_lte(u3_noun); - u3_noun u3wer_equ(u3_noun); - u3_noun u3wer_gte(u3_noun); - u3_noun u3wer_gth(u3_noun); - - u3_noun u3wet_add(u3_noun); - u3_noun u3wet_sub(u3_noun); - u3_noun u3wet_mul(u3_noun); - u3_noun u3wet_div(u3_noun); - u3_noun u3wet_sqt(u3_noun); - u3_noun u3wet_fma(u3_noun); - u3_noun u3wet_lth(u3_noun); - u3_noun u3wet_lte(u3_noun); - u3_noun u3wet_equ(u3_noun); - u3_noun u3wet_gte(u3_noun); - u3_noun u3wet_gth(u3_noun); - - u3_noun u3weq_add(u3_noun); - u3_noun u3weq_sub(u3_noun); - u3_noun u3weq_mul(u3_noun); - u3_noun u3weq_div(u3_noun); - u3_noun u3weq_sqt(u3_noun); - u3_noun u3weq_fma(u3_noun); - u3_noun u3weq_lth(u3_noun); - u3_noun u3weq_lte(u3_noun); - u3_noun u3weq_equ(u3_noun); - u3_noun u3weq_gte(u3_noun); - u3_noun u3weq_gth(u3_noun); - - u3_noun u3wes_add(u3_noun); - u3_noun u3wes_sub(u3_noun); - u3_noun u3wes_mul(u3_noun); - u3_noun u3wes_div(u3_noun); - u3_noun u3wes_sqt(u3_noun); - u3_noun u3wes_fma(u3_noun); - u3_noun u3wes_lth(u3_noun); - u3_noun u3wes_lte(u3_noun); - u3_noun u3wes_equ(u3_noun); - u3_noun u3wes_gte(u3_noun); - u3_noun u3wes_gth(u3_noun); - - /** Tier 6. - **/ - u3_noun u3wf_bull(u3_noun); - u3_noun u3wf_cell(u3_noun); - u3_noun u3wf_comb(u3_noun); - u3_noun u3wf_cons(u3_noun); - u3_noun u3wf_core(u3_noun); - u3_noun u3wf_cube(u3_noun); - u3_noun u3wf_face(u3_noun); - u3_noun u3wf_fine(u3_noun); - u3_noun u3wf_fitz(u3_noun); - u3_noun u3wf_flan(u3_noun); - u3_noun u3wf_flay(u3_noun); - u3_noun u3wf_flip(u3_noun); - u3_noun u3wf_flor(u3_noun); - u3_noun u3wf_forq(u3_noun); - u3_noun u3wf_fork(u3_noun); - u3_noun u3wf_hint(u3_noun); - u3_noun u3wf_hike(u3_noun); - u3_noun u3wf_look(u3_noun); - u3_noun u3wf_loot(u3_noun); - - u3_noun u3wfl_bunt(u3_noun); - u3_noun u3wfl_whip(u3_noun); - - u3_noun u3wfp_hack(u3_noun); - u3_noun u3wfp_late(u3_noun); - u3_noun u3wfp_open(u3_noun); - u3_noun u3wfp_rake(u3_noun); - - u3_noun u3wfu_busk(u3_noun); - u3_noun u3wfu_crop(u3_noun); - u3_noun u3wfu_find(u3_noun); - u3_noun u3wfu_fond(u3_noun); - u3_noun u3wfu_fish(u3_noun); - u3_noun u3wfu_fuse(u3_noun); - u3_noun u3wfu_mint(u3_noun); - u3_noun u3wfu_mull(u3_noun); - u3_noun u3wfu_nest_dext(u3_noun); - u3_noun u3wfu_peek(u3_noun); - u3_noun u3wfu_play(u3_noun); - u3_noun u3wfu_repo(u3_noun); - u3_noun u3wfu_rest(u3_noun); - -#endif /* ifndef U3_JETS_W_H */ diff --git a/pkg/urbit/include/noun/aliases.h b/pkg/urbit/include/noun/aliases.h deleted file mode 100644 index 9304563a4..000000000 --- a/pkg/urbit/include/noun/aliases.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef U3_ALIASES_H -#define U3_ALIASES_H - - /** Constants. - **/ - /* u3_none - u3_noun which is not a noun. - */ -# define u3_none (u3_noun)0xffffffff - - /* u3_nul: 0, hoon ~. - */ -# define u3_nul 0 - - /* u3_blip: 0, hoon %$. - */ -# define u3_blip 0 - - - /** Typedefs. - **/ - /* u3_post: pointer offset into u3_Loom; _p suffix; declare as u3p(). - */ - typedef c3_w u3_post; -# define u3p(type) u3_post - - /* u3_noun: tagged noun pointer. - ** - ** If bit 31 is 0, a u3_noun is a direct 31-bit atom ("cat"). - ** If bit 31 is 1 and bit 30 0, an indirect atom ("pug"). - ** If bit 31 is 1 and bit 30 1, an indirect cell ("pom"). - ** - ** Bits 0-29 are a word offset against u3_Loom (u3_post). - */ - typedef c3_w u3_noun; - - /* u3_weak: u3_noun which may be u3_none (not a noun). - */ - typedef u3_noun u3_weak; - - /* u3_atom: u3_noun which must be an atom. - */ - typedef u3_noun u3_atom; - - /* u3_term: u3_noun which must be a term (@tas). - */ - typedef u3_noun u3_term; - - /* u3_cell, u3_trel, u3_qual, u3_quin: cell, triple, quadruple, quintuple. - */ - typedef u3_noun u3_cell; - typedef u3_noun u3_trel; - typedef u3_noun u3_qual; - typedef u3_noun u3_quin; - - /* u3_funk, u3_funq: unary and binary noun functions. - */ - typedef u3_noun (*u3_funk)(u3_noun); - typedef u3_noun (*u3_funq)(u3_noun, u3_noun); - - - /** Macros. - **/ - /* u3_assure(): loobean assert, bailing with %fail. - */ -# define u3_assure(x) if ( !_(x) ) { u3m_bail(c3__fail); } - - /* u3_assert(): loobean assert, bailing with %exit. - */ -# define u3_assent(x) if ( !_(x) ) { u3m_bail(c3__exit); } - - - /** Aliases. - **/ - /* u3h(), u3t(), u3at(): noun fragments. - */ -# define u3h(som) u3x_h(som) -# define u3t(som) u3x_t(som) -# define u3at(axe, som) u3x_at(axe, som) - - /* u3nc(), u3nt(), u3nq(): tuple composition. - */ -# define u3nc(a, b) u3i_cell(a, b) -# define u3nt(a, b, c) u3i_trel(a, b, c) -# define u3nq(a, b, c, d) u3i_qual(a, b, c, d) - - - /* u3nl(), u3_none-terminated varargs list - */ -# define u3nl u3i_list - - /* u3du(), u3ud(): noun/cell test. - */ -# define u3du(som) (u3r_du(som)) -# define u3ud(som) (u3r_ud(som)) - - /* u3k(), u3z(): reference counts. - */ -# define u3k(som) u3a_gain(som) -# define u3z(som) u3a_lose(som) - - /* u3do(), u3dc(), u3dt(), u3dq(): arvo calls. - */ -# define u3do(txt_c, arg) u3v_do(txt_c, arg) -# define u3dc(txt_c, a, b) u3v_do(txt_c, u3nc(a, b)) -# define u3dt(txt_c, a, b, c) u3v_do(txt_c, u3nt(a, b, c)) -# define u3dq(txt_c, a, b, c, d) u3v_do(txt_c, u3nq(a, b, c, d)) - - /* u3to(), u3of(): offset/pointer conversion. - */ -# define u3to(type, x) ((type *) u3a_into(x)) -# define u3tn(type, x) (x == 0) ? (void *)0 : ((type *) u3a_into(x)) -# define u3of(type, x) (u3a_outa((type *)x)) - - -#endif /* ifndef U3_ALIASES_H */ diff --git a/pkg/urbit/include/noun/allocate.h b/pkg/urbit/include/noun/allocate.h deleted file mode 100644 index 964de538b..000000000 --- a/pkg/urbit/include/noun/allocate.h +++ /dev/null @@ -1,674 +0,0 @@ -#ifndef U3_ALLOCATE_H -#define U3_ALLOCATE_H - -#include "manage.h" - - /** Constants. - **/ - /* u3a_bits: number of bits in word-addressed pointer. 29 == 2GB. - */ -# define u3a_bits U3_OS_LoomBits - - /* u3a_page: number of bits in word-addressed page. 12 == 16Kbyte page. - */ -# define u3a_page 12 - - /* u3a_pages: maximum number of pages in memory. - */ -# define u3a_pages (1 << (u3a_bits - u3a_page)) - - /* u3a_words: maximum number of words in memory. - */ -# define u3a_words (1 << u3a_bits) - - /* u3a_bytes: maximum number of bytes in memory. - */ -# define u3a_bytes (sizeof(c3_w) * u3a_words) - - /* u3a_cells: number of representable cells. - */ -# define u3a_cells (c3_w)(u3a_words / u3a_minimum) - - /* u3a_maximum: maximum loom object size (largest possible atom). - */ -# define u3a_maximum \ - (c3_w)(u3a_words - (c3_wiseof(u3a_box) + c3_wiseof(u3a_atom))) - - /* u3a_minimum: minimum loom object size (actual size of a cell). - */ -# define u3a_minimum (c3_w)(1 + c3_wiseof(u3a_box) + c3_wiseof(u3a_cell)) - - /* u3a_fbox_no: number of free lists per size. - */ -# define u3a_fbox_no 27 - - - /** Structures. - **/ - /* u3a_atom, u3a_cell: logical atom and cell structures. - */ - typedef struct { - c3_w mug_w; - } u3a_noun; - - typedef struct { - c3_w mug_w; - c3_w len_w; - c3_w buf_w[0]; - } u3a_atom; - - typedef struct { - c3_w mug_w; - u3_noun hed; - u3_noun tel; - } u3a_cell; - - /* u3a_box: classic allocation box. - ** - ** The box size is also stored at the end of the box in classic - ** bad ass malloc style. Hence a box is: - ** - ** --- - ** siz_w - ** use_w - ** user data - ** siz_w - ** --- - ** - ** Do not attempt to adjust this structure! - */ - typedef struct _u3a_box { - c3_w siz_w; // size of this box - c3_w use_w; // reference count; free if 0 -# ifdef U3_MEMORY_DEBUG - c3_w eus_w; // recomputed refcount - c3_w cod_w; // tracing code -# endif - } u3a_box; - - /* u3a_fbox: free node in heap. Sets minimum node size. - */ - typedef struct _u3a_fbox { - u3a_box box_u; - u3p(struct _u3a_fbox) pre_p; - u3p(struct _u3a_fbox) nex_p; - } u3a_fbox; - - /* u3a_jets: jet dashboard - */ - typedef struct _u3a_jets { - u3p(u3h_root) hot_p; // hot state (home road only) - u3p(u3h_root) war_p; // warm state - u3p(u3h_root) cod_p; // cold state - u3p(u3h_root) han_p; // hank cache - u3p(u3h_root) bas_p; // battery hashes - } u3a_jets; - - /* u3a_road: contiguous allocation and execution context. - */ - typedef struct _u3a_road { - u3p(struct _u3a_road) par_p; // parent road - u3p(struct _u3a_road) kid_p; // child road list - u3p(struct _u3a_road) nex_p; // sibling road - - u3p(c3_w) cap_p; // top of transient region - u3p(c3_w) hat_p; // top of durable region - u3p(c3_w) mat_p; // bottom of transient region - u3p(c3_w) rut_p; // bottom of durable region - u3p(c3_w) ear_p; // original cap if kid is live - - c3_w fut_w[32]; // futureproof buffer - - struct { // escape buffer - union { - jmp_buf buf; - c3_w buf_w[256]; // futureproofing - }; - } esc; - - struct { // miscellaneous config - c3_w fag_w; // flag bits - } how; // - - struct { // allocation pools - u3p(u3a_fbox) fre_p[u3a_fbox_no]; // heap by node size log - u3p(u3a_fbox) cel_p; // custom cell allocator - c3_w fre_w; // number of free words - c3_w max_w; // maximum allocated - } all; - - u3a_jets jed; // jet dashboard - - struct { // bytecode state - u3p(u3h_root) har_p; // formula->post of bytecode - } byc; - - struct { // namespace - u3_noun gul; // (list $+(* (unit (unit)))) now - } ski; - - struct { // trace stack - u3_noun tax; // (list ,*) - u3_noun mer; // emergency buffer to release - } bug; - - struct { // profile stack - c3_d nox_d; // nock steps - c3_d cel_d; // cell allocations - u3_noun don; // (list batt) - u3_noun trace; // (list trace) - u3_noun day; // doss, only in u3H (moveme) - } pro; - - struct { // memoization - u3p(u3h_root) har_p; // (map (pair term noun) noun) - } cax; - } u3a_road; - typedef u3a_road u3_road; - - /* u3a_flag: flags for how.fag_w. All arena related. - */ - enum u3a_flag { - u3a_flag_sand = 0x1, // bump allocation (XX not impl) - }; - - /* u3a_pile: stack control, abstracted over road direction. - */ - typedef struct _u3a_pile { - c3_ws mov_ws; - c3_ws off_ws; - u3_post top_p; -#ifdef U3_MEMORY_DEBUG - u3a_road* rod_u; -#endif - } u3a_pile; - - /** Macros. Should be better commented. - **/ - /* In and out of the box. - */ -# define u3a_boxed(len_w) (len_w + c3_wiseof(u3a_box) + 1) -# define u3a_boxto(box_v) ( (void *) \ - ( ((c3_w *)(void*)(box_v)) + \ - c3_wiseof(u3a_box) ) ) -# define u3a_botox(tox_v) ( (struct _u3a_box *) \ - (void *) \ - ( ((c3_w *)(void*)(tox_v)) - \ - c3_wiseof(u3a_box) ) ) - /* Inside a noun. - */ - - /* u3a_is_cat(): yes if noun [som] is direct atom. - */ -# define u3a_is_cat(som) (((som) >> 31) ? c3n : c3y) - - /* u3a_is_dog(): yes if noun [som] is indirect noun. - */ -# define u3a_is_dog(som) (((som) >> 31) ? c3y : c3n) - - /* u3a_is_pug(): yes if noun [som] is indirect atom. - */ -# define u3a_is_pug(som) ((0b10 == ((som) >> 30)) ? c3y : c3n) - - /* u3a_is_pom(): yes if noun [som] is indirect cell. - */ -# define u3a_is_pom(som) ((0b11 == ((som) >> 30)) ? c3y : c3n) - - /* u3a_to_off(): mask off bits 30 and 31 from noun [som]. - */ -# define u3a_to_off(som) ((som) & 0x3fffffff) - - /* u3a_to_ptr(): convert noun [som] into generic pointer into loom. - */ -# define u3a_to_ptr(som) (u3a_into(u3a_to_off(som))) - - /* u3a_to_wtr(): convert noun [som] into word pointer into loom. - */ -# define u3a_to_wtr(som) ((c3_w *)u3a_to_ptr(som)) - - /* u3a_to_pug(): set bit 31 of [off]. - */ -# define u3a_to_pug(off) (off | 0x80000000) - - /* u3a_to_pom(): set bits 30 and 31 of [off]. - */ -# define u3a_to_pom(off) (off | 0xc0000000) - - /* u3a_is_atom(): yes if noun [som] is direct atom or indirect atom. - */ -# define u3a_is_atom(som) c3o(u3a_is_cat(som), \ - u3a_is_pug(som)) - /* u3a_is_cell: yes if noun [som] is cell. - */ -# define u3a_is_cell(som) u3a_is_pom(som) - - /* u3a_h(): get head of cell [som]. Bail if [som] is not cell. - */ -# define u3a_h(som) \ - ( _(u3a_is_cell(som)) \ - ? ( ((u3a_cell *)u3a_to_ptr(som))->hed )\ - : u3m_bail(c3__exit) ) - - /* u3a_t(): get tail of cell [som]. Bail if [som] is not cell. - */ -# define u3a_t(som) \ - ( _(u3a_is_cell(som)) \ - ? ( ((u3a_cell *)u3a_to_ptr(som))->tel )\ - : u3m_bail(c3__exit) ) - - /* u3a_into(): convert loom offset [x] into generic pointer. - */ -# define u3a_into(x) ((void *)(u3_Loom + (x))) - - /* u3a_outa(): convert pointer [p] into word offset into loom. - */ -# define u3a_outa(p) (((c3_w*)(void*)(p)) - u3_Loom) - - /* u3a_is_north(): yes if road [r] is north road. - */ -# define u3a_is_north(r) __(r->cap_p > r->hat_p) - - /* u3a_is_south(): yes if road [r] is south road. - */ -# define u3a_is_south(r) !u3a_is_north(r) - - /* u3a_open(): words of contiguous free space in road [r] - */ -# define u3a_open(r) ( (c3y == u3a_is_north(r)) \ - ? (c3_w)(r->cap_p - r->hat_p) \ - : (c3_w)(r->hat_p - r->cap_p) ) - - /* u3a_full(): total words in road [r]; - ** u3a_full(r) == u3a_heap(r) + u3a_temp(r) + u3a_open(r) - */ -# define u3a_full(r) ( (c3y == u3a_is_north(r)) \ - ? (c3_w)(r->mat_p - r->rut_p) \ - : (c3_w)(r->rut_p - r->mat_p) ) - - /* u3a_heap(): words of heap in road [r] - */ -# define u3a_heap(r) ( (c3y == u3a_is_north(r)) \ - ? (c3_w)(r->hat_p - r->rut_p) \ - : (c3_w)(r->rut_p - r->hat_p) ) - - /* u3a_temp(): words of stack in road [r] - */ -# define u3a_temp(r) ( (c3y == u3a_is_north(r)) \ - ? (c3_w)(r->mat_p - r->cap_p) \ - : (c3_w)(r->cap_p - r->mat_p) ) - -# define u3a_north_is_senior(r, dog) \ - __((u3a_to_off(dog) < r->rut_p) || \ - (u3a_to_off(dog) >= r->mat_p)) - -# define u3a_north_is_junior(r, dog) \ - __((u3a_to_off(dog) >= r->cap_p) && \ - (u3a_to_off(dog) < r->mat_p)) - -# define u3a_north_is_normal(r, dog) \ - c3a(!(u3a_north_is_senior(r, dog)), \ - !(u3a_north_is_junior(r, dog))) - -# define u3a_south_is_senior(r, dog) \ - __((u3a_to_off(dog) < r->mat_p) || \ - (u3a_to_off(dog) >= r->rut_p)) - -# define u3a_south_is_junior(r, dog) \ - __((u3a_to_off(dog) < r->cap_p) && \ - (u3a_to_off(dog) >= r->mat_p)) - -# define u3a_south_is_normal(r, dog) \ - c3a(!(u3a_south_is_senior(r, dog)), \ - !(u3a_south_is_junior(r, dog))) - -# define u3a_is_junior(r, som) \ - ( _(u3a_is_cat(som)) \ - ? c3n \ - : _(u3a_is_north(r)) \ - ? u3a_north_is_junior(r, som) \ - : u3a_south_is_junior(r, som) ) - -# define u3a_is_senior(r, som) \ - ( _(u3a_is_cat(som)) \ - ? c3y \ - : _(u3a_is_north(r)) \ - ? u3a_north_is_senior(r, som) \ - : u3a_south_is_senior(r, som) ) - -# define u3a_is_mutable(r, som) \ - ( _(u3a_is_atom(som)) \ - ? c3n \ - : _(u3a_is_senior(r, som)) \ - ? c3n \ - : _(u3a_is_junior(r, som)) \ - ? c3n \ - : (u3a_botox(u3a_to_ptr(som))->use_w == 1) \ - ? c3y : c3n ) - - /** Globals. - **/ - /* u3_Road / u3R: current road (thread-local). - */ - c3_global u3_road* u3a_Road; -# define u3R u3a_Road - - /* u3_Code: memory code. - */ -#ifdef U3_MEMORY_DEBUG - c3_global c3_w u3_Code; -#endif - -# define u3_Loom ((c3_w *)(void *)U3_OS_LoomBase) - - /** inline functions. - **/ - /** road stack. - **/ - /* u3a_drop(): drop a road stack frame per [pil_u]. - */ - inline void - u3a_drop(const u3a_pile* pil_u) - { - u3R->cap_p -= pil_u->mov_ws; - } - - /* u3a_peek(): examine the top of the road stack. - */ - inline void* - u3a_peek(const u3a_pile* pil_u) - { - return u3to(void, (u3R->cap_p + pil_u->off_ws)); - } - - /* u3a_pop(): drop a road stack frame, peek at the new top. - */ - inline void* - u3a_pop(const u3a_pile* pil_u) - { - u3a_drop(pil_u); - return u3a_peek(pil_u); - } - - /* u3a_push(): push a frame onto the road stack, per [pil_u]. - */ - inline void* - u3a_push(const u3a_pile* pil_u) - { - u3R->cap_p += pil_u->mov_ws; - -#ifndef U3_GUARD_PAGE - // !off means we're on a north road - // - if ( !pil_u->off_ws ) { - if( !(u3R->cap_p > u3R->hat_p) ) { - u3m_bail(c3__meme); - } -# ifdef U3_MEMORY_DEBUG - c3_assert( pil_u->top_p >= u3R->cap_p ); -# endif - } - else { - if( !(u3R->cap_p < u3R->hat_p) ) { - u3m_bail(c3__meme); - } -# ifdef U3_MEMORY_DEBUG - c3_assert( pil_u->top_p <= u3R->cap_p ); -# endif - } -#endif /* ifndef U3_GUARD_PAGE */ - -#ifdef U3_MEMORY_DEBUG - c3_assert( pil_u->rod_u == u3R ); -#endif - - return u3a_peek(pil_u); - } - - /* u3a_pile_done(): assert valid upon completion. - */ - inline c3_o - u3a_pile_done(const u3a_pile* pil_u) - { - return (pil_u->top_p == u3R->cap_p) ? c3y : c3n; - } - - /** Functions. - **/ - /** Allocation. - **/ - /* Word-aligned allocation. - */ - /* u3a_walloc(): allocate storage measured in words. - */ - void* - u3a_walloc(c3_w len_w); - - /* u3a_celloc(): allocate a cell. Faster, sometimes. - */ - c3_w* - u3a_celloc(void); - - /* u3a_wfree(): free storage. - */ - void - u3a_wfree(void* lag_v); - - /* u3a_wtrim(): trim storage. - */ - void - u3a_wtrim(void* tox_v, c3_w old_w, c3_w len_w); - - /* u3a_wealloc(): word realloc. - */ - void* - u3a_wealloc(void* lag_v, c3_w len_w); - - /* u3a_pile_prep(): initialize stack control. - */ - void - u3a_pile_prep(u3a_pile* pil_u, c3_w len_w); - - /* C-style aligned allocation - *not* compatible with above. - */ - /* u3a_malloc(): aligned storage measured in bytes. - */ - void* - u3a_malloc(size_t len_i); - - /* u3a_calloc(): aligned storage measured in bytes. - */ - void* - u3a_calloc(size_t num_i, size_t len_i); - - /* u3a_realloc(): aligned realloc in bytes. - */ - void* - u3a_realloc(void* lag_v, size_t len_i); - - /* u3a_free(): free for aligned malloc. - */ - void - u3a_free(void* tox_v); - - /* Reference and arena control. - */ - /* u3a_gain(): gain a reference count in normal space. - */ - u3_weak - u3a_gain(u3_weak som); - - /* u3a_take(): gain, copying juniors. - */ - u3_noun - u3a_take(u3_noun som); - - /* u3a_left(): true of junior if preserved. - */ - c3_o - u3a_left(u3_noun som); - - /* u3a_lose(): lose a reference. - */ - void - u3a_lose(u3_weak som); - - /* u3a_wash(): wash all lazy mugs in subtree. RETAIN. - */ - void - u3a_wash(u3_noun som); - - /* u3a_use(): reference count. - */ - c3_w - u3a_use(u3_noun som); - - /* u3a_wed(): unify noun references. - */ - void - u3a_wed(u3_noun* a, u3_noun* b); - - /* u3a_luse(): check refcount sanity. - */ - void - u3a_luse(u3_noun som); - - /* u3a_mark_ptr(): mark a pointer for gc. Produce size. - */ - c3_w - u3a_mark_ptr(void* ptr_v); - - /* u3a_mark_mptr(): mark a u3_malloc-allocated ptr for gc. - */ - c3_w - u3a_mark_mptr(void* ptr_v); - - /* u3a_mark_noun(): mark a noun for gc. Produce size. - */ - c3_w - u3a_mark_noun(u3_noun som); - - /* u3a_mark_road(): mark ad-hoc persistent road structures. - */ - c3_w - u3a_mark_road(FILE* fil_u); - - /* u3a_reclaim(): clear ad-hoc persistent caches to reclaim memory. - */ - void - u3a_reclaim(void); - - /* u3a_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures. - */ - void - u3a_rewrite_compact(void); - - /* u3a_rewrite_ptr(): mark a pointer as already having been rewritten - */ - c3_o - u3a_rewrite_ptr(void* ptr_v); - - /* u3a_rewrite_noun(): rewrite a noun for compaction. - */ - void - u3a_rewrite_noun(u3_noun som); - - /* u3a_rewritten(): rewrite a pointer for compaction. - */ - u3_post - u3a_rewritten(u3_post som_p); - - /* u3a_rewritten(): rewritten noun pointer for compaction. - */ - u3_noun - u3a_rewritten_noun(u3_noun som); - - /* u3a_count_noun(): count size of noun. - */ - c3_w - u3a_count_noun(u3_noun som); - - /* u3a_discount_noun(): clean up after counting a noun. - */ - c3_w - u3a_discount_noun(u3_noun som); - - /* u3a_count_ptr(): count a pointer for gc. Produce size. */ - c3_w - u3a_count_ptr(void* ptr_v); - - /* u3a_discount_ptr(): discount a pointer for gc. Produce size. */ - c3_w - u3a_discount_ptr(void* ptr_v); - - /* u3a_idle(): measure free-lists in [rod_u] - */ - c3_w - u3a_idle(u3a_road* rod_u); - - /* u3a_sweep(): sweep a fully marked road. - */ - c3_w - u3a_sweep(void); - - /* u3a_pack_seek(): sweep the heap, modifying boxes to record new addresses. - */ - void - u3a_pack_seek(u3a_road* rod_u); - - /* u3a_pack_move(): sweep the heap, moving boxes to new addresses. - */ - void - u3a_pack_move(u3a_road* rod_u); - - /* u3a_sane(): check allocator sanity. - */ - void - u3a_sane(void); - - /* u3a_lush(): leak push. - */ - c3_w - u3a_lush(c3_w lab_w); - - /* u3a_lop(): leak pop. - */ - void - u3a_lop(c3_w lab_w); - - /* u3a_print_time: print microsecond time. - */ - void - u3a_print_time(c3_c* str_c, c3_c* cap_c, c3_d mic_d); - - /* u3a_print_memory(): print memory amount. - */ - void - u3a_print_memory(FILE* fil_u, c3_c* cap_c, c3_w wor_w); - - /* u3a_maid(): maybe print memory. - */ - c3_w - u3a_maid(FILE* fil_u, c3_c* cap_c, c3_w wor_w); - - /* u3a_deadbeef(): write 0xdeadbeef from hat to cap. - */ - void - u3a_deadbeef(void); - - /* u3a_walk_fore(): preorder traversal, visits ever limb of a noun. - ** - ** cells are visited *before* their heads and tails - ** and can shortcircuit traversal by returning [c3n] - */ - void - u3a_walk_fore(u3_noun a, - void* ptr_v, - void (*pat_f)(u3_atom, void*), - c3_o (*cel_f)(u3_noun, void*)); - - /* u3a_string(): `a` as an on-loom c-string. - */ - c3_c* - u3a_string(u3_atom a); - -#endif /* ifndef U3_ALLOCATE_H */ diff --git a/pkg/urbit/include/noun/events.h b/pkg/urbit/include/noun/events.h deleted file mode 100644 index c1b95cde8..000000000 --- a/pkg/urbit/include/noun/events.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef U3_EVENTS_H -#define U3_EVENTS_H - - /** Data structures. - **/ - /* u3e_line: control line. - */ - typedef struct _u3e_line { - c3_w pag_w; - c3_w mug_w; - } u3e_line; - - /* u3e_control: memory change, control file. - */ - typedef struct _u3e_control { - c3_w ver_y; // version number - c3_w nor_w; // new page count north - c3_w sou_w; // new page count south - c3_w pgs_w; // number of changed pages - u3e_line mem_u[0]; // per page - } u3e_control; - - /* u3_cs_patch: memory change, top level. - */ - typedef struct _u3_cs_patch { - c3_i ctl_i; - c3_i mem_i; - u3e_control* con_u; - } u3_ce_patch; - - /* u3e_image: memory segment, open file. - */ - typedef struct _u3e_image { - c3_c* nam_c; // segment name - c3_i fid_i; // open file, or 0 - c3_w pgs_w; // length in pages - } u3e_image; - - /* u3e_pool: entire memory system. - */ - typedef struct _u3e_pool { - c3_c* dir_c; // path to - c3_w dit_w[u3a_pages >> 5]; // touched since last save - c3_w pag_w; // number of pages (<= u3a_pages) - u3e_image nor_u; // north segment - u3e_image sou_u; // south segment - } u3e_pool; - - - /** Globals. - **/ - /* u3_Pool / u3P: global memory control. - */ - c3_global u3e_pool u3e_Pool; -# define u3P u3e_Pool - - /** Constants. - **/ -# define u3e_version 1 - - /** Functions. - **/ - /* u3e_fault(): handle a memory event with libsigsegv protocol. - */ - c3_i - u3e_fault(void* adr_v, c3_i ser_i); - - /* u3e_save(): - */ - void - u3e_save(void); - - /* u3e_live(): start the persistence system. Return c3y if no image. - */ - c3_o - u3e_live(c3_o nuu_o, c3_c* dir_c); - - /* u3e_yolo(): disable dirty page tracking, read/write whole loom. - */ - c3_o - u3e_yolo(void); - - /* u3e_foul(): dirty all the pages of the loom. - */ - void - u3e_foul(void); - - /* u3e_init(): initialize guard page tracking. - */ - void - u3e_init(void); - - /* u3e_ward(): reposition guard page if needed. - */ - void - u3e_ward(u3_post low_p, u3_post hig_p); - -#endif /* ifndef U3_EVENTS_H */ diff --git a/pkg/urbit/include/noun/hashtable.h b/pkg/urbit/include/noun/hashtable.h deleted file mode 100644 index 8c69b13b9..000000000 --- a/pkg/urbit/include/noun/hashtable.h +++ /dev/null @@ -1,185 +0,0 @@ -#ifndef U3_HASHTABLE_H -#define U3_HASHTABLE_H - - /** Data structures. - **/ - /** Straightforward implementation of the classic Bagwell - *** HAMT (hash array mapped trie), using a mug hash. - *** - *** Because a mug is 31 bits, the root table has 64 slots. - *** The 31 bits of a mug are divided into the first lookup, - *** which is 6 bits (corresponding to the 64 entries in the - *** root table), followed by 5 more branchings of 5 bits each, - *** corresponding to the 32-slot nodes for everything under - *** the root node. - *** - *** We store an extra "freshly warm" bit for a simple - *** clock-algorithm reclamation policy, not yet implemented. - *** Search "clock algorithm" to figure it out. - **/ - /* u3h_slot: map slot. - ** - ** Either a key-value cell or a loom offset, decoded as a pointer - ** to a u3h_node, or a u3h_buck at the bottom. Matches the u3_noun - ** format - coordinate with allocate.h. The top two bits are: - ** - ** 00 - empty (in the root table only) - ** 01 - table - ** 02 - entry, stale - ** 03 - entry, fresh - */ - typedef c3_w u3h_slot; - - /* u3h_node: map node. - */ - typedef struct { - c3_w map_w; // bitmap for [sot_w] - u3h_slot sot_w[0]; // filled slots - } u3h_node; - - /* u3h_root: hash root table - */ - typedef struct { - c3_w max_w; // number of cache lines (0 for no trimming) - c3_w use_w; // number of lines currently filled - struct { - c3_w mug_w; // current hash - c3_w inx_w; // index into current hash bucket - c3_o buc_o; // XX remove - } arm_u; // clock arm - u3h_slot sot_w[64]; // slots - } u3h_root; - - /* u3h_buck: bottom bucket. - */ - typedef struct { - c3_w len_w; // length of [sot_w] - u3h_slot sot_w[0]; // filled slots - } u3h_buck; - - /** HAMT macros. - *** - *** Coordinate with u3_noun definition! - **/ - /* u3h_slot_is_null(): yes iff slot is empty - ** u3h_slot_is_noun(): yes iff slot contains a key/value cell - ** u3h_slot_is_node(): yes iff slot contains a subtable/bucket - ** u3h_slot_is_warm(): yes iff fresh bit is set - ** u3h_slot_to_node(): slot to node pointer - ** u3h_node_to_slot(): node pointer to slot - ** u3h_slot_to_noun(): slot to cell - ** u3h_noun_to_slot(): cell to slot - ** u3h_noun_be_warm(): warm mutant - ** u3h_noun_be_cold(): cold mutant - */ -# define u3h_slot_is_null(sot) ((0 == ((sot) >> 30)) ? c3y : c3n) -# define u3h_slot_is_node(sot) ((1 == ((sot) >> 30)) ? c3y : c3n) -# define u3h_slot_is_noun(sot) ((1 == ((sot) >> 31)) ? c3y : c3n) -# define u3h_slot_is_warm(sot) (((sot) & 0x40000000) ? c3y : c3n) -# define u3h_slot_to_node(sot) (u3a_into((sot) & 0x3fffffff)) -# define u3h_node_to_slot(ptr) (u3a_outa(ptr) | 0x40000000) -# define u3h_noun_be_warm(sot) ((sot) | 0x40000000) -# define u3h_noun_be_cold(sot) ((sot) & ~0x40000000) -# define u3h_slot_to_noun(sot) (0x40000000 | (sot)) -# define u3h_noun_to_slot(som) (u3h_noun_be_warm(som)) - - /** Functions. - *** - *** Needs: delete and merge functions; clock reclamation function. - **/ - /* u3h_new_cache(): create hashtable with bounded size. - */ - u3p(u3h_root) - u3h_new_cache(c3_w clk_w); - - /* u3h_new(): create hashtable. - */ - u3p(u3h_root) - u3h_new(void); - - /* u3h_put(): insert in hashtable. - ** - ** `key` is RETAINED; `val` is transferred. - */ - void - u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val); - - /* u3h_uni(): unify hashtables, copying [rah_p] into [har_p] - */ - void - u3h_uni(u3p(u3h_root) har_p, u3p(u3h_root) rah_p); - - /* u3h_get(): read from hashtable. - ** - ** `key` is RETAINED; result is PRODUCED. - */ - u3_weak - u3h_get(u3p(u3h_root) har_p, u3_noun key); - - /* u3h_git(): read from hashtable, retaining result. - ** - ** `key` is RETAINED; result is RETAINED. - */ - u3_weak - u3h_git(u3p(u3h_root) har_p, u3_noun key); - - /* u3h_trim_to(): trim to n key-value pairs - */ - void - u3h_trim_to(u3p(u3h_root) har_p, c3_w n_w); - - /* u3h_free(): free hashtable. - */ - void - u3h_free(u3p(u3h_root) har_p); - - /* u3h_mark(): mark hashtable for gc. - */ - c3_w - u3h_mark(u3p(u3h_root) har_p); - - /* u3h_rewrite(): rewrite hashtable for compaction. - */ - void - u3h_rewrite(u3p(u3h_root) har_p); - - /* u3h_count(): count hashtable for gc. - */ - c3_w - u3h_count(u3p(u3h_root) har_p); - - /* u3h_discount(): discount hashtable for gc. - */ - c3_w - u3h_discount(u3p(u3h_root) har_p); - - /* u3h_walk_with(): traverse hashtable with key, value fn and data - * argument; RETAINS. - */ - void - u3h_walk_with(u3p(u3h_root) har_p, - void (*fun_f)(u3_noun, void*), - void* wit); - - /* u3h_walk(): u3h_walk_with, but with no data argument - */ - void - u3h_walk(u3p(u3h_root) har_p, void (*fun_f)(u3_noun)); - - /* u3h_take_with(): gain hashtable, copying junior keys - ** and calling [fun_f] on values - */ - u3p(u3h_root) - u3h_take_with(u3p(u3h_root) har_p, u3_funk fun_f); - - /* u3h_take(): gain hashtable, copying junior nouns - */ - u3p(u3h_root) - u3h_take(u3p(u3h_root) har_p); - - /* u3h_wyt(): number of entries - */ - c3_w - u3h_wyt(u3p(u3h_root) har_p); - -#endif /* ifndef U3_HASHTABLE_H */ diff --git a/pkg/urbit/include/noun/imprison.h b/pkg/urbit/include/noun/imprison.h deleted file mode 100644 index 2123fb813..000000000 --- a/pkg/urbit/include/noun/imprison.h +++ /dev/null @@ -1,159 +0,0 @@ -#ifndef U3_IMPRISON_H -#define U3_IMPRISON_H - - /** Structures. - **/ - /* u3i_slab: atom builder. - */ - typedef struct _u3i_slab { - struct { // internals - u3a_atom* _vat_u; // heap atom (nullable) - c3_w _sat_w; // static storage - } _; // - union { // - c3_y* buf_y; // bytes - c3_w* buf_w; // words - }; // - c3_w len_w; // word length - } u3i_slab; - - /* staged atom-building api - */ - /* u3i_slab_init(): configure bloq-length slab, zero-initialize. - */ - void - u3i_slab_init(u3i_slab* sab_u, c3_g met_g, c3_d len_d); - - /* u3i_slab_bare(): configure bloq-length slab, uninitialized. - */ - void - u3i_slab_bare(u3i_slab* sab_u, c3_g met_g, c3_d len_d); - - /* u3i_slab_from(): configure bloq-length slab, initialize with [a]. - */ - void - u3i_slab_from(u3i_slab* sab_u, u3_atom a, c3_g met_g, c3_d len_d); - - /* u3i_slab_grow(): resize slab, zero-initializing new space. - */ - void - u3i_slab_grow(u3i_slab* sab_u, c3_g met_g, c3_d len_d); - - /* u3i_slab_free(): dispose memory backing slab. - */ - void - u3i_slab_free(u3i_slab* sab_u); - - /* u3i_slab_mint(): produce atom from slab, trimming. - */ - u3_atom - u3i_slab_mint(u3i_slab* sab_u); - - /* u3i_slab_moot(): produce atom from slab, no trimming. - */ - u3_atom - u3i_slab_moot(u3i_slab* sab_u); - - /* u3i_slab_mint_bytes(): produce atom from byte-slab, trimming. - ** XX assumes little-endian, implement swap to support big-endian - */ -# define u3i_slab_mint_bytes u3i_slab_mint - - /* u3i_slab_moot_bytes(): produce atom from byte-slab, no trimming. - ** XX assumes little-endian, implement swap to support big-endian - */ -# define u3i_slab_moot_bytes u3i_slab_moot - - /* General constructors. - */ - /* u3i_word(): construct u3_atom from c3_w. - */ - u3_atom - u3i_word(c3_w dat_w); - - /* u3i_chub(): construct u3_atom from c3_d. - */ - u3_atom - u3i_chub(c3_d dat_d); - - /* u3i_bytes(): Copy [a] bytes from [b] to an LSB first atom. - */ - u3_atom - u3i_bytes(c3_w a_w, - const c3_y* b_y); - - /* u3i_words(): Copy [a] words from [b] into an atom. - */ - u3_atom - u3i_words(c3_w a_w, - const c3_w* b_w); - - /* u3i_chubs(): Copy [a] chubs from [b] into an atom. - */ - u3_atom - u3i_chubs(c3_w a_w, - const c3_d* b_d); - - /* u3i_mp(): Copy the GMP integer [a] into an atom, and clear it. - */ - u3_atom - u3i_mp(mpz_t a_mp); - - /* u3i_vint(): increment [a]. - */ - u3_atom - u3i_vint(u3_noun a); - - /* u3i_cell(): Produce the cell `[a b]`. - */ - u3_noun - u3i_cell(u3_noun a, u3_noun b); - - /* u3i_defcons(): allocate cell for deferred construction. - ** NB: [hed] and [tel] pointers MUST be filled. - */ - u3_cell - u3i_defcons(u3_noun** hed, u3_noun** tel); - - /* u3i_trel(): Produce the triple `[a b c]`. - */ - u3_noun - u3i_trel(u3_noun a, u3_noun b, u3_noun c); - - /* u3i_qual(): Produce the cell `[a b c d]`. - */ - u3_noun - u3i_qual(u3_noun a, u3_noun b, u3_noun c, u3_noun d); - - /* u3i_string(): Produce an LSB-first atom from the C string [a]. - */ - u3_atom - u3i_string(const c3_c* a_c); - - /* u3i_tape(): from a C string, to a list of bytes. - */ - u3_noun - u3i_tape(const c3_c* txt_c); - - /* u3i_list(): list from `u3_none`-terminated varargs. - */ - u3_noun - u3i_list(u3_weak som, ...); - - /* u3i_edit(): - ** - ** Mutate `big` at axis `axe` with new value `som` - ** `axe` is RETAINED. - */ - u3_noun - u3i_edit(u3_noun big, u3_noun axe, u3_noun som); - - /* u3i_molt(): - ** - ** Mutate `som` with a 0-terminated list of axis, noun pairs. - ** Axes must be cats (31 bit). - */ - u3_noun - u3i_molt(u3_noun som, ...); - -#endif /* ifndef U3_IMPRISON_H */ diff --git a/pkg/urbit/include/noun/jets.h b/pkg/urbit/include/noun/jets.h deleted file mode 100644 index 5b1c4f03c..000000000 --- a/pkg/urbit/include/noun/jets.h +++ /dev/null @@ -1,304 +0,0 @@ -#ifndef U3_JETS_H -#define U3_JETS_H - - /** Noun semantics. - **/ -#if 0 -+= location $: pattern=(each static dynamic) - name=term - hooks=(map term axis) - == -+= static (each payload=* parent=location) -+= dynamic [where=axis parent=location] -:: -+= registry [roots=(map * location) parents=(list parent)] -+= parent (pair axis (map location location)) -:: -+= activation $: hot-index=@ud - drivers=(map axis @ud) - label=path - jit=* :: FIXME: should probably be (map battery *) - :: since there can be multiple batteries per location - == -+= hot-info $: reg=registry - hot-index=@ud - drivers=(map axis @ud) - label=path - == -+= bash @ :: battery hash (sha-256 based) -:: -+= hot (map bash hot-info) -+= cold (map battery=^ (pair bash registry)) -+= warm (map location activation) -#endif - - /** Data structures. - *** - *** All of these are transient structures allocated with malloc. - **/ - /* u3j_harm: jet arm. - */ - typedef struct _u3j_harm { - c3_c* fcs_c; // `.axe` or name - u3_noun (*fun_f)(u3_noun); // compute or 0 / semitransfer - // c3_o (*val_f)(u3_noun); // validate or 0 / retain - c3_o ice; // perfect (don't test) - c3_o tot; // total (never punts) - c3_o liv; // live (enabled) - c3_l axe_l; // computed/discovered axis - struct _u3j_core* cop_u; // containing core - } u3j_harm; - - /* u3j_hood: hook description. - */ - typedef struct _u3j_hood { - c3_c* nam_c; // hook name - c3_l axe_l; // hook axis (XX: direct) - c3_o kic_o; // hook is kick (vs. fragment) - c3_l sax_l; // hook subject axis (XX: direct) - } u3j_hood; - - /* u3j_core: driver definition. - */ - typedef struct _u3j_core { - c3_c* cos_c; // control string - c3_l axe_l; // axis to parent - struct _u3j_harm* arm_u; // blank-terminated static list - struct _u3j_core* dev_u; // blank-terminated static list - c3_c** bas_u; // blank-terminated static list - struct _u3j_hood* huc_u; // blank-terminated static list - struct _u3j_core* par_u; // dynamic parent pointer - c3_l jax_l; // index in global dashboard - } u3j_core; - - /* u3j_dash, u3_Dash, u3D: jet dashboard singleton - */ - typedef struct _u3j_dash { - u3j_core* dev_u; // null-terminated static list - c3_l len_l; // dynamic array length - c3_l all_l; // allocated length - u3j_core* ray_u; // dynamic array by axis - } u3j_dash; - - /* u3j_fist: a single step in a fine check. - */ - typedef struct { - u3_noun bat; // battery - u3_noun pax; // parent axis - } u3j_fist; - - /* u3j_fink: (fine check) enough data to verify a located core. - */ - typedef struct { - c3_w len_w; // number of fists - u3_noun sat; // static noun at end of check - u3j_fist fis_u[0]; // fists - } u3j_fink; - - /* u3j_rite: site of a %fast, used to skip re-mining. - */ - typedef struct { - c3_o own_o; // rite owns fink? - u3_weak clu; // cached product of clue formula - u3p(u3j_fink) fin_p; // fine check - } u3j_rite; - - /* u3j_site: site of a kick (nock 9), used to cache call target. - */ - struct _u3n_prog; - typedef struct { - u3p(struct _u3n_prog) pog_p; // program for formula - u3_noun axe; // axis - u3_weak bat; // battery (for verification) - u3_weak bas; // hash of battery (for hot find) - u3_weak loc; // location (for reaming) - c3_o jet_o; // have jet driver? - c3_o fon_o; // site owns fink? - u3_weak lab; // label (for tracing) - u3j_core* cop_u; // jet core - u3j_harm* ham_u; // jet arm - u3p(u3j_fink) fin_p; // fine check - } u3j_site; - - /** Globals. - **/ - /* u3_Dash: jet dashboard. - */ - extern u3j_dash u3j_Dash; -# define u3D u3j_Dash - - /** Functions. - **/ - /* u3j_boot(): initialize jet system. - */ - c3_w - u3j_boot(c3_o nuu_o); - - /* u3j_clear(): clear jet table to re-register. - */ - void - u3j_clear(void); - - /* u3j_cook(): - ** - ** Execute hook from core, call site cached by arbitrary c string - */ - u3_noun - u3j_cook(const c3_c* key_c, - u3_noun cor, - const c3_c* tam_c); - - /* u3j_hook(): - ** - ** Execute hook from core. - */ - u3_noun - u3j_hook(u3_noun cor, - const c3_c* tam_c); - - /* u3j_soft(): - ** - ** Execute hook from core, without jet. - */ - u3_noun - u3j_soft(u3_noun cor, - const c3_c* tam_c); - - /* u3j_kick(): try to kick by jet. If no kick, produce u3_none. - ** - ** `axe` is RETAINED by the caller; `cor` is RETAINED iff there - ** is no kick, TRANSFERRED if one. - */ - u3_weak - u3j_kick(u3_noun cor, u3_noun axe); - - /* u3j_kink(): kick either by jet or by nock. - */ - u3_noun - u3j_kink(u3_noun cor, - u3_noun axe); - - /* u3j_mine(): register core for jets. - */ - void - u3j_mine(u3_noun clu, - u3_noun cor); - - /* u3j_ream(): refresh after restoring from checkpoint. - */ - void - u3j_ream(void); - - /* u3j_stay(): extract cold state - */ - u3_noun - u3j_stay(void); - - /* u3j_load(): inject cold state - */ - void - u3j_load(u3_noun rel); - - /* u3j_reap(): promote jet state. - */ - void - u3j_reap(u3a_jets jed_u); - - /* u3j_take(): copy junior jet state. - */ - u3a_jets - u3j_take(u3a_jets jed_u); - - /* u3j_rite_mine(): mine cor with clu, using u3j_rite for caching - */ - void - u3j_rite_mine(u3j_rite* rit_u, u3_noun clu, u3_noun cor); - - /* u3j_rite_take(): copy junior rite references from src_u to dst_u. - */ - void - u3j_rite_take(u3j_rite* dst_u, u3j_rite* src_u); - - /* u3j_rite_merge(): copy rite references from src_u to dst_u, - ** losing old references - */ - void - u3j_rite_merge(u3j_rite* dst_u, u3j_rite* src_u); - - /* u3j_site_take(): copy junior site references. - */ - void - u3j_site_take(u3j_site* dst_u, u3j_site* src_u); - - /* u3j_site_merge(): copy site references from src_u to dst_u, - ** losing old references - */ - void - u3j_site_merge(u3j_site* dst_u, u3j_site* src_u); - - /* u3j_site_ream(): refresh u3j_site after restoring from checkpoint - */ - void - u3j_site_ream(u3j_site* sit_u); - - /* u3j_site_kick(): kick a core with a u3j_site cache. - */ - u3_weak - u3j_site_kick(u3_noun cor, u3j_site* sit_u); - - /* u3j_gate_prep(): prepare a locally cached gate to call repeatedly. - */ - void - u3j_gate_prep(u3j_site* sit_u, u3_noun cor); - - /* u3j_gate_slam(): slam a site prepared by u3j_gate_find() with sample. - */ - u3_noun - u3j_gate_slam(u3j_site* sit_u, u3_noun sam); - - /* u3j_gate_lose(): clean up site prepared by u3j_gate_find(). - */ - void - u3j_gate_lose(u3j_site* sit_u); - - /* u3j_rite_mark(): mark u3j_rite for gc. - */ - c3_w - u3j_rite_mark(u3j_rite* rit_u); - - /* u3j_rite_lose(): lose references of u3j_rite (but do not free). - */ - void - u3j_rite_lose(u3j_rite* rit_u); - - /* u3j_site_lose(): lose references of u3j_site (but do not free). - */ - void - u3j_site_lose(u3j_site* sit_u); - - /* u3j_site_mark(): mark u3j_site for gc. - */ - c3_w - u3j_site_mark(u3j_site* sit_u); - - /* u3j_mark(): mark jet state for gc. - */ - c3_w - u3j_mark(FILE* fil_u); - - /* u3j_free(): free jet state. - */ - void - u3j_free(void); - - /* u3j_reclaim(): clear ad-hoc persistent caches to reclaim memory. - */ - void - u3j_reclaim(void); - - /* u3j_rewrite_compact(): rewrite jet state for compaction. - */ - void - u3j_rewrite_compact(); - -#endif /* ifndef U3_JETS_H */ diff --git a/pkg/urbit/include/noun/log.h b/pkg/urbit/include/noun/log.h deleted file mode 100644 index e786eff5f..000000000 --- a/pkg/urbit/include/noun/log.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef U3_LOG_H -#define U3_LOG_H - -/* u3l_log(): logs to stderr or redirects to configured function. -*/ - void - u3l_log(const char* format, ...) - __attribute__ ((format (printf, 1, 2))); - -/* u3l_punt(): condtionally logs a named punt - * (e.g. "mint-punt" for the `name` "mint") - * when `pro` is u3_none, and returns pro. - * For use when a jet driver declines to handle - * a core, when the user should be somehow notified - * (e.g. in a cryptographic jet). - */ - u3_weak - u3l_punt(const char* name, u3_weak pro); - -#endif /* ifndef U3_LOG_H */ diff --git a/pkg/urbit/include/noun/manage.h b/pkg/urbit/include/noun/manage.h deleted file mode 100644 index 72e29f533..000000000 --- a/pkg/urbit/include/noun/manage.h +++ /dev/null @@ -1,157 +0,0 @@ -#ifndef U3_MANAGE_H -#define U3_MANAGE_H - - /** System management. - **/ - /* u3m_boot(): start the u3 system. return next event, starting from 1. - */ - c3_d - u3m_boot(c3_c* dir_c, size_t len_i); - - /* u3m_boot_lite(): start without checkpointing. - */ - c3_d - u3m_boot_lite(size_t len_i); - - /* u3m_stop(): graceful shutdown cleanup. */ - void - u3m_stop(void); - - /* u3m_bail(): bail out. Does not return. - ** - ** Bail motes: - ** - ** %exit :: semantic failure - ** %evil :: bad crypto - ** %intr :: interrupt - ** %fail :: execution failure - ** %foul :: assert failure - ** %need :: network block - ** %meme :: out of memory - ** %time :: timed out - ** %oops :: assertion failure - */ - c3_i - u3m_bail(c3_m how_m) __attribute__((noreturn)); - - /* u3m_init(): start the environment. - */ - void - u3m_init(size_t len_i); - - /* u3m_pave(): instantiate or activate image. - */ - void - u3m_pave(c3_o nuu_o); - - /* u3m_signal(): treat a nock-level exception as a signal interrupt. - */ - void - u3m_signal(u3_noun sig_l); - - /* u3m_file(): load file, as atom, or bail. - */ - u3_noun - u3m_file(c3_c* pas_c); - - /* u3m_error(): bail out with %exit, ct_pushing error. - */ - c3_i - u3m_error(c3_c* str_c); - - /* u3m_hate(): new, integrated leap mechanism (enter). - */ - void - u3m_hate(c3_w pad_w); - - /* u3m_love(): return product from leap. - */ - u3_noun - u3m_love(u3_noun pro); - - /* u3m_soft(): system soft wrapper. unifies unix and nock errors. - ** - ** Produces [%$ result] or [%error (list tank)]. - */ - u3_noun - u3m_soft(c3_w mil_w, u3_funk fun_f, u3_noun arg); - - /* u3m_soft_slam: top-level call. - */ - u3_noun - u3m_soft_slam(u3_noun gat, u3_noun sam); - - /* u3m_soft_nock: top-level nock. - */ - u3_noun - u3m_soft_nock(u3_noun bus, u3_noun fol); - - /* u3m_soft_sure(): top-level call assumed correct. - */ - u3_noun - u3m_soft_sure(u3_funk fun_f, u3_noun arg); - - /* u3m_soft_run(): descend into virtualization context. - */ - u3_noun - u3m_soft_run(u3_noun gul, - u3_funq fun_f, - u3_noun aga, - u3_noun agb); - - /* u3m_soft_esc(): namespace lookup to (unit ,*). - */ - u3_noun - u3m_soft_esc(u3_noun ref, u3_noun sam); - - /* u3m_mark(): mark all nouns in the road. - */ - c3_w - u3m_mark(FILE* fil_u); - - /* u3m_grab(): garbage-collect the world, plus extra roots. - */ - void - u3m_grab(u3_noun som, ...); // terminate with u3_none - - /* u3m_water(): produce high and low watermarks. Asserts u3R == u3H. - */ - void - u3m_water(c3_w *low_w, c3_w *hig_w); - - /* u3m_pretty(): dumb prettyprint to string. RETAIN. - */ - c3_c* - u3m_pretty(u3_noun som); - - /* u3m_pretty_path(): prettyprint a path to string. RETAIN. - */ - c3_c* - u3m_pretty_path(u3_noun som); - - /* u3m_p(): dumb print with caption. RETAIN. - */ - void - u3m_p(const c3_c* cap_c, u3_noun som); - - /* u3m_tape(): dump a tape to stdout. - */ - void - u3m_tape(u3_noun tep); - - /* u3m_wall(): dump a wall to stdout. - */ - void - u3m_wall(u3_noun wol); - - /* u3m_reclaim: clear persistent caches to reclaim memory - */ - void - u3m_reclaim(void); - - /* u3m_pack: compact (defragment) memory. - */ - c3_w - u3m_pack(void); - -#endif /* ifndef U3_MANAGE_H */ diff --git a/pkg/urbit/include/noun/nock.h b/pkg/urbit/include/noun/nock.h deleted file mode 100644 index 561cb7585..000000000 --- a/pkg/urbit/include/noun/nock.h +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef U3_NOCK_H -#define U3_NOCK_H - - /** Data structures. - *** - **/ - - /* u3n_memo: %memo hint space - */ - typedef struct { - c3_l sip_l; - u3_noun key; - } u3n_memo; - - /* u3n_prog: program compiled from nock - */ - typedef struct _u3n_prog { - struct { - c3_o own_o; // program owns ops_y? - c3_w len_w; // length of bytecode (bytes) - c3_y* ops_y; // actual array of bytes - } byc_u; // bytecode - struct { - c3_w len_w; // number of literals - u3_noun* non; // array of literals - } lit_u; // literals - struct { - c3_w len_w; // number of memo slots - u3n_memo* sot_u; // array of memo slots - } mem_u; // memo slot data - struct { - c3_w len_w; // number of calls sites - u3j_site* sit_u; // array of sites - } cal_u; // call site data - struct { - c3_w len_w; // number of registration sites - u3j_rite* rit_u; // array of sites - } reg_u; // registration site data - } u3n_prog; - - /** Functions. - **/ - /* u3n_nock_on(): produce .*(bus fol). - */ - u3_noun - u3n_nock_on(u3_noun bus, u3_noun fol); - - /* u3n_find(): return prog for given formula, - * split by key (u3_nul for none). RETAIN. - */ - u3p(u3n_prog) - u3n_find(u3_noun key, u3_noun fol); - - /* u3n_burn(): execute u3n_prog with bus as subject. - */ - u3_noun - u3n_burn(u3p(u3n_prog) pog_p, u3_noun bus); - - /* u3n_slam_on(): produce (gat sam). - */ - u3_noun - u3n_slam_on(u3_noun gat, u3_noun sam); - - /* u3n_kick_on(): fire `gat` without changing the sample. - */ - u3_noun - u3n_kick_on(u3_noun gat); - - /* u3n_nock_in(): produce .*(bus fol), as ++toon, in namespace. - */ - u3_noun - u3n_nock_in(u3_noun fly, u3_noun bus, u3_noun fol); - - /* u3n_nock_it(): produce .*(bus fol), as ++toon, in namespace. - */ - u3_noun - u3n_nock_it(u3_noun sea, u3_noun bus, u3_noun fol); - - /* u3n_nock_et(): produce .*(bus fol), as ++toon, in namespace. - */ - u3_noun - u3n_nock_et(u3_noun gul, u3_noun bus, u3_noun fol); - - /* u3n_slam_in(): produce (gat sam), as ++toon, in namespace. - */ - u3_noun - u3n_slam_in(u3_noun fly, u3_noun gat, u3_noun sam); - - /* u3n_slam_it(): produce (gat sam), as ++toon, in namespace. - */ - u3_noun - u3n_slam_it(u3_noun sea, u3_noun gat, u3_noun sam); - - /* u3n_slam_et(): produce (gat sam), as ++toon, in namespace. - */ - u3_noun - u3n_slam_it(u3_noun gul, u3_noun gat, u3_noun sam); - - /* u3n_nock_an(): as slam_in(), but with empty fly. - */ - u3_noun - u3n_nock_an(u3_noun bus, u3_noun fol); - - /* u3n_reap(): promote bytecode state. - */ - void - u3n_reap(u3p(u3h_root) har_p); - - /* u3n_take(): copy junior bytecode state. - */ - u3p(u3h_root) - u3n_take(u3p(u3h_root) har_p); - - /* u3n_mark(): mark bytecode cache. - */ - c3_w - u3n_mark(FILE* fil_u); - - /* u3n_reclaim(): clear ad-hoc persistent caches to reclaim memory. - */ - void - u3n_reclaim(void); - - /* u3n_rewrite_compact(): rewrite bytecode cache for compaction. - */ - void - u3n_rewrite_compact(); - - /* u3n_free(): free bytecode cache. - */ - void - u3n_free(void); - - /* u3n_ream(): refresh after restoring from checkpoint. - */ - void - u3n_ream(void); - -#endif /* ifndef U3_NOCK_H */ diff --git a/pkg/urbit/include/noun/options.h b/pkg/urbit/include/noun/options.h deleted file mode 100644 index c1fd58c40..000000000 --- a/pkg/urbit/include/noun/options.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef U3_OPTIONS_H -#define U3_OPTIONS_H - - /** Data structures. - **/ - /* u3o_config: process / system configuration. - */ - typedef struct _u3o_config { - u3_noun who; // single identity - c3_c* dir_c; // execution directory (pier) - c3_w wag_w; // flags (both ways) - size_t wor_i; // loom word-length (<= u3a_words) - void (*stderr_log_f)(c3_c*); // errors from c code - void (*slog_f)(u3_noun); // function pointer for slog - void (*sign_hold_f)(void); // suspend system signal regime - void (*sign_move_f)(void); // restore system signal regime - } u3o_config; - - /* u3o_flag: process/system flags. - ** - ** _debug flags are set outside u3 and heard inside it. - ** _check flags are set inside u3 and heard outside it. - */ - enum u3o_flag { // execution flags - u3o_debug_ram = 0x1, // debug: gc - u3o_debug_cpu = 0x2, // debug: profile - u3o_check_corrupt = 0x4, // check: gc memory - u3o_check_fatal = 0x8, // check: unrecoverable - u3o_verbose = 0x10, // be remarkably wordy - u3o_dryrun = 0x20, // don't touch checkpoint - u3o_quiet = 0x40, // disable ~& - u3o_hashless = 0x80, // disable hashboard - u3o_trace = 0x100 // enables trace dumping - }; - - /** Globals. - **/ - /* u3_Config / u3C: global memory control. - */ - c3_global u3o_config u3o_Config; -# define u3C u3o_Config - - -#endif /* ifndef U3_OPTIONS_H */ diff --git a/pkg/urbit/include/noun/retrieve.h b/pkg/urbit/include/noun/retrieve.h deleted file mode 100644 index b6e96e380..000000000 --- a/pkg/urbit/include/noun/retrieve.h +++ /dev/null @@ -1,498 +0,0 @@ -#ifndef U3_RETRIEVE_H -#define U3_RETRIEVE_H - - /** u3r_*: read without ever crashing. - **/ -#if 1 -# define u3r_du(a) u3a_is_cell(a) -# define u3r_ud(a) u3a_is_atom(a) -#else - /* u3r_du(): c3y iff `a` is cell. - */ - c3_o - u3r_du(u3_noun a); - - /* u3r_ud(): c3n iff `a` is cell. - */ - c3_o - u3r_ud(u3_noun a); -#endif - - /* u3r_at(): fragment `a` of `b`, or u3_none. - */ - u3_weak - u3r_at(u3_atom a, u3_weak b); - - /* u3r_mean(): - ** - ** Attempt to deconstruct `a` by axis, noun pairs; 0 terminates. - ** Axes must be sorted in tree order. - */ - c3_o - u3r_vmean(u3_noun a, va_list ap); - c3_o - u3r_mean(u3_noun a, ...); - - /* u3r_mug_both(): Join two mugs. - */ - c3_l - u3r_mug_both(c3_w lef_w, c3_w rit_w); - - /* u3r_mug_bytes(): Compute the mug of `buf`, `len`, LSW first. - */ - c3_l - u3r_mug_bytes(const c3_y *buf_y, - c3_w len_w); - - /* u3r_mug_c(): Compute the mug of `a`, LSB first. - */ - c3_l - u3r_mug_c(const c3_c *a_c); - - /* u3r_mug_cell(): Compute the mug of the cell `[hed tel]`. - */ - c3_l - u3r_mug_cell(u3_noun hed, - u3_noun tel); - - /* u3r_mug_chub(): Compute the mug of `num`, LSW first. - */ - c3_l - u3r_mug_chub(c3_d num_d); - - /* u3r_mug_words(): 31-bit nonzero MurmurHash3 on raw words. - */ - c3_l - u3r_mug_words(const c3_w* key_w, c3_w len_w); - - /* u3r_mug(): statefully mug a noun with 31-bit murmur3. - */ - c3_l - u3r_mug(u3_noun veb); - - /* u3r_fing(): - ** - ** Yes iff (a) and (b) are the same copy of the same noun. - ** (Ie, by pointer equality - u3r_sing with false negatives.) - */ - c3_o - u3r_fing(u3_noun a, - u3_noun b); - - /* u3r_fing_cell(): - ** - ** Yes iff `[p q]` and `b` are the same copy of the same noun. - */ - c3_o - u3r_fing_cell(u3_noun p, - u3_noun q, - u3_noun b); - - /* u3r_fing_mixt(): - ** - ** Yes iff `[p q]` and `b` are the same copy of the same noun. - */ - c3_o - u3r_fing_mixt(const c3_c* p_c, - u3_noun q, - u3_noun b); - - /* u3r_fing_trel(): - ** - ** Yes iff `[p q r]` and `b` are the same copy of the same noun. - */ - c3_o - u3r_fing_trel(u3_noun p, - u3_noun q, - u3_noun r, - u3_noun b); - - /* u3r_fing_qual(): - ** - ** Yes iff `[p q r s]` and `b` are the same copy of the same noun. - */ - c3_o - u3r_fing_qual(u3_noun p, - u3_noun q, - u3_noun r, - u3_noun s, - u3_noun b); - - /* u3r_sing(): noun value equality. - ** - ** Unifies noun pointers on inner roads. - */ - c3_o - u3r_sing(u3_noun a, u3_noun b); - - /* u3r_sing_c(): cord/C-string value equivalence. - */ - c3_o - u3r_sing_c(const c3_c* a_c, - u3_noun b); - - /* u3r_sing_cell(): - ** - ** Yes iff `[p q]` and `b` are the same noun. - */ - c3_o - u3r_sing_cell(u3_noun p, - u3_noun q, - u3_noun b); - - /* u3r_sing_mixt(): - ** - ** Yes iff `[p q]` and `b` are the same noun. - */ - c3_o - u3r_sing_mixt(const c3_c* p_c, - u3_noun q, - u3_noun b); - - /* u3r_sing_trel(): - ** - ** Yes iff `[p q r]` and `b` are the same noun. - */ - c3_o - u3r_sing_trel(u3_noun p, - u3_noun q, - u3_noun r, - u3_noun b); - - /* u3r_sing_qual(): - ** - ** Yes iff `[p q r s]` and `b` are the same noun. - */ - c3_o - u3r_sing_qual(u3_noun p, - u3_noun q, - u3_noun r, - u3_noun s, - u3_noun b); - - /* u3r_nord(): - ** - ** Return 0, 1 or 2 if `a` is below, equal to, or above `b`. - */ - u3_atom - u3r_nord(u3_noun a, - u3_noun b); - - /* u3r_mold(): - ** - ** Divide `a` as a mold `[b.[p q] c]`. - */ - c3_o - u3r_mold(u3_noun a, - u3_noun* b, - u3_noun* c); - - /* u3r_bite(): retrieve/default $bloq and $step from $bite. - */ - c3_o - u3r_bite(u3_noun bite, u3_atom* bloq, u3_atom *step); - - /* u3r_cell(): - ** - ** Divide `a` as a cell `[b c]`. - */ - c3_o - u3r_cell(u3_noun a, - u3_noun* b, - u3_noun* c); - - /* u3r_trel(): - ** - ** Divide `a` as a trel `[b c d]`. - */ - c3_o - u3r_trel(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d); - - /* u3r_qual(): - ** - ** Divide (a) as a qual [b c d e]. - */ - c3_o - u3r_qual(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d, - u3_noun* e); - - /* u3r_quil(): - ** - ** Divide (a) as a quil [b c d e f]. - */ - c3_o - u3r_quil(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d, - u3_noun* e, - u3_noun* f); - - /* u3r_hext(): - ** - ** Divide (a) as a hext [b c d e f g]. - */ - c3_o - u3r_hext(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d, - u3_noun* e, - u3_noun* f, - u3_noun* g); - - /* u3r_p(): - ** - ** & [0] if [a] is of the form [b *c]. - */ - c3_o - u3r_p(u3_noun a, - u3_noun b, - u3_noun* c); - - /* u3r_bush(): - ** - ** Factor [a] as a bush [b.[p q] c]. - */ - c3_o - u3r_bush(u3_noun a, - u3_noun* b, - u3_noun* c); - - /* u3r_pq(): - ** - ** & [0] if [a] is of the form [b *c d]. - */ - c3_o - u3r_pq(u3_noun a, - u3_noun b, - u3_noun* c, - u3_noun* d); - - /* u3r_pqr(): - ** - ** & [0] if [a] is of the form [b *c *d *e]. - */ - c3_o - u3r_pqr(u3_noun a, - u3_noun b, - u3_noun* c, - u3_noun* d, - u3_noun* e); - - /* u3r_pqrs(): - ** - ** & [0] if [a] is of the form [b *c *d *e *f]. - */ - c3_o - u3r_pqrs(u3_noun a, - u3_noun b, - u3_noun* c, - u3_noun* d, - u3_noun* e, - u3_noun* f); - - /* u3r_met(): - ** - ** Return the size of (b) in bits, rounded up to - ** (1 << a_y). - ** - ** For example, (a_y == 3) returns the size in bytes. - ** NB: (a_y) must be < 37. - */ - c3_w - u3r_met(c3_y a_y, - u3_atom b); - - /* u3r_bit(): - ** - ** Return bit (a_w) of (b). - */ - c3_b - u3r_bit(c3_w a_w, - u3_atom b); - - /* u3r_byte(): - ** - ** Return byte (a_w) of (b). - */ - c3_y - u3r_byte(c3_w a_w, - u3_atom b); - - /* u3r_bytes(): - ** - ** Copy bytes (a_w) through (a_w + b_w - 1) from (d) to (c). - */ - void - u3r_bytes(c3_w a_w, - c3_w b_w, - c3_y* c_y, - u3_atom d); - - /* u3r_bytes_fit(): - ** - ** Copy (len_w) bytes of (a) into (buf_y) if it fits, returning overage. - */ - c3_w - u3r_bytes_fit(c3_w len_w, - c3_y* buf_y, - u3_atom a); - - /* u3r_bytes_alloc(): - ** - ** Copy (len_w) bytes starting at (a_w) from (b) into a fresh allocation. - */ - c3_y* - u3r_bytes_alloc(c3_w a_w, - c3_w len_w, - u3_atom b); - - /* u3r_bytes_all(): - ** - ** Allocate and return a new byte array with all the bytes of (a), - ** storing the length in (len_w). - */ - c3_y* - u3r_bytes_all(c3_w* len_w, - u3_atom a); - - /* u3r_chop_bits(): - ** - ** XOR `wid_d` bits from`src_w` at `bif_g` to `dst_w` at `bif_g` - ** - ** NB: [dst_w] must have space for [bit_g + wid_d] bits - */ - void - u3r_chop_bits(c3_g bif_g, - c3_d wid_d, - c3_g bit_g, - c3_w* dst_w, - const c3_w* src_w); - - /* u3r_chop_words(): - ** - ** Into the bloq space of `met`, from position `fum` for a - ** span of `wid`, to position `tou`, XOR from `src_w` - ** into `dst_w`. - ** - ** NB: [dst_w] must have space for [tou_w + wid_w] bloqs - */ - void - u3r_chop_words(c3_g met_g, - c3_w fum_w, - c3_w wid_w, - c3_w tou_w, - c3_w* dst_w, - c3_w len_w, - const c3_w* src_w); - - /* u3r_chop(): - ** - ** Into the bloq space of `met`, from position `fum` for a - ** span of `wid`, to position `tou`, XOR from atom `src` - ** into `dst_w`. - ** - ** NB: [dst_w] must have space for [tou_w + wid_w] bloqs - */ - void - u3r_chop(c3_g met_g, - c3_w fum_w, - c3_w wid_w, - c3_w tou_w, - c3_w* dst_w, - u3_atom src); - - /* u3r_mp(): - ** - ** Copy (b) into (a_mp). - */ - void - u3r_mp(mpz_t a_mp, - u3_atom b); - - /* u3r_short(): - ** - ** Return short (a_w) of (b). - */ - c3_s - u3r_short(c3_w a_w, - u3_atom b); - - /* u3r_word(): - ** - ** Return word (a_w) of (b). - */ - c3_w - u3r_word(c3_w a_w, - u3_atom b); - - - /* u3r_word_fit(): - ** - ** Fill (out_w) with (a) if it fits, returning success. - */ - c3_t - u3r_word_fit(c3_w* out_w, - u3_atom a); - - /* u3r_chub(): - ** - ** Return double-word (a_w) of (b). - */ - c3_d - u3r_chub(c3_w a_w, - u3_atom b); - - /* u3r_words(): - ** - ** Copy words (a_w) through (a_w + b_w - 1) from (d) to (c). - */ - void - u3r_words(c3_w a_w, - c3_w b_w, - c3_w* c_w, - u3_atom d); - - /* u3r_chubs(): - ** - ** Copy double-words (a_w) through (a_w + b_w - 1) from (d) to (c). - */ - void - u3r_chubs(c3_w a_w, - c3_w b_w, - c3_d* c_d, - u3_atom d); - - /* u3r_safe_byte(): validate and retrieve byte. - */ - c3_o - u3r_safe_byte(u3_noun dat, c3_y* out_y); - - /* u3r_safe_word(): validate and retrieve word. - */ - c3_o - u3r_safe_word(u3_noun dat, c3_w* out_w); - - /* u3r_safe_chub(): validate and retrieve chub. - */ - c3_o - u3r_safe_chub(u3_noun dat, c3_d* out_d); - - /* u3r_string(): `a`, a text atom, as malloced C string. - */ - c3_c* - u3r_string(u3_atom a); - - /* u3r_tape(): `a`, a list of bytes, as malloced C string. - */ - c3_y* - u3r_tape(u3_noun a); - -#endif /* ifndef U3_RETRIEVE_H */ diff --git a/pkg/urbit/include/noun/serial.h b/pkg/urbit/include/noun/serial.h deleted file mode 100644 index 89a835b99..000000000 --- a/pkg/urbit/include/noun/serial.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef U3_SERIAL_H -#define U3_SERIAL_H - - /* opaque handles - */ - /* u3_cue_xeno: handle for cue-ing with an off-loom dictionary. - */ - typedef struct _u3_cue_xeno u3_cue_xeno; - - /* Noun serialization. All noun arguments RETAINED. - */ - - /* u3s_jam_fib(): jam without atom allocation. - ** - ** returns atom-suitable words, and *bit_w will have - ** the length (in bits). return should be freed with u3a_wfree(). - */ - c3_w - u3s_jam_fib(u3i_slab* sab_u, u3_noun a); - - /* u3s_jam_xeno(): jam with off-loom buffer (re-)allocation. - */ - c3_d - u3s_jam_xeno(u3_noun a, c3_d* len_d, c3_y** byt_y); - - /* u3s_cue(): cue [a] - */ - u3_noun - u3s_cue(u3_atom a); - - /* u3s_cue_xeno_init_with(): initialize a cue_xeno handle as specified. - */ - u3_cue_xeno* - u3s_cue_xeno_init_with(c3_d pre_d, c3_d siz_d); - - /* u3s_cue_xeno_init(): initialize a cue_xeno handle. - */ - u3_cue_xeno* - u3s_cue_xeno_init(void); - - /* u3s_cue_xeno_init(): cue on-loom, with off-loom dictionary in handle. - */ - u3_weak - u3s_cue_xeno_with(u3_cue_xeno* sil_u, - c3_d len_d, - const c3_y* byt_y); - - /* u3s_cue_xeno_init(): dispose cue_xeno handle. - */ - void - u3s_cue_xeno_done(u3_cue_xeno* sil_u); - - /* u3s_cue_xeno(): cue on-loom, with off-loom dictionary. - */ - u3_weak - u3s_cue_xeno(c3_d len_d, - const c3_y* byt_y); - - /* u3s_cue_bytes(): cue bytes onto the loom. - */ - u3_noun - u3s_cue_bytes(c3_d len_d, const c3_y* byt_y); - - /* u3s_cue_atom(): cue atom. - */ - u3_noun - u3s_cue_atom(u3_atom a); - - /* u3s_sift_ud_bytes: parse @ud. - */ - u3_weak - u3s_sift_ud_bytes(c3_w len_w, c3_y* byt_y); - - /* u3s_sift_ud: parse @ud. - */ - u3_weak - u3s_sift_ud(u3_atom a); - -#endif /* ifndef U3_SERIAL_H */ diff --git a/pkg/urbit/include/noun/trace.h b/pkg/urbit/include/noun/trace.h deleted file mode 100644 index e887feb3a..000000000 --- a/pkg/urbit/include/noun/trace.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef U3_TRACE_H -#define U3_TRACE_H - - /** Data structures. - **/ - /* u3t_trace: fast execution flags. - */ - typedef struct _u3t_trace { - c3_o noc_o; // now executing in nock interpreter - c3_o glu_o; // now executing in jet glue - c3_o mal_o; // now executing in allocator - c3_o far_o; // now executing in fragmentor - c3_o coy_o; // now executing in copy - c3_o euq_o; // now executing in equal - } u3t_trace; - - /** Macros. - **/ -# ifdef U3_CPU_DEBUG -# define u3t_on(var) \ - (u3T.var = (u3C.wag_w & u3o_debug_cpu) \ - ? (c3n == u3T.var) ? c3y : (abort(), 0) \ - : u3T.var) -# else -# define u3t_on(var) -#endif - -# ifdef U3_CPU_DEBUG -# define u3t_off(var) \ - (u3T.var = (u3C.wag_w & u3o_debug_cpu) \ - ? (c3y == u3T.var) ? c3n : (abort(), 0) \ - : u3T.var) -# else -# define u3t_off(var) -#endif - - - /** Functions. - **/ - /* u3t_init(): initialize tracing layer. - */ - void - u3t_init(void); - - /* u3t_push(): push on trace stack. - */ - void - u3t_push(u3_noun mon); - - /* u3t_mean(): push `[%mean roc]` on trace stack. - */ - void - u3t_mean(u3_noun roc); - - /* u3t_drop(): drop from meaning stack. - */ - void - u3t_drop(void); - - /* u3t_slog(): print directly. - */ - void - u3t_slog(u3_noun hod); - - /* u3t_heck(): profile point. - */ - void - u3t_heck(u3_atom cog); - - /* u3t_samp(): sample. - */ - void - u3t_samp(void); - - /* u3t_come(): push on profile stack; return yes if active push. RETAIN. - */ - c3_o - u3t_come(u3_noun bat); - - /* u3t_flee(): pop off profile stack. - */ - void - u3t_flee(void); - - /* u3t_trace_open(): opens the path for writing tracing information. - */ - void - u3t_trace_open(); - - /* u3t_trace_close(): closes the trace file. optional. - */ - void - u3t_trace_close(); - - /* u3t_trace_time(): returns current time since system epoc, - * whatever it is per system, in microseconds. - */ - c3_d - u3t_trace_time(); - - /* u3t_nock_trace_push(): pushes a frame onto the trace stack; - * return yes if active push. - */ - c3_o - u3t_nock_trace_push(u3_noun lab); - - /* u3t_nock_trace_pop(): pop off trace stack. - */ - void - u3t_nock_trace_pop(); - - /* u3t_event_trace(): record a lifecycle event. - */ - void - u3t_event_trace(const c3_c* name, c3_c type); - - /* u3t_damp(): print and clear profile data. - */ - void - u3t_damp(FILE* fil_u); - - /* u3t_boff(): turn profile sampling off. - */ - void - u3t_boff(void); - - /* u3t_boot(): turn sampling on. - */ - void - u3t_boot(void); - - /* u3t_slog_cap(): slog a tank with a caption with - ** a given priority c3_l (assumed 0-3). - */ - void - u3t_slog_cap(c3_l pri_l, u3_noun cap, u3_noun tan); - - /* u3t_slog_trace(): given a c3_l priority pri and a raw stack tax - ** flop the order into start-to-end, render, and slog each item - ** until done. - */ - void - u3t_slog_trace(c3_l pri_l, u3_noun tax); - - /* u3t_slog_nara(): slog only the deepest road's trace with - ** c3_l priority pri - */ - void - u3t_slog_nara(c3_l pri_l); - - /* u3t_slog_hela(): join all roads' traces together into one tax - ** and pass it to slog_trace along with the given c3_l priority pri_l - */ - void - u3t_slog_hela(c3_l pri_l); - - /** Globals. - **/ - /* u3_Trace / u3C: global memory control. - */ - c3_global u3t_trace u3t_Trace; -# define u3T u3t_Trace - - -#endif /* ifndef U3_TRACE_H */ diff --git a/pkg/urbit/include/noun/urth.h b/pkg/urbit/include/noun/urth.h deleted file mode 100644 index 3fe29792e..000000000 --- a/pkg/urbit/include/noun/urth.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef U3_URTH_H -#define U3_URTH_H - - /** Functions. - **/ - /* u3u_meld(): globally deduplicate memory. - */ - void - u3u_meld(void); - - /* u3u_cram(): globably deduplicate memory, and write a rock to disk. - */ - c3_o - u3u_cram(c3_c* dir_c, c3_d eve_d); - /* u3u_uncram(): restore persistent state from a rock. - */ - c3_o - u3u_uncram(c3_c* dir_c, c3_d eve_d); - - /* u3u_mmap_read(): open and mmap the file at [pat_c] for reading. - */ - c3_o - u3u_mmap_read(c3_c* cap_c, c3_c* pat_c, c3_d* out_d, c3_y** out_y); - - /* u3u_mmap(): open/create file-backed mmap at [pat_c] for read/write. - */ - c3_o - u3u_mmap(c3_c* cap_c, c3_c* pat_c, c3_d len_d, c3_y** out_y); - - /* u3u_mmap_save(): sync file-backed mmap. - */ - c3_o - u3u_mmap_save(c3_c* cap_c, c3_c* pat_c, c3_d len_d, c3_y* byt_y); - - /* u3u_munmap(): unmap the region at [byt_y]. - */ - c3_o - u3u_munmap(c3_d len_d, c3_y* byt_y); - -#endif /* ifndef U3_URTH_H */ diff --git a/pkg/urbit/include/noun/vortex.h b/pkg/urbit/include/noun/vortex.h deleted file mode 100644 index 92320620a..000000000 --- a/pkg/urbit/include/noun/vortex.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef U3_VORTEX_H -#define U3_VORTEX_H - - /** Data structures. - **/ - /* u3v_arvo: modern arvo structure. - ** NB: packed to perserve word alignment given [eve_d] - */ - typedef struct __attribute__((__packed__)) _u3v_arvo { - c3_d eve_d; // event number - u3_noun yot; // cached gates - u3_noun now; // current time - u3_noun roc; // kernel core - } u3v_arvo; - - /* u3v_home: all internal (within image) state. - ** NB: version must be last for discriminability in north road - */ - typedef struct _u3v_home { - u3a_road rod_u; // storage state - u3v_arvo arv_u; // arvo state - c3_w ver_w; // version number - } u3v_home; - - - /** Globals. - **/ - /* u3_Home / u3H: root of thread. - */ - c3_global u3v_home* u3v_Home; -# define u3H u3v_Home -# define u3A (&(u3v_Home->arv_u)) - - /** Constants. - **/ -# define u3v_version 1 - - /** Functions. - **/ - /* u3v_life(): execute initial lifecycle, producing Arvo core. - */ - u3_noun - u3v_life(u3_noun eve); - - /* u3v_boot(): evaluate boot sequence, making a kernel - */ - c3_o - u3v_boot(u3_noun eve); - - /* u3v_boot_lite(): light bootstrap sequence, just making a kernel. - */ - c3_o - u3v_boot_lite(u3_noun lit); - - /* u3v_do(): use a kernel function. - */ - u3_noun - u3v_do(const c3_c* txt_c, u3_noun arg); - - /* u3v_wish(): text expression with cache. - */ - u3_noun - u3v_wish(const c3_c* str_c); - - /* u3v_time(): set the reck time. - */ - void - u3v_time(u3_noun now); - - /* u3v_lily(): parse little atom. - */ - c3_o - u3v_lily(u3_noun fot, u3_noun txt, c3_l* tid_l); - - /* u3v_peek(): query the reck namespace. - */ - u3_noun - u3v_peek(u3_noun hap); - - /* u3v_soft_peek(): softly query the reck namespace. - */ - u3_noun - u3v_soft_peek(c3_w mil_w, u3_noun sam); - - /* u3v_poke(): insert and apply an input ovum (protected). - */ - u3_noun - u3v_poke(u3_noun ovo); - - /* u3v_tank(): dump single tank. - */ - void - u3v_tank(u3_noun blu, c3_l tab_l, u3_noun tac); - - /* u3v_punt(): dump tank list. - */ - void - u3v_punt(u3_noun blu, c3_l tab_l, u3_noun tac); - - /* u3v_sway(): print trace. - */ - void - u3v_sway(u3_noun blu, c3_l tab_l, u3_noun tax); - - /* u3v_plan(): queue ovum (external). - */ - void - u3v_plan(u3_noun pax, u3_noun fav); - - /* u3v_mark(): mark arvo kernel. - */ - c3_w - u3v_mark(FILE* fil_u); - - /* u3v_reclaim(): clear ad-hoc persistent caches to reclaim memory. - */ - void - u3v_reclaim(void); - - /* u3v_rewrite_compact(): rewrite arvo kernel for compaction. - */ - void - u3v_rewrite_compact(); - -#endif /* ifndef U3_VORTEX_H */ diff --git a/pkg/urbit/include/noun/xtract.h b/pkg/urbit/include/noun/xtract.h deleted file mode 100644 index 3c26e5e4c..000000000 --- a/pkg/urbit/include/noun/xtract.h +++ /dev/null @@ -1,160 +0,0 @@ -#ifndef U3_XTRACT_H -#define U3_XTRACT_H - - /** Constants. - **/ - /* Conventional axes for gate call. - */ -# define u3x_pay 3 // payload -# define u3x_sam 6 // sample -# define u3x_sam_1 6 -# define u3x_sam_2 12 -# define u3x_sam_3 13 -# define u3x_sam_4 24 -# define u3x_sam_5 25 -# define u3x_sam_6 26 -# define u3x_sam_12 52 -# define u3x_sam_13 53 -# define u3x_sam_7 27 -# define u3x_sam_14 54 -# define u3x_sam_15 55 -# define u3x_sam_30 110 -# define u3x_sam_31 111 -# define u3x_sam_62 222 -# define u3x_sam_63 223 -# define u3x_con 7 // context -# define u3x_con_2 14 // context -# define u3x_con_3 15 // context -# define u3x_con_sam 30 // sample in gate context -# define u3x_con_sam_2 60 -# define u3x_con_sam_3 61 -# define u3x_bat 2 // battery - - - /** Macros. - **/ - /* Word axis macros. For 31-bit axes only. - */ - /* u3x_dep(): number of axis bits. - */ -# define u3x_dep(a_w) (c3_bits_word(a_w) - 1) - - /* u3x_cap(): root axis, 2 or 3. - */ -# define u3x_cap(a_w) ({ \ - c3_assert( 1 < a_w ); \ - (0x2 | (a_w >> (u3x_dep(a_w) - 1))); }) - - /* u3x_mas(): remainder after cap. - */ -# define u3x_mas(a_w) ({ \ - c3_assert( 1 < a_w ); \ - ( (a_w & ~(1 << u3x_dep(a_w))) | (1 << (u3x_dep(a_w) - 1)) ); }) - - /* u3x_peg(): connect two axes. - */ -# define u3x_peg(a_w, b_w) \ - ( (a_w << u3x_dep(b_w)) | (b_w &~ (1 << u3x_dep(b_w))) ) - - /* u3x_atom(): atom or exit. - */ -# define u3x_atom(a) \ - ( (c3y == u3a_is_cell(a)) ? u3m_bail(c3__exit) : a ) - - /** Functions. - **/ - /** u3x_*: read, but bail with c3__exit on a crash. - **/ -#if 1 -# define u3x_h(som) u3a_h(som) -# define u3x_t(som) u3a_t(som) -#else - /* u3x_h (u3h): head. - */ - u3_noun - u3x_h(u3_noun som); - - /* u3x_t (u3t): tail. - */ - u3_noun - u3x_t(u3_noun som); -#endif - /* u3x_good(): test for u3_none. - */ - u3_noun - u3x_good(u3_weak som); - - /* u3x_at (u3at): fragment. - */ - u3_noun - u3x_at(u3_noun axe, u3_noun som); - - /* u3x_mean(): - ** - ** Attempt to deconstruct `a` by axis, noun pairs; 0 terminates. - ** Axes must be sorted in tree order. - */ - void - u3x_mean(u3_noun a, ...); - - /* u3x_bite(): xtract/default $bloq and $step from $bite. - */ - void - u3x_bite(u3_noun bite, u3_atom* bloq, u3_atom *step); - - /* u3x_cell(): - ** - ** Divide `a` as a cell `[b c]`. - */ - void - u3x_cell(u3_noun a, - u3_noun* b, - u3_noun* c); - - /* u3x_trel(): - ** - ** Divide `a` as a trel `[b c d]`, or bail. - */ - void - u3x_trel(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d); - - /* u3x_qual(): - ** - ** Divide `a` as a quadruple `[b c d e]`. - */ - void - u3x_qual(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d, - u3_noun* e); - - /* u3x_quil(): - ** - ** Divide `a` as a quintuple `[b c d e f]`. - */ - void - u3x_quil(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d, - u3_noun* e, - u3_noun* f); - - /* u3x_hext(): - ** - ** Divide `a` as a hextuple `[b c d e f g]`. - */ - void - u3x_hext(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d, - u3_noun* e, - u3_noun* f, - u3_noun* g); - -#endif /* ifndef U3_XTRACT_H */ diff --git a/pkg/urbit/include/noun/zave.h b/pkg/urbit/include/noun/zave.h deleted file mode 100644 index 2f637c0ea..000000000 --- a/pkg/urbit/include/noun/zave.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef U3_ZAVE_H -#define U3_ZAVE_H - - /** Memoization. - *** - *** The memo cache is keyed by an arbitrary symbolic function - *** and a noun argument to that (logical) function. Functions - *** are predefined by C-level callers, but 0 means nock. - *** - *** The memo cache is within its road and dies when it falls. - *** - *** Memo functions RETAIN keys and transfer values. - **/ - /* u3z_key*(): construct a memo cache-key. Arguments retained. - */ - u3_noun u3z_key(c3_m, u3_noun); - u3_noun u3z_key_2(c3_m, u3_noun, u3_noun); - u3_noun u3z_key_3(c3_m, u3_noun, u3_noun, u3_noun); - u3_noun u3z_key_4(c3_m, u3_noun, u3_noun, u3_noun, u3_noun); - u3_noun u3z_key_5(c3_m, u3_noun, u3_noun, u3_noun, u3_noun, u3_noun); - - /* u3z_find*(): find in memo cache. Arguments retained - */ - u3_weak u3z_find(u3_noun key); - u3_weak u3z_find_m(c3_m fun_m, u3_noun one); - - /* u3z_save(): save in memo cache. TRANSFER key; RETAIN val; - */ - u3_noun u3z_save(u3_noun key, u3_noun val); - - /* u3z_save_m(): save in memo cache. Arguments retained - */ - u3_noun u3z_save_m(c3_m fun_m, u3_noun one, u3_noun val); - - /* u3z_uniq(): uniquify with memo cache. - */ - u3_noun - u3z_uniq(u3_noun som); - -#endif /* ifndef U3_ZAVE_H */ diff --git a/pkg/urbit/include/ur/bitstream.h b/pkg/urbit/include/ur/bitstream.h deleted file mode 100644 index 8e7ae7f94..000000000 --- a/pkg/urbit/include/ur/bitstream.h +++ /dev/null @@ -1,235 +0,0 @@ -#ifndef UR_BITSTREAM_H -#define UR_BITSTREAM_H - -#include - -/* -** stateful bitstream reader, backed by a byte-buffer, -** maintaing a 64-bit bit-cursor, and supporting a variety -** of read sizes and patterns. -** -** NB: ur_bsr*_any() functions behave as if the stream were infinite, -** subject to the overall limit of the bit-cursor. -** -*/ -typedef struct ur_bsr_s { - uint64_t left; - uint64_t bits; - uint8_t off; - const uint8_t *bytes; -} ur_bsr_t; - -/* -** generalized bitstream-reader/cue response enum -*/ -typedef enum { - ur_cue_good = 0, // successful read - ur_cue_back = 1, // missing backreference - ur_cue_gone = 2, // read off the end of the stream - ur_cue_meme = 3 // exceeded memory representation -} ur_cue_res_e; - -/* -** jam/cue type tag enumeration -*/ -typedef enum { - ur_jam_atom = 0, - ur_jam_cell = 1, - ur_jam_back = 2 -} ur_cue_tag_e; - -/* -** stateful bitstream writer, backed by a byte-buffer automatically -** reallocated with fibonacc growth, maintaing a 64-bit bit-cursor, -** and supporting a variety of write sizes and patterns. -** -*/ -typedef struct ur_bsw_s { - uint64_t prev; - uint64_t size; - uint64_t fill; - uint64_t bits; - uint8_t off; - uint8_t *bytes; -} ur_bsw_t; - -/* -** initialize bitstream-reader and check for 64-bit bit-cursor overflow. -*/ -ur_cue_res_e -ur_bsr_init(ur_bsr_t *bsr, uint64_t len, const uint8_t *bytes); - -/* -** validate bitstream-reader invariants. -*/ -ur_bool_t -ur_bsr_sane(ur_bsr_t *bsr); - -/* -** read a bit, failing at EOS -*/ -ur_cue_res_e -ur_bsr_bit(ur_bsr_t *bsr, uint8_t *out); - -/* -** read a bit -*/ -uint8_t -ur_bsr_bit_any(ur_bsr_t *bsr); - -/* -** read N (up to 8) bits into a uint8. -*/ -uint8_t -ur_bsr8_any(ur_bsr_t *bsr, uint8_t len); - -/* -** read N (up to 32) bits into a uint32. -*/ -uint32_t -ur_bsr32_any(ur_bsr_t *bsr, uint8_t len); - -/* -** read N (up to 64) bits into a uint64. -*/ -uint64_t -ur_bsr64_any(ur_bsr_t *bsr, uint8_t len); - -/* -** read N bits into a zero-initialized byte array. -*/ -void -ur_bsr_bytes_any(ur_bsr_t *bsr, uint64_t len, uint8_t *out); - -/* -** advance the bitstream cursor as if we had read N bits. -*/ -void -ur_bsr_skip_any(ur_bsr_t *bsr, uint64_t len); - -/* -** read a jam/cue type tag. -*/ -ur_cue_res_e -ur_bsr_tag(ur_bsr_t *bsr, ur_cue_tag_e *out); - -/* -** read a binary exponent, producing the binary log. -** -** read N (up to 255) zero bits followed by a 1, produce N. -*/ -ur_cue_res_e -ur_bsr_log(ur_bsr_t *bsr, uint8_t *out); - -/* -** read an atomic run-length (a la +rub). -** -** read a binary log N, then read N (up to 64) bits, -** produce (N-bits ^ (1 << N)) -*/ -ur_cue_res_e -ur_bsr_rub_len(ur_bsr_t *bsr, uint64_t *out); - -/* -** initialize bitstream-writer with prev/size for fibonacci growth. -*/ -void -ur_bsw_init(ur_bsw_t *bsw, uint64_t prev, uint64_t size); - -/* -** reallocate bitstream write buffer with max(fibonacci, step) growth. -*/ -void -ur_bsw_grow(ur_bsw_t *bsw, uint64_t step); - -/* -** validate bitstream-writer invariants. -*/ -ur_bool_t -ur_bsw_sane(ur_bsw_t *bsw); - -/* -** return bit-length, produce byte-buffer. -*/ -uint64_t -ur_bsw_done(ur_bsw_t *bsw, uint64_t *len, uint8_t **byt); - -/* -** write a bit -*/ -void -ur_bsw_bit(ur_bsw_t *bsw, uint8_t bit); - -/* -** write N (up to 8) bits of a uint8. -*/ -void -ur_bsw8(ur_bsw_t *bsw, uint8_t len, uint8_t byt); - -/* -** write N (up to 32) bits of a uint32. -*/ -void -ur_bsw32(ur_bsw_t *bsw, uint8_t len, uint32_t val); - -/* -** write N (up to 64) bits of a uint64. -*/ -void -ur_bsw64(ur_bsw_t *bsw, uint8_t len, uint64_t val); - -/* -** write N bits of a byte array. -** -** NB: [byt] must contain at least N bits. -*/ -void -ur_bsw_bytes(ur_bsw_t *bsw, uint64_t len, uint8_t *byt); - -/* -** write a binary exponent (N zero bits, followed by a 1). -*/ -void -ur_bsw_bex(ur_bsw_t *bsw, uint8_t n); - -/* -** write N (up to 64) run-length prefixed bits (a la +mat). -*/ -void -ur_bsw_mat64(ur_bsw_t *bsw, uint8_t len, uint64_t val); - -/* -** write N run-length prefixed bits (a la +mat). -** -** NB: [byt] must contain at least N bits. -*/ -void -ur_bsw_mat_bytes(ur_bsw_t *bsw, uint64_t len, uint8_t *byt); - -/* -** write a backref tag (1, 1) and N (up to 64) run-length prefixed bits. -*/ -void -ur_bsw_back64(ur_bsw_t *bsw, uint8_t len, uint64_t val); - -/* -** write an atom tag (0) and N (up to 64) run-length prefixed bits. -*/ -void -ur_bsw_atom64(ur_bsw_t *bsw, uint8_t len, uint64_t val); - -/* -** write an atom tag (0) and N run-length prefixed bits. -** -** NB: [byt] must contain at least N bits. -*/ -void -ur_bsw_atom_bytes(ur_bsw_t *bsw, uint64_t len, uint8_t *byt); - -/* -** write a cell tag (1, 0) -*/ -void -ur_bsw_cell(ur_bsw_t *bsw); - -#endif diff --git a/pkg/urbit/include/ur/defs.h b/pkg/urbit/include/ur/defs.h deleted file mode 100644 index f6c0b00cd..000000000 --- a/pkg/urbit/include/ur/defs.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef UR_DEFS_H -#define UR_DEFS_H - -#include -#include -#include - -typedef uint8_t ur_bool_t; - -#define ur_min(a, b) ( ((a) < (b)) ? (a) : (b) ) -#define ur_max(a, b) ( ((a) > (b)) ? (a) : (b) ) - -/* -** fibonacci constants, for convenient initialization of -** objects intended to be reallocated with fibonacci growth -*/ -#define ur_fib10 55 -#define ur_fib11 89 -#define ur_fib12 144 -#define ur_fib27 196418 -#define ur_fib28 317811 -#define ur_fib33 3524578 -#define ur_fib34 5702887 - -/* -** bit-masking helpers -*/ -#define ur_mask_3(a) (a & 0x7) -#define ur_mask_8(a) (a & 0xff) -#define ur_mask_31(a) (a & 0x7fffffff) -#define ur_mask_62(a) (a & 0x3fffffffffffffffULL) - -/* -** bloq (binary exponent) conversions -*/ -#define ur_bloq_up1(a) ( (a + 0x1) >> 1 ) -#define ur_bloq_up2(a) ( (a + 0x3) >> 2 ) -#define ur_bloq_up3(a) ( (a + 0x7) >> 3 ) - -/* -** atom measurement -*/ -#if (32 == (CHAR_BIT * __SIZEOF_INT__)) -# define ur_lz32 __builtin_clz -# define ur_tz32 __builtin_ctz -#elif (32 == (CHAR_BIT * __SIZEOF_LONG__)) -# define ur_lz32 __builtin_clzl -# define ur_tz32 __builtin_ctzl -#else -# error "port me" -#endif - -#if (64 == (CHAR_BIT * __SIZEOF_LONG__)) -# define ur_lz64 __builtin_clzl -# define ur_tz64 __builtin_ctzl -#elif (64 == (CHAR_BIT * __SIZEOF_LONG_LONG__)) -# define ur_lz64 __builtin_clzll -# define ur_tz64 __builtin_ctzll -#else -# error "port me" -#endif - -#define ur_lz8(a) ( ur_lz32(a) - 24 ) -#define ur_tz8 ur_tz32 - -#define ur_met0_8(a) ( (a) ? 8 - ur_lz8(a) : 0 ) -#define ur_met0_32(a) ( (a) ? 32 - ur_lz32(a) : 0 ) -#define ur_met0_64(a) ( (a) ? 64 - ur_lz64(a) : 0 ) - -/* -** unsafe wrt trailing null bytes, which are invalid -*/ -inline uint64_t -ur_met0_bytes_unsafe(uint64_t len, uint8_t *byt) -{ - uint64_t last = len - 1; - return (last << 3) + ur_met0_8(byt[last]); -} - -#define ur_met3_8(a) ur_bloq_up3(ur_met0_8(a)) -#define ur_met3_32(a) ur_bloq_up3(ur_met0_32(a)) -#define ur_met3_64(a) ur_bloq_up3(ur_met0_64(a)) - -#endif /* ifndef UR_DEFS_H */ diff --git a/pkg/urbit/include/ur/hashcons.h b/pkg/urbit/include/ur/hashcons.h deleted file mode 100644 index f1d5b075f..000000000 --- a/pkg/urbit/include/ur/hashcons.h +++ /dev/null @@ -1,257 +0,0 @@ -#ifndef UR_HASHCONS_H -#define UR_HASHCONS_H - -#include -#include -#include -#include - -#include "ur/defs.h" - -/* -** 64-bit noun references, with the top 2 bits reserved for type tags. -*/ -typedef uint64_t ur_nref; - -typedef enum { - ur_direct = 0, - ur_iatom = 1, - ur_icell = 2, -} ur_tag; - -#define ur_nref_tag(ref) ( ref >> 62 ) -#define ur_nref_idx(ref) ur_mask_62(ref) - -/* -** 31-bit, non-zero, murmur3-based noun hash. -*/ -typedef uint32_t ur_mug; - -/* -** associative structures (dictionaries) of noun references, -** distributed by mug across fixed-size buckets (pails), -** reallocated with fibonacci growth once a bucket is full. -** -** - ur_dict_t: set of noun references -** - ur_dict32_t: map from noun reference to uint32 -** - ur_dict32_t: map from noun reference to uint64 -*/ - -#define ur_pail_max 10 - -typedef struct ur_pail32_s { - ur_nref refs[ur_pail_max]; - uint32_t vals[ur_pail_max]; -} ur_pail32_t; - -typedef struct ur_dict32_s { - uint64_t prev; - uint64_t size; - uint8_t *fills; - ur_pail32_t *buckets; -} ur_dict32_t; - -typedef struct ur_pail64_s { - ur_nref refs[ur_pail_max]; - uint64_t vals[ur_pail_max]; -} ur_pail64_t; - -typedef struct ur_dict64_s { - uint64_t prev; - uint64_t size; - uint8_t *fills; - ur_pail64_t *buckets; -} ur_dict64_t; - -typedef struct ur_pail_s { - ur_nref refs[ur_pail_max]; -} ur_pail_t; - -typedef struct ur_dict_s { - uint64_t prev; - uint64_t size; - uint8_t *fills; - ur_pail_t *buckets; -} ur_dict_t; - -/* -** cells are hash-consed, atoms are deduplicated (byte-array comparison), -** mug hashes are stored, and noun references are unique within a root. -*/ -typedef struct ur_cells_s { - ur_dict_t dict; - uint64_t prev; - uint64_t size; - uint64_t fill; - ur_mug *mugs; - ur_nref *heads; - ur_nref *tails; -} ur_cells_t; - -typedef struct ur_atoms_s { - ur_dict_t dict; - uint64_t prev; - uint64_t size; - uint64_t fill; - ur_mug *mugs; - uint8_t **bytes; - uint64_t *lens; -} ur_atoms_t; - -typedef struct ur_root_s { - ur_cells_t cells; - ur_atoms_t atoms; -} ur_root_t; - -/* -** a vector of noun references. -*/ -typedef struct ur_nvec_s { - uint64_t fill; - ur_nref* refs; -} ur_nvec_t; - -/* -** opaque handle for repeated traversal. -*/ -typedef struct ur_walk_fore_s ur_walk_fore_t; - -/* -** type-specific dictionary operations. -** -** NB: [r] is only used to retrieve the stored mug of cells and -** indirect atoms. If all references are direct atoms (62-bits or less), -** [r] can be null. This option is used extensively in cue (de-serialization) -** implementations, where the dictionary keys are bit-cursors. -*/ -void -ur_dict32_grow(ur_root_t *r, ur_dict32_t *dict, uint64_t prev, uint64_t size); - -ur_bool_t -ur_dict32_get(ur_root_t *r, ur_dict32_t *dict, ur_nref ref, uint32_t *out); - -void -ur_dict32_put(ur_root_t *r, ur_dict32_t *dict, ur_nref ref, uint32_t val); - -void -ur_dict32_wipe(ur_dict32_t *dict); - -void -ur_dict64_grow(ur_root_t *r, ur_dict64_t *dict, uint64_t prev, uint64_t size); - -ur_bool_t -ur_dict64_get(ur_root_t *r, ur_dict64_t *dict, ur_nref ref, uint64_t *out); - -void -ur_dict64_put(ur_root_t *r, ur_dict64_t *dict, ur_nref ref, uint64_t val); - -void -ur_dict64_wipe(ur_dict64_t *dict); - -void -ur_dict_grow(ur_root_t *r, ur_dict_t *dict, uint64_t prev, uint64_t size); - -ur_bool_t -ur_dict_get(ur_root_t *r, ur_dict_t *dict, ur_nref ref); - -void -ur_dict_put(ur_root_t *r, ur_dict_t *dict, ur_nref ref); - -void -ur_dict_wipe(ur_dict_t *dict); - -/* -** free the buckets of any dictionary (cast to ur_dict_t*). -*/ -void -ur_dict_free(ur_dict_t *dict); - -/* -** measure the bloq (binary-exponent) length of an atom in [r] -*/ -uint64_t -ur_met(ur_root_t *r, uint8_t bloq, ur_nref ref); - -/* -** find or allocate an atom in [r] -** -** unsafe variant is unsafe wrt allocation (byte arrays must be -** allocated with system malloc) and trailing null bytes (not allowed). -*/ -ur_nref -ur_coin_bytes_unsafe(ur_root_t *r, uint64_t len, uint8_t *byt); - -ur_nref -ur_coin_bytes(ur_root_t *r, uint64_t len, uint8_t *byt); - -ur_nref -ur_coin64(ur_root_t *r, uint64_t n); - -/* -** find or construct a cell in [r] -*/ -ur_nref -ur_cons(ur_root_t *r, ur_nref hed, ur_nref tal); - -/* -** calculate the mug of [ref], or produce the stored value in [r]. -*/ -ur_mug -ur_nref_mug(ur_root_t *r, ur_nref ref); - -/* -** initialize a noun arena (root). -*/ -ur_root_t* -ur_root_init(void); - -/* -** print root details to [f] -*/ -void -ur_root_info(FILE *f, ur_root_t *r); - -/* -** dispose all allocations in [r] -*/ -void -ur_root_free(ur_root_t *r); - -/* -** initialize or dispose a vector of noun references -*/ -void -ur_nvec_init(ur_nvec_t *v, uint64_t size); - -void -ur_nvec_free(ur_nvec_t *v); - -/* -** depth-first, pre-order noun traversal, cells can short-circuit. -*/ -void -ur_walk_fore(ur_root_t *r, - ur_nref ref, - void *v, - void (*atom)(ur_root_t*, ur_nref, void*), - ur_bool_t (*cell)(ur_root_t*, ur_nref, void*)); - -ur_walk_fore_t* -ur_walk_fore_init_with(ur_root_t *r, - uint32_t s_prev, - uint32_t s_size); - -ur_walk_fore_t* -ur_walk_fore_init(ur_root_t *r); - -void -ur_walk_fore_with(ur_walk_fore_t *w, - ur_nref ref, - void *v, - void (*atom)(ur_root_t*, ur_nref, void*), - ur_bool_t (*cell)(ur_root_t*, ur_nref, void*)); - -void -ur_walk_fore_done(ur_walk_fore_t *w); - -#endif /* ifndef UR_HASHCONS_H */ diff --git a/pkg/urbit/include/ur/serial.h b/pkg/urbit/include/ur/serial.h deleted file mode 100644 index 6010df6b6..000000000 --- a/pkg/urbit/include/ur/serial.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef UR_SERIAL_H -#define UR_SERIAL_H - -#include -#include -#include -#include - -/* -** bit-wise serialization of a noun into a byte-buffer. -** supports up to 64-bits of bit-addressed output (nearly 2 EiB). -** (as this is an impractical volume data, cursor overflow is not checked.) -** -** jam_with* api factors out stack/dict (re)allocation, -** for better performance inside hot loops. -** -*/ - -typedef struct ur_jam_s ur_jam_t; - -uint64_t -ur_jam_unsafe(ur_root_t *r, - ur_nref ref, - ur_dict64_t *dict, - uint64_t *len, - uint8_t **byt); - -uint64_t -ur_jam(ur_root_t *r, - ur_nref ref, - uint64_t *len, - uint8_t **byt); - -ur_jam_t* -ur_jam_init_with(ur_root_t *r, - uint64_t d_prev, - uint64_t d_size, - uint32_t s_prev, - uint32_t s_size); - -ur_jam_t* -ur_jam_init(ur_root_t *r); - -uint64_t -ur_jam_with(ur_jam_t *j, - ur_nref ref, - uint64_t *len, - uint8_t **byt); -void -ur_jam_done(ur_jam_t *j); - -/* -** bitwise deserialization of a byte-buffer into a noun. -** supports up to 62-bits of bit-addressed input (511 PiB). -** returns [ur_cue_good] on success. -** -** cue_with factors out stack/dict (re)allocation, -** for better performance of hot loops. -** -** cue_test does not allocate nouns, but merely parses the input; -** cue_test_with* api factors out stack/dict (re)allocation, -** for better performance of repeated tests. -** -*/ - -typedef struct ur_cue_test_s ur_cue_test_t; -typedef struct ur_cue_s ur_cue_t; - -ur_cue_res_e -ur_cue(ur_root_t *r, uint64_t len, const uint8_t *byt, ur_nref *out); - -ur_cue_t* -ur_cue_init_with(ur_root_t *r, - uint64_t d_prev, - uint64_t d_size, - uint32_t s_prev, - uint32_t s_size); - -ur_cue_t* -ur_cue_init(ur_root_t *r); - -ur_cue_res_e -ur_cue_with(ur_cue_t *c, - uint64_t len, - const uint8_t *byt, - ur_nref *out); - -void -ur_cue_done(ur_cue_t *c); - -ur_bool_t -ur_cue_test(uint64_t len, const uint8_t *byt); - -ur_cue_test_t* -ur_cue_test_init_with(uint64_t d_prev, - uint64_t d_size, - uint32_t s_prev, - uint32_t s_size); - -ur_cue_test_t* -ur_cue_test_init(void); - -ur_bool_t -ur_cue_test_with(ur_cue_test_t *t, - uint64_t len, - const uint8_t *byt); - -void -ur_cue_test_done(ur_cue_test_t *t); - -#endif /* ifndef UR_SERIAL_H */ diff --git a/pkg/urbit/include/ur/ur.h b/pkg/urbit/include/ur/ur.h deleted file mode 100644 index 5665a3cc4..000000000 --- a/pkg/urbit/include/ur/ur.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef UR_H -#define UR_H - -#include "ur/defs.h" -#include "ur/bitstream.h" -#include "ur/hashcons.h" -#include "ur/serial.h" - -#endif /* ifndef UR_H */ diff --git a/pkg/urbit/include/vere/db/lmdb.h b/pkg/urbit/include/vere/db/lmdb.h deleted file mode 100644 index 573a68fa4..000000000 --- a/pkg/urbit/include/vere/db/lmdb.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef U3_VERE_DB_LMDB_H -#define U3_VERE_DB_LMDB_H - -#include - - /* lmdb api wrapper - */ - - /* u3_lmdb_init(): open lmdb at [pax_c], mmap up to [siz_i]. - */ - MDB_env* - u3_lmdb_init(const c3_c* pax_c, size_t siz_i); - - /* u3_lmdb_exit(): close lmdb. - */ - void - u3_lmdb_exit(MDB_env* env_u); - - - /* u3_lmdb_stat(): print env stats. - */ - void - u3_lmdb_stat(MDB_env* env_u, FILE* fil_u); - - /* u3_lmdb_gulf(): read first and last event numbers. - */ - c3_o - u3_lmdb_gulf(MDB_env* env_u, c3_d* low_d, c3_d* hig_d); - - /* u3_lmdb_read(): read [len_d] events starting at [eve_d]. - */ - c3_o - u3_lmdb_read(MDB_env* env_u, - void* ptr_v, - c3_d eve_d, - c3_d len_d, - c3_o (*read_f)(void*, c3_d, size_t , void*)); - - /* u3_lmdb_save(): save [len_d] events starting at [eve_d]. - */ - c3_o - u3_lmdb_save(MDB_env* env_u, - c3_d eve_d, - c3_d len_d, - void** byt_p, - size_t* siz_i); - - /* u3_lmdb_read_meta(): read by string from the META db. - */ - void - u3_lmdb_read_meta(MDB_env* env_u, - void* ptr_v, - const c3_c* key_c, - void (*read_f)(void*, size_t, void*)); - - /* u3_lmdb_save_meta(): save by string into the META db. - */ - c3_o - u3_lmdb_save_meta(MDB_env* env_u, - const c3_c* key_c, - size_t val_i, - void* val_p); - -#endif /* ifndef U3_VERE_DB_LMDB_H */ diff --git a/pkg/urbit/include/vere/ivory.h b/pkg/urbit/include/vere/ivory.h deleted file mode 100644 index 8ebc94c92..000000000 --- a/pkg/urbit/include/vere/ivory.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef U3_IVORY_H -#define U3_IVORY_H - -extern unsigned char u3_Ivory_pill[]; -extern unsigned int u3_Ivory_pill_len; - -#endif diff --git a/pkg/urbit/include/vere/serf.h b/pkg/urbit/include/vere/serf.h deleted file mode 100644 index 5808f362e..000000000 --- a/pkg/urbit/include/vere/serf.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef U3_VERE_SERF_H -#define U3_VERE_SERF_H - - /** Data types. - **/ - /* u3_serf: worker-process state - */ - typedef struct _u3_serf { - c3_d key_d[4]; // disk key - c3_c* dir_c; // execution directory (pier) - c3_d sen_d; // last event requested - c3_d dun_d; // last event processed - c3_l mug_l; // hash of state - c3_o pac_o; // pack kernel - c3_o rec_o; // reclaim cache - c3_o mut_o; // mutated kerne - u3_noun sac; // space measurementl - void (*xit_f)(void); // exit callback - } u3_serf; - - /** Functions. - **/ - /* u3_serf_init(): init or restore, producing status. - */ - u3_noun - u3_serf_init(u3_serf* sef_u); - - /* u3_serf_writ(): apply writ [wit], producing plea [*pel] on c3y. - */ - c3_o - u3_serf_writ(u3_serf* sef_u, u3_noun wit, u3_noun* pel); - - /* u3_serf_live(): apply %live command [com], producing *ret on c3y. - */ - c3_o - u3_serf_live(u3_serf* sef_u, u3_noun com, u3_noun* ret); - - /* u3_serf_peek(): read namespace. - */ - u3_noun - u3_serf_peek(u3_serf* sef_u, c3_w mil_w, u3_noun sam); - - /* u3_serf_play(): apply event list, producing status. - */ - u3_noun - u3_serf_play(u3_serf* sef_u, c3_d eve_d, u3_noun lit); - - /* u3_serf_work(): apply event, producing effects. - */ - u3_noun - u3_serf_work(u3_serf* sef_u, c3_w mil_w, u3_noun job); - - /* u3_serf_post(): update serf state post-writ. - */ - void - u3_serf_post(u3_serf* sef_u); - - /* u3_serf_grab(): garbage collect. - */ - void - u3_serf_grab(void); - -#endif /* ifndef U3_VERE_SERF_H */ diff --git a/pkg/urbit/include/vere/vere.h b/pkg/urbit/include/vere/vere.h deleted file mode 100644 index ef5b4e551..000000000 --- a/pkg/urbit/include/vere/vere.h +++ /dev/null @@ -1,1467 +0,0 @@ -#ifndef U3_VERE_H -#define U3_VERE_H - -#include - - /** Quasi-tunable parameters. - **/ - /* First kernel this executable can boot. - */ -# define FirstKernel 164 -# define DefaultKernel 164 - - /** Data types. - **/ - - /* u3_hhed: http header. - */ - typedef struct _u3_hhed { - struct _u3_hhed* nex_u; - c3_w nam_w; - c3_c* nam_c; - c3_w val_w; - c3_c* val_c; - } u3_hhed; - - /* u3_hbod: http body block. Also used for responses. - */ - typedef struct _u3_hbod { - struct _u3_hbod* nex_u; - c3_w len_w; - c3_y hun_y[0]; - } u3_hbod; - - /* u3_lane: ames lane (IP address and port) - */ - typedef struct _u3_lane { - c3_w pip_w; // target IPv4 address - c3_s por_s; // target port - } u3_lane; - - /* u3_moor_poke: poke callback function. - */ - typedef void (*u3_moor_poke)(void*, c3_d, c3_y*); - - /* u3_moor_bail: bailout callback function. - */ - typedef void (*u3_moor_bail)(void*, ssize_t err_i, const c3_c* err_c); - - /* u3_meat: blob message block. - */ - typedef struct _u3_meat { - struct _u3_meat* nex_u; - c3_d len_d; - c3_y hun_y[0]; - } u3_meat; - - /* u3_mess_type: in-process message type. - */ - typedef enum { - u3_mess_head = 0, // awaiting header - u3_mess_tail = 1 // awaiting body - } u3_mess_type; - - /* u3_mess: blob message in process. - */ - typedef struct _u3_mess { - u3_mess_type sat_e; // msg type - union { // - struct { // awaiting header: - c3_y hed_y[5]; // header bytes - c3_y has_y; // length - } hed_u; // - struct { // awaiting body - u3_meat* met_u; // partial message - c3_d has_d; // length - } tal_u; // - }; - } u3_mess; - - /* u3_moat: inbound message stream. - */ - typedef struct _u3_moat { - uv_pipe_t pyp_u; // input stream - u3_moor_bail bal_f; // error response function - void* ptr_v; // callback pointer - u3_moor_poke pok_f; // action function - u3_mess mes_u; // message in progress - uv_timer_t tim_u; // queue timer - u3_meat* ent_u; // entry of message queue - u3_meat* ext_u; // exit of message queue - } u3_moat; - - /* u3_mojo: outbound message stream. - */ - typedef struct _u3_mojo { - uv_pipe_t pyp_u; // output stream - u3_moor_bail bal_f; // error response function - void* ptr_v; // callback pointer - } u3_mojo; - - /* u3_moor: two-way message stream, linked list */ - typedef struct _u3_moor { - uv_pipe_t pyp_u; // duplex stream - u3_moor_bail bal_f; // error response function - void* ptr_v; // callback pointer - u3_moor_poke pok_f; // action function - u3_mess mes_u; // message in progress - uv_timer_t tim_u; // queue timer - u3_meat* ent_u; // entry of message queue - u3_meat* ext_u; // exit of message queue - struct _u3_moor* nex_u; // next in list - } u3_moor; - - /* u3_dent: directory entry. - */ - typedef struct _u3_dent { - c3_c* nam_c; - struct _u3_dent* nex_u; - } u3_dent; - - /* u3_dire: simple directory state. - */ - typedef struct _u3_dire { - c3_c* pax_c; // path of directory - uv_file fil_u; // file, opened read-only to fsync - u3_dent* all_u; // file list - } u3_dire; - - /* u3_save: checkpoint control. - */ - typedef struct _u3_save { - uv_timer_t tim_u; // checkpoint timer - uv_signal_t sil_u; // child signal - c3_d req_d; // requested at evt_d - c3_d dun_d; // completed at evt_d - c3_w pid_w; // pid of checkpoint process - } u3_save; - - /* u3_utat: unix terminal state. - */ - typedef struct { - struct { - c3_l col_l; // columns - c3_l row_l; // rows - } siz; - - struct { - u3_noun lin; // bottom line (stub) - c3_w rus_w; // cursor position (row) - c3_w cus_w; // cursor position (column) - } mir; - - struct { // escape code control - c3_o ape; // escape received - c3_o bra; // bracket or O received - c3_o mou; // M (for mouse event) received - c3_y ton_y; // mouse button - c3_y col_y; // column coordinate - c3_y seq_y; // vt sequence - } esc; - - struct { // input buffering - c3_y syb_y[5]; // utf8 code buffer - c3_w len_w; // present length - c3_w wid_w; // total width - u3_noun imp; // %txt input buffer - } fut; - - struct { - uv_timer_t tim_u; // spinner timeout - c3_o diz_o; // spinner activated - c3_d eve_d; // spin count - c3_d end_d; // spinner end tick (ms) - c3_c why_c[5]; // spinner label - } sun_u; - } u3_utat; - - /* u3_usig: receive signals. - */ - typedef struct _u3_usig { - uv_signal_t sil_u; - c3_i num_i; - struct _u3_usig* nex_u; - } u3_usig; - - /* u2_utfo: terminal escape sequences - */ - typedef struct { - uv_buf_t mon_u; // mouse reporting on - uv_buf_t mof_u; // mouse reporting off - // - uv_buf_t reg_u; // restore scroll region - // - uv_buf_t suc_u; // save cursor position - uv_buf_t ruc_u; // restore cursor position - uv_buf_t cub_u; // move cursor left one column - // - uv_buf_t clr_u; // clear screen - uv_buf_t cel_u; // clear to end of line - // - uv_buf_t bel_u; // bel sound bell - } u3_utfo; - -#if 0 - /* u3_uwen: unix alarm. - */ - typedef struct _u3_uwen { - c3_y* pax_y; // printed path - c3_d wen_d[2]; // timer expire - }; - - /* u3_utim: unix timer control. - */ - typedef struct _u3_utim { - uv_timer_t wat_u; // timer control - u3_uwen* wen_u; // timers in ascending order - }; -#endif - - /* u3_utty: unix tty. - */ - struct _u3_utty; - - /* u3_ustm: uv stream. - */ - typedef union _u3_ustm { - uv_pipe_t pip_u; - uv_tty_t tty_u; - } u3_ustm; - - /* u3_ttyf: simple unix tty function. - */ - typedef c3_o (*u3_ttyf)(struct _u3_utty* uty_u); - - /* u3_utty: unix tty. - */ - typedef struct _u3_utty { - u3_ustm pin_u; // input stream - u3_ustm pop_u; // output stream - struct _u3_utty* nex_u; // next in host list - u3_ttyf sta_f; // start tty - u3_ttyf sto_f; // clean up tty - u3_ttyf hij_f; // hijack tty for cooked print - u3_ttyf loj_f; // release tty from cooked print - c3_o (*wsz_f) - (struct _u3_utty* uty_u, - c3_l* col_l, - c3_l* row_l); // return tty window size - c3_i fid_i; // file descriptor - c3_w tid_l; // terminal identity number - u3_utfo ufo_u; // escape sequences - u3_utat tat_u; // control state - struct _u3_auto* car_u; // driver hack - } u3_utty; - - /* u3_trac: tracing information. - */ - typedef struct _u3_trac { - c3_w nid_w; // nock pid - FILE* fil_u; // trace file (json) - c3_w con_w; // trace counter - c3_w fun_w; // file counter - } u3_trac; - - /* u3_opts: command line configuration. - */ - typedef struct _u3_opts { - c3_c* arv_c; // -A, initial sync from - c3_o abo; // -a, abort aggressively - c3_c* pil_c; // -B, bootstrap from - c3_c* bin_c; // -b, http server bind ip - c3_w hap_w; // -C, cap memo cache - c3_o nuu; // -c, new pier - c3_o dry; // -D, dry compute, no checkpoint - c3_o dem; // -d, daemon - c3_c* eth_c; // -e, ethereum node url - c3_c* fak_c; // -F, fake ship - c3_c* gen_c; // -G, czar generator - c3_o gab; // -g, test garbage collection - c3_c* dns_c; // -H, ames bootstrap domain - c3_c* jin_c; // -I, inject raw event - c3_c* imp_c; // -i, import pier state - c3_c* lit_c; // -J, ivory (fastboot) kernel - c3_o tra; // -j, json trace - c3_w kno_w; // -K, kernel version - c3_c* key_c; // -k, private key file - c3_o net; // -L, local-only networking - c3_o lit; // -l, lite mode - c3_y lom_y; // loom bex - c3_y lut_y; // urth-loom bex - c3_c* til_c; // -n, play till eve_d - c3_o pro; // -P, profile - c3_s per_s; // http port - c3_s pes_s; // https port - c3_s por_s; // -p, ames port - c3_o qui; // -q, quiet - c3_o rep; // -R, report build info - c3_c* roc_c; // -r, load rock by eve_d - c3_o has; // -S, Skip battery hashes - c3_o git; // -s, pill url from arvo git hash - c3_o tem; // -t, Disable terminal/tty assumptions - c3_c* url_c; // -u, pill url - c3_o veb; // -v, verbose (inverse of -q) - c3_c* who_c; // -w, begin with ticket - c3_c* pek_c; // -X, scry path (/vc/desk/path) - c3_o tex; // -x, exit after loading - c3_c* puk_c; // -Y, scry result filename - c3_c* puf_c; // -Z, scry result format - c3_o con; // run conn - c3_o doc; // dock binary in pier - } u3_opts; - - /* u3_host: entire host. - */ - typedef struct _u3_host { - c3_w kno_w; // current executing stage - c3_c* dir_c; // pier path (no trailing /) - c3_c* dem_c; // daemon executable path - c3_c* wrk_c; // worker executable path - c3_d now_d; // event tick - uv_loop_t* lup_u; // libuv event loop - u3_usig* sig_u; // signal list -#if defined(U3_OS_mingw) - HANDLE cev_u; // Ctrl-C event handle -#endif - u3_utty* uty_u; // linked terminal list - c3_o nex_o; // upgrade requested - c3_c* arc_c; // upgrade to arch - u3_opts ops_u; // commandline options - c3_o pep_o; // prep for upgrade - c3_i xit_i; // exit code for shutdown - u3_trac tra_u; // tracing information - void (*bot_f)(); // call when chis is up - } u3_host; // host == computer == process - - /** Pier system. - **/ - /* u3_ovum_news: u3_ovum lifecycle events - */ - typedef enum { - u3_ovum_drop = 0, // unplanned - u3_ovum_work = 1, // begun - u3_ovum_done = 2 // complete - } u3_ovum_news; - - struct _u3_ovum; - - /* u3_ovum_peer: news callback - */ - typedef void (*u3_ovum_peer)(struct _u3_ovum*, u3_ovum_news); - - /* u3_ovum_bail: failure callback - */ - typedef void (*u3_ovum_bail)(struct _u3_ovum*, u3_noun); - - /* u3_ovum: potential event - */ - typedef struct _u3_ovum { - void* ptr_v; // context - c3_w try_w; // retry count - c3_w mil_w; // timeout ms - u3_noun tar; // target (in arvo) - u3_noun wir; // wire - u3_noun cad; // card - struct { // spinner: - u3_atom lab; // label - c3_o del_o; // delay (c3y) - } pin_u; // - struct { // optional callbacks: - u3_ovum_peer news_f; // progress - u3_ovum_bail bail_f; // failure - } cb_u; // - struct _u3_ovum* pre_u; // previous ovum - struct _u3_ovum* nex_u; // next ovum - struct _u3_auto* car_u; // backpointer to i/o driver - } u3_ovum; - - /* u3_fact: completed event - */ - typedef struct _u3_fact { - c3_d eve_d; // event number - c3_l mug_l; // kernel mug after - u3_noun job; // (pair date ovum) - struct _u3_fact* nex_u; // next in queue - } u3_fact; - - /* u3_gift: effects - */ - typedef struct _u3_gift { - c3_d eve_d; // causal event number - u3_noun act; // (list ovum) - struct _u3_gift* nex_u; // next in queue - } u3_gift; - - /* u3_info: ordered, contiguous slice of facts - */ - typedef struct _u3_info { - u3_fact* ent_u; // queue entry (highest) - u3_fact* ext_u; // queue exit (lowest) - } u3_info; - - /* u3_peek_cb: namespace read response callback. - */ - typedef void (*u3_peek_cb)(void*, u3_noun); - - /* u3_pico_type: kinds of proto-peek - */ - typedef enum { - u3_pico_full = 0, - u3_pico_once = 1 - } u3_pico_type; - - /* u3_pico: proto-peek - */ - typedef struct _u3_pico { - struct _u3_pico* nex_u; // next in queue - void* ptr_v; // context - u3_peek_cb fun_f; // callback - u3_noun gan; // leakset - u3_pico_type typ_e; // type-tagged - union { // - u3_noun ful; // (each path [%beam term beam]) - struct { // once: - c3_m car_m; // care - u3_atom des; // desk - u3_noun pax; // /path - } las_u; - }; - } u3_pico; - - /* u3_peek: namespace read request - */ - typedef struct _u3_peek { - void* ptr_v; // context - u3_peek_cb fun_f; // callback - u3_pico_type typ_e; // type - u3_noun sam; // +peek sample - } u3_peek; - - /* u3_writ_type: king->serf ipc message types - */ - typedef enum { - u3_writ_work = 0, - u3_writ_peek = 1, - u3_writ_play = 2, - u3_writ_save = 3, - u3_writ_cram = 4, - u3_writ_meld = 5, - u3_writ_pack = 6, - u3_writ_exit = 7 - } u3_writ_type; - - /* u3_writ: ipc message from king to serf - */ - typedef struct _u3_writ { - struct _u3_writ* nex_u; // next in queue - u3_writ_type typ_e; // type-tagged - union { // - struct { // work: - u3_ovum* egg_u; // origin - u3_noun job; // (pair date ovum) - } wok_u; // - u3_peek* pek_u; // peek - u3_info fon_u; // recompute - c3_d eve_d; // save/pack at - }; - } u3_writ; - - /* u3_lord_cb: u3_lord callbacks - */ - typedef struct _u3_lord_cb { - void* ptr_v; - void (*live_f)(void*); - void (*slog_f)(void*, c3_w, u3_noun); - void (*spin_f)(void*, u3_atom, c3_o); - void (*spun_f)(void*); - void (*play_done_f)(void*, u3_info, c3_l mug_l); - void (*play_bail_f)(void*, u3_info, c3_l mug_l, c3_d eve_d, u3_noun dud); - void (*work_done_f)(void*, u3_ovum*, u3_fact*, u3_gift*); - void (*work_bail_f)(void*, u3_ovum*, u3_noun lud); - void (*save_f)(void*); - void (*cram_f)(void*); - void (*bail_f)(void*); - void (*exit_f)(void*); - } u3_lord_cb; - - /* u3_lord: serf controller. - */ - typedef struct _u3_lord { - uv_process_t cub_u; // process handle - uv_process_options_t ops_u; // process configuration - uv_stdio_container_t cod_u[3]; // process options - u3_cue_xeno* sil_u; // cue handle - time_t wen_t; // process creation time - u3_mojo inn_u; // client's stdin - u3_moat out_u; // client's stdout - uv_pipe_t err_u; // client's stderr - c3_w wag_w; // config flags - c3_c* bin_c; // binary path - c3_c* pax_c; // directory - c3_d key_d[4]; // image key - c3_o liv_o; // live - c3_y hon_y; // hoon kelvin - c3_y noc_y; // nock kelvin - c3_d eve_d; // last event completed - c3_l mug_l; // mug at eve_d - u3_lord_cb cb_u; // callbacks - c3_o pin_o; // spinning - c3_w dep_w; // queue depth - struct _u3_writ* ent_u; // queue entry - struct _u3_writ* ext_u; // queue exit - } u3_lord; - - /* u3_read: event log read request - */ - typedef struct _u3_read { - union { // read timer/handle - uv_timer_t tim_u; // - uv_handle_t had_u; // - }; // - c3_d eve_d; // first event - c3_d len_d; // read stride - struct _u3_fact* ent_u; // response entry - struct _u3_fact* ext_u; // response exit - struct _u3_read* nex_u; // next read - struct _u3_read* pre_u; // previous read - struct _u3_disk* log_u; // disk backpointer - } u3_read; - - /* u3_disk_cb: u3_disk callbacks - */ - typedef struct _u3_disk_cb { - void* ptr_v; - void (*read_done_f)(void*, u3_info); - void (*read_bail_f)(void*, c3_d eve_d); - void (*write_done_f)(void*, c3_d eve_d); - void (*write_bail_f)(void*, c3_d eve_d); - } u3_disk_cb; - - /* u3_disk: manage event persistence. - */ - typedef struct _u3_disk { - u3_dire* dir_u; // main pier directory - u3_dire* urb_u; // urbit system data - u3_dire* com_u; // log directory - c3_o liv_o; // live - void* mdb_u; // lmdb environment. - c3_d sen_d; // commit requested - c3_d dun_d; // committed - u3_disk_cb cb_u; // callbacks - u3_read* red_u; // read requests - union { // write thread/request - uv_work_t ted_u; // - uv_req_t req_u; // - }; // - c3_o ted_o; // c3y == active - u3_info put_u; // write queue - } u3_disk; - - /* u3_psat: pier state. - */ - typedef enum { - u3_psat_init = 0, // initialized - u3_psat_boot = 1, // bootstrap - u3_psat_play = 2, // replaying - u3_psat_wyrd = 3, // versioning - u3_psat_work = 4, // working - u3_psat_done = 5 // shutting down - } u3_psat; - - /* u3_boot: bootstrap event sequence - */ - typedef struct _u3_boot { - u3_noun bot; // boot formulas - u3_noun mod; // module ova - u3_noun use; // userpace ova - } u3_boot; - - /* u3_play: replay control. - */ - typedef struct _u3_play { - c3_d eve_d; // target - c3_d req_d; // last read requested - c3_d sen_d; // last sent - u3_fact* ent_u; // queue entry - u3_fact* ext_u; // queue exit - struct _u3_pier* pir_u; // pier backpointer - } u3_play; - - /* u3_auto_cb: i/o driver callbacks - */ - typedef struct _u3_auto_cb { - void (*talk_f)(struct _u3_auto*); - u3_noun (*info_f)(struct _u3_auto*); - void (*slog_f)(struct _u3_auto*); - c3_o (*kick_f)(struct _u3_auto*, u3_noun, u3_noun); - void (*exit_f)(struct _u3_auto*); // XX close_cb? - } u3_auto_cb; - - /* u3_auto: abstract i/o driver - */ - typedef struct _u3_auto { - c3_m nam_m; - c3_o liv_o; - u3_auto_cb io; // XX io_u; - c3_w dep_w; - struct _u3_ovum* ent_u; - struct _u3_ovum* ext_u; - struct _u3_auto* nex_u; - struct _u3_pier* pir_u; - } u3_auto; - - /* u3_wall: pier barrier - */ - typedef struct _u3_wall { - void* ptr_v; - c3_d eve_d; - void (*wal_f)(void*, c3_d); - struct _u3_wall* nex_u; - } u3_wall; - - /* u3_work: normal operation. - */ - typedef struct _u3_work { - u3_auto* car_u; // i/o drivers - u3_wall* wal_u; // barriers - struct { // finished event queue: - c3_d rel_d; // last released - u3_gift* ent_u; // entry - u3_gift* ext_u; // exit - } fec_u; // - uv_prepare_t pep_u; // pre-loop - uv_check_t cek_u; // post-loop - uv_idle_t idl_u; // catchall XX uv_async_t? - struct _u3_pier* pir_u; // pier backpointer - } u3_work; - - /* u3_pier: ship controller. - */ - typedef struct _u3_pier { - c3_c* pax_c; // pier directory - c3_w lif_w; // lifecycle barrier - c3_d who_d[2]; // identity - c3_o fak_o; // yes iff fake security - c3_o liv_o; // fully live - u3_disk* log_u; // event log - u3_lord* god_u; // computer - u3_psat sat_e; // type-tagged - union { // - u3_boot* bot_u; // bootstrap - u3_play* pay_u; // recompute - u3_work* wok_u; // work - }; - struct { - u3_pico* ent_u; - u3_pico* ext_u; - } pec_u; - void* sop_p; // slog stream data - void (*sog_f) // slog stream callback - (void*, c3_w, u3_noun);// - // XX remove - c3_s per_s; // http port - c3_s pes_s; // htls port - c3_s por_s; // ames port - u3_save* sav_u; // autosave - // XX end remove - struct _u3_pier* nex_u; // next in list - } u3_pier; - - /* u3_king: all executing piers. - */ - typedef struct _u3_king { - void (*ssl_curl_f)(void*); // setup ssl CAs in CURL* - void (*ssl_x509_f)(void*); // setup ssl CAs in X509_STORE* - u3_pier* pir_u; // pier list - uv_timer_t tim_u; // gc timer - } u3_king; - - /* u3_pier_spin(): (re-)activate idle handler - */ - void - u3_pier_spin(u3_pier* pir_u); - -# define u3L u3_Host.lup_u // global event loop -# define u3K u3_King - - /** Global variables. - **/ - c3_global u3_host u3_Host; - c3_global c3_c* u3_Local; - c3_global u3_king u3_King; - - /** Functions. - **/ - /* Urbit time: 128 bits, leap-free. - ** - ** High 64 bits: 0x8000.000c.cea3.5380 + Unix time at leap 25 (Jul 2012) - ** Low 64 bits: 1/2^64 of a second. - ** - ** Seconds per Gregorian 400-block: 12.622.780.800 - ** 400-blocks from 0 to 0AD: 730.692.561 - ** Years from 0 to 0AD: 292.277.024.400 - ** Seconds from 0 to 0AD: 9.223.372.029.693.628.800 - ** Seconds between 0A and Unix epoch: 62.167.219.200 - ** Seconds before Unix epoch: 9.223.372.091.860.848.000 - ** The same, in C hex notation: 0x8000000cce9e0d80ULL - ** - ** XX: needs to be adjusted to implement Google leap-smear time. - */ - /* u3_time_sec_in(): urbit seconds from unix time. - ** - ** Adjust (externally) for future leap secs! - */ - c3_d - u3_time_sec_in(c3_w unx_w); - - /* u3_time_sec_out(): unix time from urbit seconds. - ** - ** Adjust (externally) for future leap secs! - */ - c3_w - u3_time_sec_out(c3_d urs_d); - - /* u3_time_fsc_in(): urbit fracto-seconds from unix microseconds. - */ - c3_d - u3_time_fsc_in(c3_w usc_w); - - /* u3_time_fsc_out: unix microseconds from urbit fracto-seconds. - */ - c3_w - u3_time_fsc_out(c3_d ufc_d); - - /* u3_time_in_tv(): urbit time from struct timeval. - */ - u3_atom - u3_time_in_tv(struct timeval* tim_tv); - - /* u3_time_out_tv(): struct timeval from urbit time. - */ - void - u3_time_out_tv(struct timeval* tim_tv, u3_noun now); - - /* u3_time_in_ts(): urbit time from struct timespec. - */ - u3_atom - u3_time_in_ts(struct timespec* tim_ts); -#if defined(U3_OS_linux) || defined(U3_OS_mingw) - /* u3_time_t_in_ts(): urbit time from time_t. - */ - u3_atom - u3_time_t_in_ts(time_t tim); -#endif - - /* u3_time_out_ts(): struct timespec from urbit time. - */ - void - u3_time_out_ts(struct timespec* tim_ts, u3_noun now); - - /* u3_time_gap_ms(): (wen - now) in ms. - */ - c3_d - u3_time_gap_ms(u3_noun now, u3_noun wen); - - /** Common structure lifecycle. - **/ - /* u3_dent_init(): initialize file record. - */ - u3_dent* - u3_dent_init(const c3_c* nam_c); - - /* u3_dent_free(): dispose file record. - */ - void - u3_dent_free(u3_dent *det_u); - - /* u3_dire_init(): initialize directory record. - */ - u3_dire* - u3_dire_init(const c3_c* pax_c); - - /* u3_dire_free(): dispose directory record. - */ - void - u3_dire_free(u3_dire *dir_u); - - /* u3_fact_init(): initialize completed event. - */ - u3_fact* - u3_fact_init(c3_d eve_d, c3_l mug_l, u3_noun job); - - /* u3_fact_free(): dispose completed event. - */ - void - u3_fact_free(u3_fact *tac_u); - - /* u3_gift_init(): initialize effect list. - */ - u3_gift* - u3_gift_init(c3_d eve_d, u3_noun act); - - /* u3_gift_free(): dispose effect list. - */ - void - u3_gift_free(u3_gift* gif_u); - - /* u3_ovum_init: initialize an unlinked potential event - */ - u3_ovum* - u3_ovum_init(c3_w mil_w, - u3_noun tar, - u3_noun wir, - u3_noun cad); - - /* u3_ovum_free: dispose an unlinked potential event - */ - void - u3_ovum_free(u3_ovum *egg_u); - - /* u3_pico_init(): initialize a scry request struct - */ - u3_pico* - u3_pico_init(); - - /* u3_pico_free(): dispose a scry request struct - */ - void - u3_pico_free(u3_pico* pic_u); - - /* u3_mcut_char(): measure/cut character. - */ - c3_w - u3_mcut_char(c3_c* buf_c, c3_w len_w, c3_c chr_c); - - /* u3_mcut_cord(): measure/cut cord. - */ - c3_w - u3_mcut_cord(c3_c* buf_c, c3_w len_w, u3_noun san); - - /* u3_mcut_path(): measure/cut cord list. - */ - c3_w - u3_mcut_path(c3_c* buf_c, c3_w len_w, c3_c sep_c, u3_noun pax); - - /* u3_mcut_host(): measure/cut host. - */ - c3_w - u3_mcut_host(c3_c* buf_c, c3_w len_w, u3_noun hot); - - /** IO drivers. - **/ - /* u3_auto_init(): initialize all drivers. - */ - u3_auto* - u3_auto_init(u3_pier* pir_u); - - /* u3_auto_info(): status info as a (list mass), all drivers. - */ - u3_noun - u3_auto_info(u3_auto* car_u); - - /* u3_auto_slog(): print status info. - */ - void - u3_auto_slog(u3_auto* car_u); - - /* u3_auto_exit(): close all drivers. - */ - void - u3_auto_exit(u3_auto* car_u); - - /* u3_auto_talk(): start all drivers. - */ - void - u3_auto_talk(u3_auto* car_u); - - /* u3_auto_live(): check if all drivers are live. - */ - c3_o - u3_auto_live(u3_auto* car_u); - - /* u3_auto_kick(): route effects to a linked driver. RETAIN - */ - void - u3_auto_kick(u3_auto* car_u, u3_noun act); - - /* u3_auto_next(): select an ovum, dequeue and construct. - */ - u3_ovum* - u3_auto_next(u3_auto* car_u, u3_noun* ovo); - - /* u3_auto_drop(): dequeue and dispose an ovum. - */ - void - u3_auto_drop(u3_auto* car_u, u3_ovum* egg_u); - - /* u3_auto_work(): notify driver of [egg_u] commencement. - */ - void - u3_auto_work(u3_ovum* egg_u); - - /* u3_auto_done(): notify driver of [egg_u] completion. - */ - void - u3_auto_done(u3_ovum* egg_u); - - /* u3_auto_bail(): notify driver that [egg_u] crashed. - */ - void - u3_auto_bail(u3_ovum* egg_u, u3_noun lud); - - /* u3_auto_bail_slog(): print a bail notification. - */ - void - u3_auto_bail_slog(u3_ovum* egg_u, u3_noun lud); - - /* u3_auto_plan(): enqueue an ovum. - */ - u3_ovum* - u3_auto_plan(u3_auto* car_u, u3_ovum* egg_u); - - /* u3_auto_redo(): retry an ovum. - */ - u3_ovum* - u3_auto_redo(u3_auto* car_u, u3_ovum* egg_u); - - /* u3_auto_peer(): subscribe to updates. - */ - void - u3_auto_peer(u3_ovum* egg_u, - void* ptr_v, - u3_ovum_peer news_f, - u3_ovum_bail bail_f); - - /* u3_disk_init(): load or create pier directories and event log. - */ - u3_disk* - u3_disk_init(c3_c* pax_c, u3_disk_cb cb_u); - - /* u3_disk_info(): status info as $mass. - */ - u3_noun - u3_disk_info(u3_disk* log_u); - - /* u3_disk_slog(): print status info. - */ - void - u3_disk_slog(u3_disk* log_u); - - /* u3_disk_exit(): close [log_u] and dispose. - */ - void - u3_disk_exit(u3_disk* log_u); - - /* u3_disk_read_meta(): read metadata. - */ - c3_o - u3_disk_read_meta(u3_disk* log_u, - c3_d* who_d, - c3_o* fak_o, - c3_w* lif_w); - - /* u3_disk_save_meta(): save metadata. - */ - c3_o - u3_disk_save_meta(u3_disk* log_u, - c3_d who_d[2], - c3_o fak_o, - c3_w lif_w); - - /* u3_disk_read(): read [len_d] events starting at [eve_d]. - */ - void - u3_disk_read(u3_disk* log_u, c3_d eve_d, c3_d len_d); - - /* u3_disk_boot_plan(): enqueue boot sequence, without autocommit. - */ - void - u3_disk_boot_plan(u3_disk* log_u, u3_noun job); - - /* u3_disk_boot_save(): commit boot sequence. - */ - void - u3_disk_boot_save(u3_disk* log_u); - - /* u3_disk_plan(): enqueue completed event for persistence. - */ - void - u3_disk_plan(u3_disk* log_u, u3_fact* tac_u); - - /* u3_lord_init(): start serf. - */ - u3_lord* - u3_lord_init(c3_c* pax_c, - c3_w wag_w, - c3_d key_d[4], - u3_lord_cb cb_u); - - /* u3_lord_info(): status info as a $mass. - */ - u3_noun - u3_lord_info(u3_lord* god_u); - - /* u3_lord_slog(): print status info. - */ - void - u3_lord_slog(u3_lord* god_u); - - /* u3_lord_exit(): shutdown gracefully. - */ - void - u3_lord_exit(u3_lord* god_u); - - /* u3_lord_stall(): send SIGINT - */ - void - u3_lord_stall(u3_lord* god_u); - - /* u3_lord_halt(): shutdown immediately - */ - void - u3_lord_halt(u3_lord* god_u); - - /* u3_lord_save(): save a snapshot. - */ - c3_o - u3_lord_save(u3_lord* god_u); - - /* u3_lord_cram(): save portable state. - */ - c3_o - u3_lord_cram(u3_lord* god_u); - - /* u3_lord_meld(): globally deduplicate persistent state. - */ - void - u3_lord_meld(u3_lord* god_u); - - /* u3_lord_pack(): defragment persistent state. - */ - void - u3_lord_pack(u3_lord* god_u); - - /* u3_lord_work(): attempt work. - */ - void - u3_lord_work(u3_lord* god_u, u3_ovum* egg_u, u3_noun job); - - /* u3_lord_play(): recompute batch. - */ - void - u3_lord_play(u3_lord* god_u, u3_info fon_u); - - /* u3_lord_peek(): read namespace, injecting what's missing. - */ - void - u3_lord_peek(u3_lord* god_u, u3_pico* pic_u); - - /** Filesystem (async). - **/ - /* u3_foil_folder(): load directory, blockingly. create if nonexistent. - */ - u3_dire* - u3_foil_folder(const c3_c* pax_c); // directory object, or 0 - - /** Terminal. - **/ - /* u3_term_start_spinner(): prepare spinner state. RETAIN. - */ - void - u3_term_start_spinner(u3_noun say, c3_o del_o); - - /* u3_term_stop_spinner(): reset spinner state and restore input line. - */ - void - u3_term_stop_spinner(void); - - /* u3_term_get_blew(): return window size [columns rows]. - */ - u3_noun - u3_term_get_blew(c3_l tid_l); - - /* u3_term_ef_winc(): window change. - */ - void - u3_term_ef_winc(void); - - /* u3_term_ef_ctlc(): send ^C. - */ - void - u3_term_ef_ctlc(void); - - /* u3_term_io_init(): initialize terminal I/O. - */ - u3_auto* - u3_term_io_init(u3_pier* pir_u); - - /* u3_term_io_hija(): hijack console for cooked print. - */ - FILE* - u3_term_io_hija(void); - - /* u3_term_it_log(): writes a log message - */ - void - u3_term_io_log(c3_c* line); - - /* u3_term_io_loja(): release console from cooked print. - */ - void - u3_term_io_loja(int x, FILE* f); - - /* u3_term_log_init(): initialize terminal for logging - */ - void - u3_term_log_init(void); - - /* u3_term_log_exit(): clean up terminal. - */ - void - u3_term_log_exit(void); - - /* u3_ptty_init(): initialize platform-specific tty. - */ - u3_utty* - u3_ptty_init(uv_loop_t* lup_u, const c3_c** err_c); - - - /** Ames, packet networking. - **/ - /* u3_ames_io_init(): initialize ames I/O. - */ - u3_auto* - u3_ames_io_init(u3_pier* pir_u); - - /* u3_ames_decode_lane(): destructure lane from noun - */ - u3_lane - u3_ames_decode_lane(u3_noun); - - /* u3_ames_encode_lane(): encode lane as noun - */ - u3_noun - u3_ames_encode_lane(u3_lane); - - /** Autosave. - **/ - /* u3_save_ef_chld(): report SIGCHLD. - */ - void - u3_save_ef_chld(u3_pier *pir_u); - - /* u3_save_io_init(): initialize autosave. - */ - void - u3_save_io_init(u3_pier *pir_u); - - /* u3_save_io_exit(): terminate autosave. - */ - void - u3_save_io_exit(u3_pier *pir_u); - - - /** Storage. - **/ - /* u3_unix_save(): save file undir .../.urb/put or bail. - */ - void - u3_unix_save(c3_c* pax_c, u3_atom pad); - - /* u3_unix_cane(): true iff (unix) path is canonical. - */ - c3_t - u3_unix_cane(const c3_c* pax_c); - - /* u3_unix_initial_into_card(): create initial filesystem sync card. - */ - u3_noun - u3_unix_initial_into_card(c3_c* arv_c); - - /* u3_unix_io_init(): initialize storage. - */ - u3_auto* - u3_unix_io_init(u3_pier* pir_u); - - /** behn, just a timer. - **/ - /* u3_behn_io_init(): initialize behn timer. - */ - u3_auto* - u3_behn_io_init(u3_pier* pir_u); - - /** HTTP server. - **/ - /* u3_http_io_init(): initialize http I/O. - */ - u3_auto* - u3_http_io_init(u3_pier* pir_u); - - /** HTTP client. - **/ - /* u3_cttp_io_init(): initialize cttp I/O. - */ - u3_auto* - u3_cttp_io_init(u3_pier* pir_u); - - /** Control plane. - **/ - /* u3_conn_io_init(): initialize control plane I/O. - */ - u3_auto* - u3_conn_io_init(u3_pier* pir_u); - - /** fore, first events. - **/ - /* u3_hind_io_init(): initialize fore - */ - u3_auto* - u3_fore_io_init(u3_pier* pir_u); - - /** hind, defaults. - **/ - /* u3_hind_io_init(): initialize hint - */ - u3_auto* - u3_hind_io_init(u3_pier* pir_u); - - /** Stream messages. - **/ - /* u3_newt_decode(): decode a (partial) length-prefixed byte buffer - */ - c3_o - u3_newt_decode(u3_moat* mot_u, c3_y* buf_y, c3_d len_d); - - /* u3_newt_send(): write buffer to stream. - */ - void - u3_newt_send(u3_mojo* moj_u, c3_d len_d, c3_y* byt_y); - - /* u3_newt_read_sync(): start reading; multiple msgs synchronous. - */ - void - u3_newt_read_sync(u3_moat* mot_u); - - /* u3_newt_read(): start reading; each msg asynchronous. - */ - void - u3_newt_read(u3_moat* mot_u); - - /* u3_newt_moat_info(): status info as $mass. - */ - u3_noun - u3_newt_moat_info(u3_moat* mot_u); - - /* u3_newt_moat_slog(); print status info. - */ - void - u3_newt_moat_slog(u3_moat* mot_u); - - /* u3_newt_moat_stop(); newt stop/close input stream. - */ - void - u3_newt_moat_stop(u3_moat* mot_u, u3_moor_bail bal_f); - - /* u3_newt_mojo_stop(); newt stop/close output stream. - */ - void - u3_newt_mojo_stop(u3_mojo* moj_u, u3_moor_bail bal_f); - - /** Pier scries. - **/ - /* u3_pier_peek(): read namespace. - */ - void - u3_pier_peek(u3_pier* pir_u, - u3_noun gan, - u3_noun ful, - void* ptr_v, - u3_peek_cb fun_f); - - /* u3_pier_peek_last(): read namespace, injecting ship and case. - */ - void - u3_pier_peek_last(u3_pier* pir_u, - u3_noun gan, - c3_m car_m, - u3_atom des, - u3_noun pax, - void* ptr_v, - u3_peek_cb fun_f); - - /** Pier control. - **/ - /* u3_pier_exit(): trigger a gentle shutdown. - */ - void - u3_pier_exit(u3_pier* pir_u); - - /* u3_pier_bail(): immediately shutdown.. - */ - void - u3_pier_bail(u3_pier* pir_u); - - /* u3_pier_save(): request checkpoint. - */ - c3_o - u3_pier_save(u3_pier* pir_u); - - /* u3_pier_cram(): save a portable snapshot. - */ - c3_o - u3_pier_cram(u3_pier* pir_u); - - /* u3_pier_meld(): globally deduplicate persistent state. - */ - void - u3_pier_meld(u3_pier* pir_u); - - /* u3_pier_pack(): defragment persistent state. - */ - void - u3_pier_pack(u3_pier* pir_u); - - /* u3_pier_info(): pier status info as $mass. - */ - u3_noun - u3_pier_info(u3_pier* pir_u); - - /* u3_pier_slog(): print pier status info. - */ - void - u3_pier_slog(u3_pier* pir_u); - - /* u3_pier_boot(): start the pier. - */ - u3_pier* - u3_pier_boot(c3_w wag_w, // config flags - u3_noun who, // identity - u3_noun ven, // boot event - u3_noun pil, // type-of/path-to pill - u3_noun pax, // path to pier - u3_weak fed); // extra private keys - - /* u3_pier_stay(): restart the pier. - */ - u3_pier* - u3_pier_stay(c3_w wag_w, u3_noun pax); - - /* u3_pier_tank(): dump single tank. - */ - void - u3_pier_tank(c3_l tab_l, c3_w pri_w, u3_noun tac); - - /* u3_pier_punt(): dump tank list. - */ - void - u3_pier_punt(c3_l tab_l, u3_noun tac); - - /* u3_pier_punt_goof(): dump a [mote tang] crash report. - */ - void - u3_pier_punt_goof(const c3_c* cap_c, u3_noun dud); - - /* u3_pier_punt_ovum(): print ovum details. - */ - void - u3_pier_punt_ovum(const c3_c* cap_c, u3_noun wir, u3_noun tag); - - /* u3_pier_sway(): print trace. - */ - void - u3_pier_sway(c3_l tab_l, u3_noun tax); - - /* u3_pier_mark(): mark all Loom allocations in all u3_pier structs. - */ - c3_w - u3_pier_mark(FILE* fil_u); - - /* u3_pier_mase(): construct a $mass leaf. - */ - u3_noun - u3_pier_mase(c3_c* cod_c, u3_noun dat); - - /* u3_pier_mass(): construct a $mass branch with noun/list. - */ - u3_noun - u3_pier_mass(u3_atom cod, u3_noun lit); - - /* u3_dawn_come(): mine a comet - */ - u3_noun - u3_dawn_come(void); - - /* u3_dawn_vent(): validated boot event - */ - u3_noun - u3_dawn_vent(u3_noun ship, u3_noun seed); - - /* u3_king_commence(): start the daemon - */ - void - u3_king_commence(); - - /* u3_king_stub(): get the One Pier for unreconstructed code. - */ - u3_pier* - u3_king_stub(void); - - /* u3_king_slog(): print status info. - */ - void - u3_king_slog(void); - - /* u3_king_dock(): copy binary into pier on boot. - */ - void - u3_king_dock(c3_c* pac_c); - - /* u3_king_done(): all piers closed - */ - void - u3_king_done(void); - - /* u3_king_exit(): shutdown gracefully - */ - void - u3_king_exit(void); - - /* u3_king_bail(): immediately shutdown. - */ - void - u3_king_bail(void); - - /* u3_king_grab(): gc the daemon - */ - void - u3_king_grab(void* ptr_v); - - /* u3_king_next(): get next vere version string, if it exists. - ** return: 0 is success, -1 is no-op (same version), -2 is error - */ - c3_i - u3_king_next(c3_c* pac_c, c3_c** out_c); - - /* u3_king_vere(): download binary as specified. - */ - c3_i - u3_king_vere(c3_c* pac_c, // pace - c3_c* ver_c, // version - c3_c* arc_c, // architecture - c3_c* dir_c, // output directory - c3_t lin_t); // link to $pier/.run - - /* u3_daemon_init(): platform-specific daemon mode initialization. - */ - void - u3_daemon_init(); - - /* u3_write_fd(): retry interrupts, continue partial writes, assert errors. - */ - void - u3_write_fd(c3_i fid_i, const void* buf_v, size_t len_i); - - c3_w - u3_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); - -#endif /* ifndef U3_VERE_H */ diff --git a/pkg/urbit/jets/a/add.c b/pkg/urbit/jets/a/add.c deleted file mode 100644 index 0bcf608ee..000000000 --- a/pkg/urbit/jets/a/add.c +++ /dev/null @@ -1,56 +0,0 @@ -/* j/1/add.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qa_add(u3_atom a, - u3_atom b) - { - if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { - c3_w c = a + b; - - return u3i_words(1, &c); - } - else if ( 0 == a ) { - return u3k(b); - } - else { - mpz_t a_mp, b_mp; - - u3r_mp(a_mp, a); - u3r_mp(b_mp, b); - - mpz_add(a_mp, a_mp, b_mp); - mpz_clear(b_mp); - - return u3i_mp(a_mp); - } - } - u3_noun - u3wa_add(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) || - (c3n == u3ud(b) && a != 0) ) - { - return u3m_bail(c3__exit); - } else { - return u3qa_add(a, b); - } - } - - u3_noun - u3ka_add(u3_noun a, - u3_noun b) - { - u3_noun c = u3qa_add(a, b); - - u3z(a); u3z(b); - return c; - } diff --git a/pkg/urbit/jets/a/dec.c b/pkg/urbit/jets/a/dec.c deleted file mode 100644 index 7ad2f170c..000000000 --- a/pkg/urbit/jets/a/dec.c +++ /dev/null @@ -1,56 +0,0 @@ -/* j/1/dec.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qa_inc(u3_atom a) - { - return u3i_vint(u3k(a)); - } - - u3_noun - u3qa_dec(u3_atom a) - { - if ( 0 == a ) { - return u3m_error("decrement-underflow"); - } - else { - if ( _(u3a_is_cat(a)) ) { - return a - 1; - } - else { - mpz_t a_mp; - - u3r_mp(a_mp, a); - mpz_sub_ui(a_mp, a_mp, 1); - - return u3i_mp(a_mp); - } - } - } - - u3_noun - u3wa_dec(u3_noun cor) - { - u3_noun a; - - if ( (u3_none == (a = u3r_at(u3x_sam, cor))) || - (c3n == u3ud(a)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qa_dec(a); - } - } - - u3_noun - u3ka_dec(u3_atom a) - { - u3_noun b = u3qa_dec(a); - u3z(a); - return b; - } diff --git a/pkg/urbit/jets/a/div.c b/pkg/urbit/jets/a/div.c deleted file mode 100644 index 9ac4eeb5f..000000000 --- a/pkg/urbit/jets/a/div.c +++ /dev/null @@ -1,56 +0,0 @@ -/* j/1/div.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qa_div(u3_atom a, - u3_atom b) - { - if ( 0 == b ) { - return u3m_error("divide-by-zero"); - } - else { - if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { - return a / b; - } - else { - mpz_t a_mp, b_mp; - - u3r_mp(a_mp, a); - u3r_mp(b_mp, b); - - mpz_tdiv_q(a_mp, a_mp, b_mp); - mpz_clear(b_mp); - - return u3i_mp(a_mp); - } - } - } - u3_noun - u3wa_div(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) || - (c3n == u3ud(b)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qa_div(a, b); - } - } - - -u3_noun -u3ka_div(u3_noun a, - u3_noun b) -{ - u3_noun c = u3qa_div(a, b); - u3z(a); u3z(b); - return c; -} diff --git a/pkg/urbit/jets/a/gte.c b/pkg/urbit/jets/a/gte.c deleted file mode 100644 index 9e2eee7fe..000000000 --- a/pkg/urbit/jets/a/gte.c +++ /dev/null @@ -1,56 +0,0 @@ -/* j/1/gte.c -** -*/ -#include "all.h" - -u3_noun -u3qa_gte(u3_atom a, u3_atom b) -{ - if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { - return __(a >= b); - } - else if ( 0 == a ) { - return c3n; - } - else if ( 0 == b ) { - return c3y; - } - else { - c3_w a_w = u3r_met(0, a); - c3_w b_w = u3r_met(0, b); - - if ( a_w != b_w ) { - return __(a_w >= b_w); - } - else { - mpz_t a_mp, b_mp; - u3_noun cmp; - - u3r_mp(a_mp, a); - u3r_mp(b_mp, b); - - cmp = (mpz_cmp(a_mp, b_mp) >= 0) ? c3y : c3n; - - mpz_clear(a_mp); - mpz_clear(b_mp); - - return cmp; - } - } -} - -u3_noun -u3wa_gte(u3_noun cor) -{ - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) - || (c3n == u3ud(b) && 0 != a) - || (c3n == u3ud(a) && 0 != b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qa_gte(a, b); - } -} diff --git a/pkg/urbit/jets/a/gth.c b/pkg/urbit/jets/a/gth.c deleted file mode 100644 index 3396b1633..000000000 --- a/pkg/urbit/jets/a/gth.c +++ /dev/null @@ -1,64 +0,0 @@ -/* j/1/gth.c -** -*/ -#include "all.h" - -u3_noun -u3qa_gth(u3_atom a, u3_atom b) -{ - if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { - return __(a > b); - } - else if ( 0 == a ) { - return c3n; - } - else if ( 0 == b ) { - return c3y; - } - else { - c3_w a_w = u3r_met(0, a); - c3_w b_w = u3r_met(0, b); - - if ( a_w != b_w ) { - return __(a_w > b_w); - } - else { - mpz_t a_mp, b_mp; - u3_noun cmp; - - u3r_mp(a_mp, a); - u3r_mp(b_mp, b); - - cmp = (mpz_cmp(a_mp, b_mp) > 0) ? c3y : c3n; - - mpz_clear(a_mp); - mpz_clear(b_mp); - - return cmp; - } - } -} - -u3_noun -u3wa_gth(u3_noun cor) -{ - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) - || (c3n == u3ud(b) && 0 != a) - || (c3n == u3ud(a) && 0 != b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qa_gth(a, b); - } -} - -u3_noun -u3ka_gth(u3_noun a, u3_noun b) -{ - u3_noun c = u3qa_gth(a, b); - u3z(a); u3z(b); - return c; -} diff --git a/pkg/urbit/jets/a/lte.c b/pkg/urbit/jets/a/lte.c deleted file mode 100644 index cb639773d..000000000 --- a/pkg/urbit/jets/a/lte.c +++ /dev/null @@ -1,64 +0,0 @@ -/* j/1/lte.c -** -*/ -#include "all.h" - -u3_noun -u3qa_lte(u3_atom a, u3_atom b) -{ - if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { - return __(a <= b); - } - else if ( 0 == a ) { - return c3y; - } - else if ( 0 == b ) { - return c3n; - } - else { - c3_w a_w = u3r_met(0, a); - c3_w b_w = u3r_met(0, b); - - if ( a_w != b_w ) { - return __(a_w <= b_w); - } - else { - mpz_t a_mp, b_mp; - u3_noun cmp; - - u3r_mp(a_mp, a); - u3r_mp(b_mp, b); - - cmp = (mpz_cmp(a_mp, b_mp) <= 0) ? c3y : c3n; - - mpz_clear(a_mp); - mpz_clear(b_mp); - - return cmp; - } - } -} - -u3_noun -u3wa_lte(u3_noun cor) -{ - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) - || (c3n == u3ud(b) && 0 != a) - || (c3n == u3ud(a) && 0 != b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qa_lte(a, b); - } -} - -u3_noun -u3ka_lte(u3_noun a, u3_noun b) -{ - u3_noun c = u3qa_lte(a, b); - u3z(a); u3z(b); - return c; -} diff --git a/pkg/urbit/jets/a/lth.c b/pkg/urbit/jets/a/lth.c deleted file mode 100644 index 0e58418e6..000000000 --- a/pkg/urbit/jets/a/lth.c +++ /dev/null @@ -1,56 +0,0 @@ -/* j/1/lth.c -** -*/ -#include "all.h" - -u3_noun -u3qa_lth(u3_atom a, u3_atom b) -{ - if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { - return __(a < b); - } - else if ( 0 == a ) { - return c3y; - } - else if ( 0 == b ) { - return c3n; - } - else { - c3_w a_w = u3r_met(0, a); - c3_w b_w = u3r_met(0, b); - - if ( a_w != b_w ) { - return __(a_w < b_w); - } - else { - mpz_t a_mp, b_mp; - u3_noun cmp; - - u3r_mp(a_mp, a); - u3r_mp(b_mp, b); - - cmp = (mpz_cmp(a_mp, b_mp) < 0) ? c3y : c3n; - - mpz_clear(a_mp); - mpz_clear(b_mp); - - return cmp; - } - } -} - -u3_noun -u3wa_lth(u3_noun cor) -{ - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) - || (c3n == u3ud(b) && 0 != a) - || (c3n == u3ud(a) && 0 != b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qa_lth(a, b); - } -} diff --git a/pkg/urbit/jets/a/mod.c b/pkg/urbit/jets/a/mod.c deleted file mode 100644 index af9f6662b..000000000 --- a/pkg/urbit/jets/a/mod.c +++ /dev/null @@ -1,52 +0,0 @@ -/* j/1/mod.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qa_mod(u3_atom a, - u3_atom b) - { - if ( 0 == b ) { - return u3m_bail(c3__exit); - } else if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { - return a % b; - } else { - mpz_t a_mp, b_mp; - - u3r_mp(a_mp, a); - u3r_mp(b_mp, b); - - mpz_tdiv_r(a_mp, a_mp, b_mp); - mpz_clear(b_mp); - - return u3i_mp(a_mp); - } - } - - u3_noun - u3wa_mod(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) || - (c3n == u3ud(b)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qa_mod(a, b); - } - } - -u3_noun -u3ka_mod(u3_noun a, - u3_noun b) -{ - u3_noun c = u3qa_mod(a, b); - u3z(a); u3z(b); - return c; -} diff --git a/pkg/urbit/jets/a/mul.c b/pkg/urbit/jets/a/mul.c deleted file mode 100644 index e8eacdbd4..000000000 --- a/pkg/urbit/jets/a/mul.c +++ /dev/null @@ -1,56 +0,0 @@ -/* j/1/mul.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qa_mul(u3_atom a, - u3_atom b) - { - if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { - c3_d c = ((c3_d) a) * ((c3_d) b); - - return u3i_chubs(1, &c); - } - else if ( 0 == a ) { - return 0; - } - else { - mpz_t a_mp, b_mp; - - u3r_mp(a_mp, a); - u3r_mp(b_mp, b); - - mpz_mul(a_mp, a_mp, b_mp); - mpz_clear(b_mp); - - return u3i_mp(a_mp); - } - } - u3_noun - u3wa_mul(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) || - (c3n == u3ud(b) && a != 0) ) - { - return u3m_bail(c3__exit); - } else { - return u3qa_mul(a, b); - } - } - u3_noun - u3ka_mul(u3_noun a, - u3_noun b) - { - u3_noun c = u3qa_mul(a, b); - - u3z(a); u3z(b); - return c; - } - diff --git a/pkg/urbit/jets/a/sub.c b/pkg/urbit/jets/a/sub.c deleted file mode 100644 index 7af71f96c..000000000 --- a/pkg/urbit/jets/a/sub.c +++ /dev/null @@ -1,64 +0,0 @@ -/* j/1/sub.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qa_sub(u3_atom a, - u3_atom b) - { - if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { - if ( a < b ) { - return u3m_error("subtract-underflow"); - } - else return (a - b); - } - else if ( 0 == b ) { - return u3k(a); - } - else { - mpz_t a_mp, b_mp; - - u3r_mp(a_mp, a); - u3r_mp(b_mp, b); - - if ( mpz_cmp(a_mp, b_mp) < 0 ) { - mpz_clear(a_mp); - mpz_clear(b_mp); - - return u3m_error("subtract-underflow"); - } - mpz_sub(a_mp, a_mp, b_mp); - mpz_clear(b_mp); - - return u3i_mp(a_mp); - } - } - - u3_noun - u3wa_sub(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(b)) || - (c3n == u3ud(a) && b != 0) ) - { - return u3m_bail(c3__exit); - } else { - return u3qa_sub(a, b); - } - } - - u3_noun - u3ka_sub(u3_noun a, - u3_noun b) - { - u3_noun c = u3qa_sub(a, b); - - u3z(a); u3z(b); - return c; - } diff --git a/pkg/urbit/jets/b/bind.c b/pkg/urbit/jets/b/bind.c deleted file mode 100644 index f0421664e..000000000 --- a/pkg/urbit/jets/b/bind.c +++ /dev/null @@ -1,30 +0,0 @@ -/* j/2/bind.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qb_bind(u3_noun a, - u3_noun b) - { - if ( 0 == a ) { - return 0; - } else { - return u3nc(0, u3n_slam_on(u3k(b), u3k(u3t(a)))); - } - } - u3_noun - u3wb_bind(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { - return u3m_bail(c3__exit); - } else { - return u3qb_bind(a, b); - } - } - diff --git a/pkg/urbit/jets/b/clap.c b/pkg/urbit/jets/b/clap.c deleted file mode 100644 index a4a8c6085..000000000 --- a/pkg/urbit/jets/b/clap.c +++ /dev/null @@ -1,36 +0,0 @@ -/* j/2/clap.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qb_clap(u3_noun a, - u3_noun b, - u3_noun c) - { - if ( 0 == a ) { - return u3k(b); - } - else if ( 0 == b ) { - return u3k(a); - } - else { - return u3nc(0, u3n_slam_on(u3k(c), u3nc(u3k(u3t(a)), u3k(u3t(b))))); - } - } - u3_noun - u3wb_clap(u3_noun cor) - { - u3_noun a, b, c; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, - u3x_sam_6, &b, - u3x_sam_7, &c, 0) ) { - return u3m_bail(c3__exit); - } else { - return u3qb_clap(a, b, c); - } - } diff --git a/pkg/urbit/jets/b/drop.c b/pkg/urbit/jets/b/drop.c deleted file mode 100644 index 2048210c3..000000000 --- a/pkg/urbit/jets/b/drop.c +++ /dev/null @@ -1,30 +0,0 @@ -/* j/2/drop.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qb_drop(u3_noun a) - { - if ( 0 == a ) { - return u3_nul; - } - else { - return u3nc(0, u3k(u3t(a))); - } - } - u3_noun - u3wb_drop(u3_noun cor) - { - u3_noun a; - - if ( u3_none == (a = u3r_at(u3x_sam, cor)) ) { - return u3_none; - } else { - return u3qb_drop(a); - } - } - diff --git a/pkg/urbit/jets/b/find.c b/pkg/urbit/jets/b/find.c deleted file mode 100644 index 2a632366d..000000000 --- a/pkg/urbit/jets/b/find.c +++ /dev/null @@ -1,48 +0,0 @@ -/* j/2/find.c -** -*/ -#include "all.h" - -STATIC_ASSERT( (UINT32_MAX > u3a_cells), - "list index precision" ); - -u3_noun -u3qb_find(u3_noun nedl, u3_noun hstk) -{ - if ( u3_nul != nedl ) { - c3_w i_w = 0; - - while ( u3_nul != hstk ) { - u3_noun i_h, t_h = hstk; - u3_noun i_n, t_n = nedl; - u3x_cell(t_h, &i_h, &t_h); - u3x_cell(t_n, &i_n, &t_n); - - while ( c3y == u3r_sing(i_n, i_h) ) { - if ( u3_nul == t_n ) { - return u3nc(u3_nul, u3i_word(i_w)); - } - else if ( u3_nul == t_h ) { - break; - } - else { - u3x_cell(t_h, &i_h, &t_h); - u3x_cell(t_n, &i_n, &t_n); - } - } - - hstk = u3t(hstk); - i_w++; - } - } - - return u3_nul; -} - -u3_noun -u3wb_find(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); - return u3qb_find(a, b); -} diff --git a/pkg/urbit/jets/b/flop.c b/pkg/urbit/jets/b/flop.c deleted file mode 100644 index 296c134c2..000000000 --- a/pkg/urbit/jets/b/flop.c +++ /dev/null @@ -1,31 +0,0 @@ -/* j/2/flop.c -** -*/ -#include "all.h" - -u3_noun -u3qb_flop(u3_noun a) -{ - u3_noun i, t = a, b = u3_nul; - - while ( u3_nul != t ) { - u3x_cell(t, &i, &t); - b = u3nc(u3k(i), b); - } - - return b; -} - -u3_noun -u3wb_flop(u3_noun cor) -{ - return u3qb_flop(u3x_at(u3x_sam, cor)); -} - -u3_noun -u3kb_flop(u3_noun a) -{ - u3_noun b = u3qb_flop(a); - u3z(a); - return b; -} diff --git a/pkg/urbit/jets/b/lent.c b/pkg/urbit/jets/b/lent.c deleted file mode 100644 index f0320c03f..000000000 --- a/pkg/urbit/jets/b/lent.c +++ /dev/null @@ -1,34 +0,0 @@ -/* j/2/lent.c -** -*/ -#include "all.h" - -STATIC_ASSERT( (UINT32_MAX > u3a_cells), - "length precision" ); - -u3_noun -u3qb_lent(u3_noun a) -{ - c3_w len_w = 0; - - while ( u3_nul != a ) { - a = u3t(a); - len_w++; - } - - return u3i_word(len_w); -} - -u3_noun -u3wb_lent(u3_noun cor) -{ - return u3qb_lent(u3x_at(u3x_sam, cor)); -} - -u3_noun -u3kb_lent(u3_noun a) -{ - u3_noun b = u3qb_lent(a); - u3z(a); - return b; -} diff --git a/pkg/urbit/jets/b/levy.c b/pkg/urbit/jets/b/levy.c deleted file mode 100644 index 3f4978b79..000000000 --- a/pkg/urbit/jets/b/levy.c +++ /dev/null @@ -1,49 +0,0 @@ -/* j/2/levy.c -** -*/ -#include "all.h" - - static u3_noun - _levy_in(u3j_site* sit_u, u3_noun a) - { - if ( 0 == a ) { - return c3y; - } else { - u3_noun loz; - - if ( c3n == u3du(a) ) { - return u3m_bail(c3__exit); - } - else switch ( (loz = u3j_gate_slam(sit_u, u3k(u3h(a)))) ) { - case c3y: return _levy_in(sit_u, u3t(a)); - case c3n: return c3n; - default: u3z(loz); - return u3m_bail(c3__exit); - } - } - } - -/* functions -*/ - u3_noun - u3qb_levy(u3_noun a, - u3_noun b) - { - u3_noun pro; - u3j_site sit_u; - u3j_gate_prep(&sit_u, u3k(b)); - pro = _levy_in(&sit_u, a); - u3j_gate_lose(&sit_u); - return pro; - } - u3_noun - u3wb_levy(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { - return u3m_bail(c3__exit); - } else { - return u3qb_levy(a, b); - } - } diff --git a/pkg/urbit/jets/b/lien.c b/pkg/urbit/jets/b/lien.c deleted file mode 100644 index c37b1ee8f..000000000 --- a/pkg/urbit/jets/b/lien.c +++ /dev/null @@ -1,49 +0,0 @@ -/* j/2/lien.c -** -*/ -#include "all.h" - - static u3_noun - _lien_in(u3j_site* sit_u, u3_noun a) - { - if ( 0 == a ) { - return c3n; - } else { - u3_noun loz; - - if ( c3n == u3du(a) ) { - return u3m_bail(c3__exit); - } - else switch ( (loz = u3j_gate_slam(sit_u, u3k(u3h(a)))) ) { - case c3y: return c3y; - case c3n: return _lien_in(sit_u, u3t(a)); - default: u3z(loz); - return u3m_bail(c3__exit); - } - } - } - -/* functions -*/ - u3_noun - u3qb_lien(u3_noun a, - u3_noun b) - { - u3_noun pro; - u3j_site sit_u; - u3j_gate_prep(&sit_u, u3k(b)); - pro = _lien_in(&sit_u, a); - u3j_gate_lose(&sit_u); - return pro; - } - u3_noun - u3wb_lien(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { - return u3m_bail(c3__exit); - } else { - return u3qb_lien(a, b); - } - } diff --git a/pkg/urbit/jets/b/murn.c b/pkg/urbit/jets/b/murn.c deleted file mode 100644 index fa04ecc7b..000000000 --- a/pkg/urbit/jets/b/murn.c +++ /dev/null @@ -1,48 +0,0 @@ -/* j/2/murn.c -** -*/ -#include "all.h" - -u3_noun -u3qb_murn(u3_noun a, u3_noun b) -{ - u3_noun pro; - u3_noun* lit = &pro; - - if ( u3_nul != a ) { - u3_noun* hed; - u3_noun* tel; - u3_noun res, i, t = a; - u3j_site sit_u; - - u3j_gate_prep(&sit_u, u3k(b)); - - do { - u3x_cell(t, &i, &t); - - res = u3j_gate_slam(&sit_u, u3k(i)); - - if ( u3_nul != res ) { - *lit = u3i_defcons(&hed, &tel); - *hed = u3k(u3t(res)); - lit = tel; - u3z(res); - } - } - while ( u3_nul != t ); - - u3j_gate_lose(&sit_u); - } - - *lit = u3_nul; - - return pro; -} - -u3_noun -u3wb_murn(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); - return u3qb_murn(a, b); -} diff --git a/pkg/urbit/jets/b/need.c b/pkg/urbit/jets/b/need.c deleted file mode 100644 index 6e0e47d25..000000000 --- a/pkg/urbit/jets/b/need.c +++ /dev/null @@ -1,30 +0,0 @@ -/* j/2/need.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qb_need(u3_noun a) - { - if ( 0 == a ) { - return u3m_bail(c3__exit); - } - else { - return u3k(u3t(a)); - } - } - u3_noun - u3wb_need(u3_noun cor) - { - u3_noun a; - - if ( u3_none == (a = u3r_at(u3x_sam, cor)) ) { - return u3m_bail(c3__exit); - } else { - return u3qb_need(a); - } - } - diff --git a/pkg/urbit/jets/b/reap.c b/pkg/urbit/jets/b/reap.c deleted file mode 100644 index 683d3f172..000000000 --- a/pkg/urbit/jets/b/reap.c +++ /dev/null @@ -1,41 +0,0 @@ -/* j/2/reap.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qb_reap(u3_atom a, - u3_noun b) - { - if ( !_(u3a_is_cat(a)) ) { - return u3m_bail(c3__fail); - } - else { - u3_noun acc = u3_nul; - c3_w i_w = a; - - while ( i_w ) { - acc = u3nc(u3k(b), acc); - i_w--; - } - - return acc; - } - } - - u3_noun - u3wb_reap(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qb_reap(a, b); - } - } diff --git a/pkg/urbit/jets/b/reel.c b/pkg/urbit/jets/b/reel.c deleted file mode 100644 index 13c47f3d1..000000000 --- a/pkg/urbit/jets/b/reel.c +++ /dev/null @@ -1,52 +0,0 @@ -/* j/2/reel.c -** -*/ -#include "all.h" - -/* functions -*/ - u3_noun - u3qb_reel(u3_noun a, - u3_noun b) - { - u3_noun pro = u3k(u3x_at(u3x_sam_3, b)); - - if ( u3_nul != a ) { - u3a_pile pil_u; - u3j_site sit_u; - u3_noun* top; - u3_noun i, t = a; - - u3a_pile_prep(&pil_u, sizeof(u3_noun)); - - // push list onto road stack - // - do { - u3x_cell(t, &i, &t); - top = u3a_push(&pil_u); - *top = i; - } while ( u3_nul != t ); - - u3j_gate_prep(&sit_u, u3k(b)); - - while ( c3n == u3a_pile_done(&pil_u) ) { - pro = u3j_gate_slam(&sit_u, u3nc(u3k(*top), pro)); - top = u3a_pop(&pil_u); - } - - u3j_gate_lose(&sit_u); - } - - return pro; - } - u3_noun - u3wb_reel(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { - return u3m_bail(c3__exit); - } else { - return u3qb_reel(a, b); - } - } diff --git a/pkg/urbit/jets/b/roll.c b/pkg/urbit/jets/b/roll.c deleted file mode 100644 index 72f334f55..000000000 --- a/pkg/urbit/jets/b/roll.c +++ /dev/null @@ -1,38 +0,0 @@ -/* j/2/roll.c -** -*/ -#include "all.h" - -/* functions -*/ - u3_noun - u3qb_roll(u3_noun a, - u3_noun b) - { - u3_noun pro = u3k(u3x_at(u3x_sam_3, b)); - - if ( u3_nul != a ) { - u3j_site sit_u; - u3_noun i, t = a; - u3j_gate_prep(&sit_u, u3k(b)); - do { - u3x_cell(t, &i, &t); - pro = u3j_gate_slam(&sit_u, u3nc(u3k(i), pro)); - } while ( u3_nul != t ); - u3j_gate_lose(&sit_u); - } - - return pro; - } - u3_noun - u3wb_roll(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { - return u3m_bail(c3__exit); - } else { - return u3qb_roll(a, b); - } - } - diff --git a/pkg/urbit/jets/b/scag.c b/pkg/urbit/jets/b/scag.c deleted file mode 100644 index dd66f6954..000000000 --- a/pkg/urbit/jets/b/scag.c +++ /dev/null @@ -1,51 +0,0 @@ -/* j/2/scag.c -** -*/ -#include "all.h" - -u3_noun -u3qb_scag(u3_atom a, u3_noun b) -{ - if ( u3_nul == b ) { - return u3_nul; - } - else if ( !_(u3a_is_cat(a)) ) { - return u3m_bail(c3__fail); - } - else { - u3_noun pro; - u3_noun* lit = &pro; - - { - c3_w len_w = (c3_w)a; - u3_noun* hed; - u3_noun* tel; - u3_noun i, t = b; - - while ( len_w-- && (u3_nul != t) ) { - u3x_cell(t, &i, &t); - - *lit = u3i_defcons(&hed, &tel); - *hed = u3k(i); - lit = tel; - } - } - - *lit = u3_nul; - - return pro; - } -} - -u3_noun -u3wb_scag(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); - - if ( (c3n == u3ud(a)) && (u3_nul != b) ) { - return u3m_bail(c3__exit); - } - - return u3qb_scag(a, b); -} diff --git a/pkg/urbit/jets/b/skid.c b/pkg/urbit/jets/b/skid.c deleted file mode 100644 index 4f1a7818b..000000000 --- a/pkg/urbit/jets/b/skid.c +++ /dev/null @@ -1,56 +0,0 @@ -/* j/2/skid.c -** -*/ -#include "all.h" - -u3_noun -u3qb_skid(u3_noun a, u3_noun b) -{ - u3_noun l, r; - u3_noun* lef = &l; - u3_noun* rig = &r; - - if ( u3_nul != a) { - u3_noun i, t = a; - u3_noun* hed; - u3_noun* tel; - u3j_site sit_u; - u3j_gate_prep(&sit_u, u3k(b)); - - do { - u3x_cell(t, &i, &t); - - switch ( u3j_gate_slam(&sit_u, u3k(i)) ) { - case c3y: { - *lef = u3i_defcons(&hed, &tel); - *hed = u3k(i); - lef = tel; - } break; - - case c3n: { - *rig = u3i_defcons(&hed, &tel); - *hed = u3k(i); - rig = tel; - } break; - - default: u3m_bail(c3__exit); - } - } - while ( u3_nul != t ); - - u3j_gate_lose(&sit_u); - } - - *lef = u3_nul; - *rig = u3_nul; - - return u3nc(l, r); -} - -u3_noun -u3wb_skid(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); - return u3qb_skid(a, b); -} diff --git a/pkg/urbit/jets/b/skim.c b/pkg/urbit/jets/b/skim.c deleted file mode 100644 index c83c2ad70..000000000 --- a/pkg/urbit/jets/b/skim.c +++ /dev/null @@ -1,50 +0,0 @@ -/* j/2/skim.c -** -*/ -#include "all.h" - -u3_noun -u3qb_skim(u3_noun a, u3_noun b) -{ - u3_noun pro; - u3_noun* lit = &pro; - - if ( u3_nul != a) { - u3_noun i, t = a; - u3_noun* hed; - u3_noun* tel; - u3j_site sit_u; - u3j_gate_prep(&sit_u, u3k(b)); - - do { - u3x_cell(t, &i, &t); - - switch ( u3j_gate_slam(&sit_u, u3k(i)) ) { - case c3y: { - *lit = u3i_defcons(&hed, &tel); - *hed = u3k(i); - lit = tel; - } break; - - case c3n: break; - - default: u3m_bail(c3__exit); - } - } - while ( u3_nul != t ); - - u3j_gate_lose(&sit_u); - } - - *lit = u3_nul; - - return pro; -} - -u3_noun -u3wb_skim(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); - return u3qb_skim(a, b); -} diff --git a/pkg/urbit/jets/b/skip.c b/pkg/urbit/jets/b/skip.c deleted file mode 100644 index 5d72796b3..000000000 --- a/pkg/urbit/jets/b/skip.c +++ /dev/null @@ -1,50 +0,0 @@ -/* j/2/skip.c -** -*/ -#include "all.h" - -u3_noun -u3qb_skip(u3_noun a, u3_noun b) -{ - u3_noun pro; - u3_noun* lit = &pro; - - if ( u3_nul != a) { - u3_noun i, t = a; - u3_noun* hed; - u3_noun* tel; - u3j_site sit_u; - u3j_gate_prep(&sit_u, u3k(b)); - - do { - u3x_cell(t, &i, &t); - - switch ( u3j_gate_slam(&sit_u, u3k(i)) ) { - case c3y: break; - - case c3n: { - *lit = u3i_defcons(&hed, &tel); - *hed = u3k(i); - lit = tel; - } break; - - default: u3m_bail(c3__exit); - } - } - while ( u3_nul != t ); - - u3j_gate_lose(&sit_u); - } - - *lit = u3_nul; - - return pro; -} - -u3_noun -u3wb_skip(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); - return u3qb_skip(a, b); -} diff --git a/pkg/urbit/jets/b/slag.c b/pkg/urbit/jets/b/slag.c deleted file mode 100644 index 5a14b0beb..000000000 --- a/pkg/urbit/jets/b/slag.c +++ /dev/null @@ -1,43 +0,0 @@ -/* j/2/slag.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qb_slag(u3_atom a, u3_noun b) - { - if ( u3_nul == b ) { - return u3_nul; - } - else if ( !_(u3a_is_cat(a)) ) { - return u3m_bail(c3__fail); - } - else { - c3_w len_w = a; - - while ( len_w ) { - if ( c3n == u3du(b) ) { - return u3_nul; - } - b = u3t(b); - len_w--; - } - return u3k(b); - } - } - u3_noun - u3wb_slag(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a) && u3_nul != b) ) - { - return u3m_bail(c3__exit); - } else { - return u3qb_slag(a, b); - } - } diff --git a/pkg/urbit/jets/b/snag.c b/pkg/urbit/jets/b/snag.c deleted file mode 100644 index 6a0003404..000000000 --- a/pkg/urbit/jets/b/snag.c +++ /dev/null @@ -1,44 +0,0 @@ -/* j/2/snag.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qb_snag(u3_atom a, - u3_noun b) - { - if ( !_(u3a_is_cat(a)) ) { - return u3m_bail(c3__fail); - } - else { - c3_w len_w = a; - - while ( len_w ) { - if ( c3n == u3du(b) ) { - return u3m_bail(c3__exit); - } - b = u3t(b); - len_w--; - } - if ( c3n == u3du(b) ) { - return u3m_bail(c3__exit); - } - return u3k(u3h(b)); - } - } - u3_noun - u3wb_snag(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qb_snag(a, b); - } - } diff --git a/pkg/urbit/jets/b/sort.c b/pkg/urbit/jets/b/sort.c deleted file mode 100644 index 51d02c05a..000000000 --- a/pkg/urbit/jets/b/sort.c +++ /dev/null @@ -1,88 +0,0 @@ -/* j/2/sort.c -** -*/ -#include "all.h" - - -/* functions -*/ - // like skid, except its callback is $-([* *] ?) and it takes the second - // argument so that it calls its callback with [i.list, second] - // - // all args are RETAINED - static u3_noun - _split_in(u3j_site* sit_u, - u3_noun a, - u3_noun second) - { - if ( 0 == a ) { - return u3nc(u3_nul, u3_nul); - } - else if ( c3n == u3du(a) ) { - return u3m_bail(c3__exit); - } else { - u3_noun acc = _split_in(sit_u, u3t(a), second); - u3_noun hoz = u3j_gate_slam(sit_u, u3nc(u3k(u3h(a)), u3k(second))); - u3_noun nex; - - if ( c3y == hoz ) { - nex = u3nc(u3nc(u3k(u3h(a)), u3k(u3h(acc))), u3k(u3t(acc))); - } - else { - nex = u3nc(u3k(u3h(acc)), u3nc(u3k(u3h(a)), u3k(u3t(acc)))); - } - u3z(hoz); - u3z(acc); - - return nex; - } - } - - static u3_noun - _sort_in(u3j_site* sit_u, u3_noun list) - { - if ( 0 == list ) { - return u3_nul; - } - else if ( c3n == u3du(list) ) { - return u3m_bail(c3__exit); - } else { - u3_noun hed, tal; - u3x_cell(list, &hed, &tal); - - u3_noun split = _split_in(sit_u, tal, hed); - u3_noun lhs = _sort_in(sit_u, u3h(split)); - u3_noun rhs = u3nc(u3k(hed), _sort_in(sit_u, u3t(split))); - - u3_noun ret = u3qb_weld(lhs, rhs); - u3z(lhs); - u3z(rhs); - u3z(split); - - return ret; - } - } - - u3_noun - u3qb_sort(u3_noun a, - u3_noun b) - { - u3_noun pro; - u3j_site sit_u; - u3j_gate_prep(&sit_u, u3k(b)); - pro = _sort_in(&sit_u, a); - u3j_gate_lose(&sit_u); - return pro; - } - u3_noun - u3wb_sort(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { - return u3m_bail(c3__exit); - } else { - return u3qb_sort(a, b); - } - } - diff --git a/pkg/urbit/jets/b/turn.c b/pkg/urbit/jets/b/turn.c deleted file mode 100644 index 1af14d7e3..000000000 --- a/pkg/urbit/jets/b/turn.c +++ /dev/null @@ -1,43 +0,0 @@ -/* j/2/turn.c -** -*/ -#include "all.h" - -u3_noun -u3qb_turn(u3_noun a, u3_noun b) -{ - u3_noun pro; - u3_noun* lit = &pro; - - if ( u3_nul != a ) { - u3_noun* hed; - u3_noun* tel; - u3_noun i, t = a; - u3j_site sit_u; - - u3j_gate_prep(&sit_u, u3k(b)); - - do { - u3x_cell(t, &i, &t); - - *lit = u3i_defcons(&hed, &tel); - *hed = u3j_gate_slam(&sit_u, u3k(i)); - lit = tel; - } - while ( u3_nul != t ); - - u3j_gate_lose(&sit_u); - } - - *lit = u3_nul; - - return pro; -} - -u3_noun -u3wb_turn(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); - return u3qb_turn(a, b); -} diff --git a/pkg/urbit/jets/b/weld.c b/pkg/urbit/jets/b/weld.c deleted file mode 100644 index c01470b45..000000000 --- a/pkg/urbit/jets/b/weld.c +++ /dev/null @@ -1,45 +0,0 @@ -/* j/2/weld.c -** -*/ -#include "all.h" - -u3_noun -u3qb_weld(u3_noun a, u3_noun b) -{ - u3_noun pro; - u3_noun* lit = &pro; - - { - u3_noun* hed; - u3_noun* tel; - u3_noun i, t = a; - - while ( u3_nul != t ) { - u3x_cell(t, &i, &t); - - *lit = u3i_defcons(&hed, &tel); - *hed = u3k(i); - lit = tel; - } - } - - *lit = u3k(b); - - return pro; -} - -u3_noun -u3wb_weld(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); - return u3qb_weld(a, b); -} - -u3_noun -u3kb_weld(u3_noun a, u3_noun b) -{ - u3_noun c = u3qb_weld(a, b); - u3z(a); u3z(b); - return c; -} diff --git a/pkg/urbit/jets/b/zing.c b/pkg/urbit/jets/b/zing.c deleted file mode 100644 index 3239e2bb3..000000000 --- a/pkg/urbit/jets/b/zing.c +++ /dev/null @@ -1,45 +0,0 @@ -/* j/2/zing.c -** -*/ -#include "all.h" - -u3_noun -u3qb_zing(u3_noun a) -{ - u3_noun pro; - u3_noun* lit = &pro; - - if ( u3_nul == a ) { - *lit = u3_nul; - } - else { - u3_noun i, t = a; - u3x_cell(t, &i, &t); - - while ( u3_nul != t ) { - u3_noun* hed; - u3_noun* tel; - u3_noun i_i, t_i = i; - - while ( u3_nul != t_i ) { - u3x_cell(t_i, &i_i, &t_i); - - *lit = u3i_defcons(&hed, &tel); - *hed = u3k(i_i); - lit = tel; - } - - u3x_cell(t, &i, &t); - } - - *lit = u3k(i); - } - - return pro; -} - -u3_noun -u3wb_zing(u3_noun cor) -{ - return u3qb_zing(u3x_at(u3x_sam, cor)); -} diff --git a/pkg/urbit/jets/c/bex.c b/pkg/urbit/jets/c/bex.c deleted file mode 100644 index baf75e485..000000000 --- a/pkg/urbit/jets/c/bex.c +++ /dev/null @@ -1,35 +0,0 @@ -/* j/3/bex.c -** -*/ -#include "all.h" - -u3_noun -u3qc_bex(u3_atom a) -{ - mpz_t a_mp; - - if ( !_(u3a_is_cat(a)) ) { - return u3m_bail(c3__fail); - } - else { - mpz_init_set_ui(a_mp, 1); - mpz_mul_2exp(a_mp, a_mp, a); - - return u3i_mp(a_mp); - } -} - -u3_noun -u3kc_bex(u3_atom a) -{ - u3_noun b = u3qc_bex(a); - u3z(a); - return b; -} - -u3_noun -u3wc_bex(u3_noun cor) -{ - u3_noun a = u3x_at(u3x_sam, cor); - return u3qc_bex(u3x_atom(a)); -} diff --git a/pkg/urbit/jets/c/c0n.c b/pkg/urbit/jets/c/c0n.c deleted file mode 100644 index 841d2cc2e..000000000 --- a/pkg/urbit/jets/c/c0n.c +++ /dev/null @@ -1,54 +0,0 @@ -/* j/3/con.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_con(u3_atom a, - u3_atom b) - { - c3_w lna_w = u3r_met(5, a); - c3_w lnb_w = u3r_met(5, b); - - if ( (lna_w == 0) && (lnb_w == 0) ) { - return 0; - } - else { - c3_w len_w = c3_max(lna_w, lnb_w); - c3_w i_w; - u3i_slab sab_u; - u3i_slab_from(&sab_u, a, 5, len_w); - - for ( i_w = 0; i_w < lnb_w; i_w++ ) { - sab_u.buf_w[i_w] |= u3r_word(i_w, b); - } - - return u3i_slab_mint(&sab_u); - } - } - u3_noun - u3wc_con(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) || - (c3n == u3ud(b)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qc_con(a, b); - } - } - -u3_noun -u3kc_con(u3_noun a, - u3_noun b) -{ - u3_noun c = u3qc_con(a, b); - u3z(a); u3z(b); - return c; -} diff --git a/pkg/urbit/jets/c/can.c b/pkg/urbit/jets/c/can.c deleted file mode 100644 index 7ee8aef45..000000000 --- a/pkg/urbit/jets/c/can.c +++ /dev/null @@ -1,85 +0,0 @@ -/* j/3/can.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_can(u3_atom a, - u3_noun b) - { - if ( !_(u3a_is_cat(a)) || (a >= 32) ) { - return u3m_bail(c3__fail); - } - else { - c3_g a_g = a; - c3_w tot_w = 0; - u3i_slab sab_u; - - /* Measure and validate the slab required. - */ - { - u3_noun cab = b; - - while ( 1 ) { - u3_noun i_cab, pi_cab, qi_cab; - - if ( 0 == cab ) { - break; - } - if ( c3n == u3du(cab) ) return u3m_bail(c3__fail); - i_cab = u3h(cab); - if ( c3n == u3du(i_cab) ) return u3m_bail(c3__fail); - pi_cab = u3h(i_cab); - qi_cab = u3t(i_cab); - if ( c3n == u3a_is_cat(pi_cab) ) return u3m_bail(c3__fail); - if ( c3n == u3ud(qi_cab) ) return u3m_bail(c3__fail); - if ( (tot_w + pi_cab) < tot_w ) return u3m_bail(c3__fail); - - tot_w += pi_cab; - cab = u3t(cab); - } - - if ( 0 == tot_w ) { - return 0; - } - - u3i_slab_init(&sab_u, a_g, tot_w); - } - - /* Chop the list atoms in. - */ - { - u3_noun cab = b; - c3_w pos_w = 0; - - while ( 0 != cab ) { - u3_noun i_cab = u3h(cab); - u3_atom pi_cab = u3h(i_cab); - u3_atom qi_cab = u3t(i_cab); - - u3r_chop(a_g, 0, pi_cab, pos_w, sab_u.buf_w, qi_cab); - pos_w += pi_cab; - cab = u3t(cab); - } - } - - return u3i_slab_mint(&sab_u); - } - } - u3_noun - u3wc_can(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) ) - { - return u3m_bail(c3__fail); - } else { - return u3qc_can(a, b); - } - } - diff --git a/pkg/urbit/jets/c/cap.c b/pkg/urbit/jets/c/cap.c deleted file mode 100644 index fdda353da..000000000 --- a/pkg/urbit/jets/c/cap.c +++ /dev/null @@ -1,36 +0,0 @@ -/* j/3/cap.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_cap(u3_atom a) - { - c3_w met_w = u3r_met(0, a); - - if ( met_w < 2 ) { - return u3m_bail(c3__exit); - } - else if ( (1 == u3r_bit((met_w - 2), a)) ) { - return 3; - } else { - return 2; - } - } - u3_noun - u3wc_cap(u3_noun cor) - { - u3_noun a; - - if ( (u3_none == (a = u3r_at(u3x_sam, cor))) || - (c3n == u3ud(a)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qc_cap(a); - } - } - diff --git a/pkg/urbit/jets/c/cat.c b/pkg/urbit/jets/c/cat.c deleted file mode 100644 index 2648c2303..000000000 --- a/pkg/urbit/jets/c/cat.c +++ /dev/null @@ -1,54 +0,0 @@ -/* j/3/cat.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_cat(u3_atom a, - u3_atom b, - u3_atom c) - { - if ( !_(u3a_is_cat(a)) || (a >= 32) ) { - return u3m_bail(c3__fail); - } - else { - c3_g a_g = a; - c3_w lew_w = u3r_met(a_g, b); - c3_w ler_w = u3r_met(a_g, c); - c3_w all_w = (lew_w + ler_w); - - if ( 0 == all_w ) { - return 0; - } - else { - u3i_slab sab_u; - u3i_slab_from(&sab_u, b, a_g, all_w); - - u3r_chop(a_g, 0, ler_w, lew_w, sab_u.buf_w, c); - - return u3i_slab_mint(&sab_u); - } - } - } - - u3_noun - u3wc_cat(u3_noun cor) - { - u3_noun a, b, c; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, - u3x_sam_6, &b, - u3x_sam_7, &c, 0)) || - (c3n == u3ud(a)) || - (c3n == u3ud(b)) || - (c3n == u3ud(c)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qc_cat(a, b, c); - } - } - diff --git a/pkg/urbit/jets/c/cut.c b/pkg/urbit/jets/c/cut.c deleted file mode 100644 index 08b7d55e5..000000000 --- a/pkg/urbit/jets/c/cut.c +++ /dev/null @@ -1,69 +0,0 @@ -/* j/3/cut.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_cut(u3_atom a, - u3_atom b, - u3_atom c, - u3_atom d) - { - if ( !_(u3a_is_cat(a)) || (a >= 32) ) { - return u3m_bail(c3__fail); - } - if ( !_(u3a_is_cat(b)) ) { - return 0; - } - if ( !_(u3a_is_cat(c)) ) { - c = 0x7fffffff; - } - - { - c3_g a_g = a; - c3_w b_w = b; - c3_w c_w = c; - c3_w len_w = u3r_met(a_g, d); - - if ( (0 == c_w) || (b_w >= len_w) ) { - return 0; - } - if ( b_w + c_w > len_w ) { - c_w = (len_w - b_w); - } - if ( (b_w == 0) && (c_w == len_w) ) { - return u3k(d); - } - else { - u3i_slab sab_u; - u3i_slab_init(&sab_u, a_g, c_w); - - u3r_chop(a_g, b_w, c_w, 0, sab_u.buf_w, d); - - return u3i_slab_mint(&sab_u); - } - } - } - u3_noun - u3wc_cut(u3_noun cor) - { - u3_noun a, b, c, d; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, - u3x_sam_12, &b, - u3x_sam_13, &c, - u3x_sam_7, &d, 0)) || - (c3n == u3ud(a)) || - (c3n == u3ud(b)) || - (c3n == u3ud(c)) || - (c3n == u3ud(d)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qc_cut(a, b, c, d); - } - } - diff --git a/pkg/urbit/jets/c/dis.c b/pkg/urbit/jets/c/dis.c deleted file mode 100644 index c9cd74f34..000000000 --- a/pkg/urbit/jets/c/dis.c +++ /dev/null @@ -1,46 +0,0 @@ -/* j/3/dis.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_dis(u3_atom a, - u3_atom b) - { - c3_w lna_w = u3r_met(5, a); - c3_w lnb_w = u3r_met(5, b); - - if ( (lna_w == 0) && (lnb_w == 0) ) { - return 0; - } - else { - c3_w len_w = c3_max(lna_w, lnb_w); - c3_w i_w; - u3i_slab sab_u; - u3i_slab_from(&sab_u, a, 5, len_w); - - for ( i_w = 0; i_w < len_w; i_w++ ) { - sab_u.buf_w[i_w] &= u3r_word(i_w, b); - } - - return u3i_slab_mint(&sab_u); - } - } - u3_noun - u3wc_dis(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) || - (c3n == u3ud(b)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qc_dis(a, b); - } - } - diff --git a/pkg/urbit/jets/c/dor.c b/pkg/urbit/jets/c/dor.c deleted file mode 100644 index 3f4842c14..000000000 --- a/pkg/urbit/jets/c/dor.c +++ /dev/null @@ -1,49 +0,0 @@ -/* j/3/dor.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_dor(u3_atom a, - u3_atom b) - { - if ( c3y == u3r_sing(a, b) ) { - return c3y; - } - else { - if ( c3y == u3ud(a) ) { - if ( c3y == u3ud(b) ) { - return u3qa_lth(a, b); - } - else { - return c3y; - } - } - else { - if ( c3y == u3ud(b) ) { - return c3n; - } - else { - if ( c3y == u3r_sing(u3h(a), u3h(b)) ) { - return u3qc_dor(u3t(a), u3t(b)); - } - else return u3qc_dor(u3h(a), u3h(b)); - } - } - } - } - u3_noun - u3wc_dor(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { - return u3m_bail(c3__exit); - } else { - return u3qc_dor(a, b); - } - } - diff --git a/pkg/urbit/jets/c/dvr.c b/pkg/urbit/jets/c/dvr.c deleted file mode 100644 index 826631c99..000000000 --- a/pkg/urbit/jets/c/dvr.c +++ /dev/null @@ -1,45 +0,0 @@ -/* j/3/dvr.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_dvr(u3_atom a, - u3_atom b) - { - if ( 0 == b ) { - return u3m_error("divide-by-zero"); - } - else { - if ( _(u3a_is_cat(a)) && _(u3a_is_cat(b)) ) { - return u3nc(a / b, a % b); - } - else { - mpz_t a_mp, b_mp; - - u3r_mp(a_mp, a); - u3r_mp(b_mp, b); - - mpz_tdiv_qr(a_mp, b_mp, a_mp, b_mp); - - return u3nc(u3i_mp(a_mp), u3i_mp(b_mp)); - } - } - } - u3_noun - u3wc_dvr(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qc_dvr(a, b); - } - } - diff --git a/pkg/urbit/jets/c/end.c b/pkg/urbit/jets/c/end.c deleted file mode 100644 index c63451d8f..000000000 --- a/pkg/urbit/jets/c/end.c +++ /dev/null @@ -1,49 +0,0 @@ -/* j/3/end.c -** -*/ -#include "all.h" - -u3_noun -u3qc_end(u3_atom a, - u3_atom b, - u3_atom c) -{ - if ( !_(u3a_is_cat(a)) || (a >= 32) ) { - return u3m_bail(c3__fail); - } - else if ( !_(u3a_is_cat(b)) ) { - return u3k(c); - } - else { - c3_g a_g = a; - c3_w b_w = b; - c3_w len_w = u3r_met(a_g, c); - - if ( 0 == b_w ) { - return 0; - } - else if ( b_w >= len_w ) { - return u3k(c); - } - else { - u3i_slab sab_u; - u3i_slab_init(&sab_u, a_g, b_w); - - u3r_chop(a_g, 0, b_w, 0, sab_u.buf_w, c); - - return u3i_slab_mint(&sab_u); - } - } -} - -u3_noun -u3wc_end(u3_noun cor) -{ - u3_atom bloq, step; - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, - u3x_sam_3, &b, 0); - u3x_bite(a, &bloq, &step); - - return u3qc_end(bloq, step, u3x_atom(b)); -} diff --git a/pkg/urbit/jets/c/gor.c b/pkg/urbit/jets/c/gor.c deleted file mode 100644 index 8e89b5e8c..000000000 --- a/pkg/urbit/jets/c/gor.c +++ /dev/null @@ -1,32 +0,0 @@ -/* j/3/gor.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_gor(u3_noun a, - u3_noun b) - { - c3_w c_w = u3r_mug(a); - c3_w d_w = u3r_mug(b); - - if ( c_w == d_w ) { - return u3qc_dor(a, b); - } - else return (c_w < d_w) ? c3y : c3n; - } - u3_noun - u3wc_gor(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ) { - return u3m_bail(c3__exit); - } else { - return u3qc_gor(a, b); - } - } - diff --git a/pkg/urbit/jets/c/lsh.c b/pkg/urbit/jets/c/lsh.c deleted file mode 100644 index 7ef4f3635..000000000 --- a/pkg/urbit/jets/c/lsh.c +++ /dev/null @@ -1,60 +0,0 @@ -/* j/3/lsh.c -** -*/ -#include "all.h" - -u3_noun -u3qc_lsh(u3_atom a, - u3_atom b, - u3_atom c) -{ - if ( !_(u3a_is_cat(a)) || (a >= 32) ) { - return u3m_bail(c3__fail); - } - else if ( !_(u3a_is_cat(b)) ) { - return u3m_bail(c3__fail); - } - else { - c3_g a_g = a; - c3_w b_w = b; - c3_w len_w = u3r_met(a_g, c); - - if ( 0 == len_w ) { - return 0; - } - else if ( (b_w + len_w) < len_w ) { - return u3m_bail(c3__exit); - } - else { - u3i_slab sab_u; - u3i_slab_init(&sab_u, a_g, (b_w + len_w)); - - u3r_chop(a_g, 0, len_w, b_w, sab_u.buf_w, c); - - return u3i_slab_mint(&sab_u); - } - } -} - -u3_noun -u3wc_lsh(u3_noun cor) -{ - u3_atom bloq, step; - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, - u3x_sam_3, &b, 0); - u3x_bite(a, &bloq, &step); - - return u3qc_lsh(bloq, step, u3x_atom(b)); -} - -u3_noun -u3kc_lsh(u3_noun a, - u3_noun b, - u3_noun c) -{ - u3_noun d = u3qc_lsh(a, b, c); - - u3z(a); u3z(b); u3z(c); - return d; -} diff --git a/pkg/urbit/jets/c/mas.c b/pkg/urbit/jets/c/mas.c deleted file mode 100644 index 81ee41407..000000000 --- a/pkg/urbit/jets/c/mas.c +++ /dev/null @@ -1,45 +0,0 @@ -/* j/3/mas.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_mas(u3_atom a) - { - c3_w b_w; - u3_atom c, d, e, f; - - b_w = u3r_met(0, a); - if ( b_w < 2 ) { - return u3m_bail(c3__exit); - } - else { - c = u3qc_bex((b_w - 1)); - d = u3qc_bex((b_w - 2)); - e = u3qa_sub(a, c); - f = u3qc_con(e, d); - - u3z(c); - u3z(d); - u3z(e); - - return f; - } - } - u3_noun - u3wc_mas(u3_noun cor) - { - u3_noun a; - - if ( (u3_none == (a = u3r_at(u3x_sam, cor))) || - (c3n == u3ud(a)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qc_mas(a); - } - } - diff --git a/pkg/urbit/jets/c/met.c b/pkg/urbit/jets/c/met.c deleted file mode 100644 index aff53da18..000000000 --- a/pkg/urbit/jets/c/met.c +++ /dev/null @@ -1,42 +0,0 @@ -/* j/3/met.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_met(u3_atom a, - u3_atom b) - { - if ( 0 == b ) { - return 0; - } - else if ( !_(u3a_is_cat(a)) || (a >= 32) ) { - return 1; - } - else { - c3_w met_w = u3r_met(a, b); - - if ( !_(u3a_is_cat(met_w)) ) { - return u3i_words(1, &met_w); - } - else return met_w; - } - } - u3_noun - u3wc_met(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(b)) || - (c3n == u3ud(a) && 0 != b) ) - { - return u3m_bail(c3__exit); - } else { - return u3qc_met(a, b); - } - } - diff --git a/pkg/urbit/jets/c/mix.c b/pkg/urbit/jets/c/mix.c deleted file mode 100644 index ccb008c05..000000000 --- a/pkg/urbit/jets/c/mix.c +++ /dev/null @@ -1,55 +0,0 @@ -/* j/3/mix.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_mix(u3_atom a, - u3_atom b) - { - c3_w lna_w = u3r_met(5, a); - c3_w lnb_w = u3r_met(5, b); - - if ( (lna_w == 0) && (lnb_w == 0) ) { - return 0; - } - else { - c3_w len_w = c3_max(lna_w, lnb_w); - c3_w i_w; - u3i_slab sab_u; - u3i_slab_from(&sab_u, a, 5, len_w); - - // XX use u3r_chop for XOR? - // - for ( i_w = 0; i_w < lnb_w; i_w++ ) { - sab_u.buf_w[i_w] ^= u3r_word(i_w, b); - } - - return u3i_slab_mint(&sab_u); - } - } - u3_noun - u3wc_mix(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) || - (c3n == u3ud(b)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qc_mix(a, b); - } - } - u3_noun - u3kc_mix(u3_atom a, - u3_atom b) - { - u3_noun res = u3qc_mix(a, b); - u3z(a); u3z(b); - return res; - } diff --git a/pkg/urbit/jets/c/mor.c b/pkg/urbit/jets/c/mor.c deleted file mode 100644 index 1c0fec930..000000000 --- a/pkg/urbit/jets/c/mor.c +++ /dev/null @@ -1,31 +0,0 @@ -/* j/3/mor.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_mor(u3_atom a, - u3_atom b) - { - c3_w c_w = u3r_mug(u3r_mug(a)); - c3_w d_w = u3r_mug(u3r_mug(b)); - - if ( c_w == d_w ) { - return u3qc_dor(a, b); - } - else return (c_w < d_w) ? c3y : c3n; - } - u3_noun - u3wc_mor(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ) { - return u3m_bail(c3__exit); - } else { - return u3qc_mor(a, b); - } - } diff --git a/pkg/urbit/jets/c/mug.c b/pkg/urbit/jets/c/mug.c deleted file mode 100644 index 22aceee01..000000000 --- a/pkg/urbit/jets/c/mug.c +++ /dev/null @@ -1,19 +0,0 @@ -/* j/3/mug.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3wc_mug(u3_noun cor) - { - u3_noun sam; - - if ( u3_none == (sam = u3r_at(u3x_sam, cor)) ) { - return u3m_bail(c3__exit); - } else { - return u3r_mug(sam); - } - } diff --git a/pkg/urbit/jets/c/muk.c b/pkg/urbit/jets/c/muk.c deleted file mode 100644 index b20f2b264..000000000 --- a/pkg/urbit/jets/c/muk.c +++ /dev/null @@ -1,76 +0,0 @@ -/* j/c/muk.c -** -*/ -#include "all.h" -#include - -/* functions -*/ -u3_noun -u3qc_muk(u3_atom sed, - u3_atom len, - u3_atom key) -{ - if ( c3n == u3a_is_cat(len) ) { - return u3m_bail(c3__fail); - } - else { - c3_w len_w = (c3_w)len; - c3_w key_w = u3r_met(3, key); - - // NB: this condition is implicit in the pad subtraction - // - if ( key_w > len_w ) { - return u3m_bail(c3__exit); - } - else { - c3_w sed_w = u3r_word(0, sed); - c3_o loc_o = c3n; - c3_y* key_y = 0; - c3_w out_w; - - // if we're hashing more bytes than we have, allocate and copy - // to ensure trailing null bytes - // - if ( len_w > key_w ) { - loc_o = c3y; - key_y = u3a_calloc(sizeof(c3_y), len_w); - u3r_bytes(0, len_w, key_y, key); - } - else if ( len_w > 0 ) { - // XX assumes little-endian - // - key_y = ( c3y == u3a_is_cat(key) ) - ? (c3_y*)&key - : (c3_y*)((u3a_atom*)u3a_to_ptr(key))->buf_w; - } - - MurmurHash3_x86_32(key_y, len_w, sed_w, &out_w); - - if ( c3y == loc_o ) { - u3a_free(key_y); - } - - return u3i_words(1, &out_w); - } - } -} - -u3_noun -u3wc_muk(u3_noun cor) -{ - u3_noun sed, len, key; - u3x_mean(cor, u3x_sam_2, &sed, - u3x_sam_6, &len, - u3x_sam_7, &key, 0); - - if ( (c3n == u3ud(sed)) - || (c3n == u3ud(len)) - || (c3n == u3ud(key)) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qc_muk(sed, len, key); - } -} diff --git a/pkg/urbit/jets/c/peg.c b/pkg/urbit/jets/c/peg.c deleted file mode 100644 index f55696a26..000000000 --- a/pkg/urbit/jets/c/peg.c +++ /dev/null @@ -1,50 +0,0 @@ -/* j/3/peg.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_peg(u3_atom a, - u3_atom b) - { - if ( 1 == b ) { - return u3k(a); - } - - u3_atom c, d, e, f, g, h; - - c = u3r_met(0, b); - d = u3qa_dec(c); - e = u3qc_lsh(0, d, 1); - f = u3qa_sub(b, e); - g = u3qc_lsh(0, d, a); - h = u3qa_add(f, g); - - u3z(c); - u3z(d); - u3z(e); - u3z(f); - u3z(g); - - return h; - } - u3_noun - u3wc_peg(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (0 == a) || - (0 == b) || - (c3n == u3ud(b)) || - (c3n == u3ud(a) && b != 1) ) - { - return u3m_bail(c3__exit); - } else { - return u3qc_peg(a, b); - } - } - diff --git a/pkg/urbit/jets/c/po.c b/pkg/urbit/jets/c/po.c deleted file mode 100644 index c907ad48a..000000000 --- a/pkg/urbit/jets/c/po.c +++ /dev/null @@ -1,1425 +0,0 @@ -/* j/3/po.c -** -*/ -#include "all.h" - -u3_noun -u3_po_find_prefix(c3_y one, c3_y two, c3_y three) { - switch (one) { - case 'b': switch (two) { - case 'a': switch (three) { - case 'c': return u3nc(0, 238); - case 'l': return u3nc(0, 107); - case 'n': return u3nc(0, 92); - case 'r': return u3nc(0, 183); - case 't': return u3nc(0, 172); - default: return 0; - } - case 'i': switch (three) { - case 'c': return u3nc(0, 56); - case 'd': return u3nc(0, 106); - case 'l': return u3nc(0, 144); - case 'n': return u3nc(0, 2); - case 's': return u3nc(0, 60); - case 't': return u3nc(0, 182); - default: return 0; - } - case 'o': switch (three) { - case 'l': return u3nc(0, 45); - case 'n': return u3nc(0, 244); - case 'r': return u3nc(0, 188); - case 's': return u3nc(0, 171); - case 't': return u3nc(0, 98); - default: return 0; - } - default: return 0; - } - case 'd': switch (two) { - case 'a': switch (three) { - case 'b': return u3nc(0, 181); - case 'c': return u3nc(0, 117); - case 'l': return u3nc(0, 37); - case 'n': return u3nc(0, 234); - case 'p': return u3nc(0, 66); - case 'r': return u3nc(0, 23); - case 's': return u3nc(0, 61); - case 't': return u3nc(0, 215); - case 'v': return u3nc(0, 105); - default: return 0; - } - case 'i': switch (three) { - case 'b': return u3nc(0, 179); - case 'f': return u3nc(0, 57); - case 'g': return u3nc(0, 193); - case 'l': return u3nc(0, 49); - case 'n': return u3nc(0, 217); - case 'r': return u3nc(0, 11); - case 's': return u3nc(0, 129); - case 'v': return u3nc(0, 116); - default: return 0; - } - case 'o': switch (three) { - case 'c': return u3nc(0, 146); - case 'l': return u3nc(0, 102); - case 'n': return u3nc(0, 233); - case 'p': return u3nc(0, 18); - case 'r': return u3nc(0, 24); - case 's': return u3nc(0, 187); - case 't': return u3nc(0, 47); - case 'v': return u3nc(0, 236); - case 'z': return u3nc(0, 0); - default: return 0; - } - default: return 0; - } - case 'f': switch (two) { - case 'a': switch (three) { - case 'b': return u3nc(0, 120); - case 'd': return u3nc(0, 206); - case 'l': return u3nc(0, 152); - case 'm': return u3nc(0, 214); - case 'n': return u3nc(0, 158); - case 's': return u3nc(0, 195); - default: return 0; - } - case 'i': switch (three) { - case 'd': return u3nc(0, 8); - case 'g': return u3nc(0, 138); - case 'l': return u3nc(0, 194); - case 'n': return u3nc(0, 90); - case 'p': return u3nc(0, 255); - case 'r': return u3nc(0, 169); - case 't': return u3nc(0, 226); - default: return 0; - } - case 'o': switch (three) { - case 'd': return u3nc(0, 247); - case 'g': return u3nc(0, 20); - case 'l': return u3nc(0, 27); - case 'n': return u3nc(0, 91); - case 'p': return u3nc(0, 213); - case 'r': return u3nc(0, 50); - case 's': return u3nc(0, 46); - case 't': return u3nc(0, 221); - default: return 0; - } - default: return 0; - } - case 'h': switch (two) { - case 'a': switch (three) { - case 'b': return u3nc(0, 209); - case 'c': return u3nc(0, 174); - case 'd': return u3nc(0, 145); - case 'l': return u3nc(0, 203); - case 'n': return u3nc(0, 41); - case 'p': return u3nc(0, 156); - case 'r': return u3nc(0, 198); - case 's': return u3nc(0, 170); - case 't': return u3nc(0, 218); - case 'v': return u3nc(0, 176); - default: return 0; - } - case 'i': switch (three) { - case 'd': return u3nc(0, 7); - case 'l': return u3nc(0, 190); - case 'n': return u3nc(0, 200); - default: return 0; - } - case 'o': switch (three) { - case 'b': return u3nc(0, 197); - case 'c': return u3nc(0, 223); - case 'd': return u3nc(0, 26); - case 'l': return u3nc(0, 32); - case 'p': return u3nc(0, 22); - case 's': return u3nc(0, 180); - default: return 0; - } - default: return 0; - } - case 'l': switch (two) { - case 'a': switch (three) { - case 'b': return u3nc(0, 161); - case 'c': return u3nc(0, 34); - case 'd': return u3nc(0, 235); - case 'g': return u3nc(0, 205); - case 'n': return u3nc(0, 232); - case 'p': return u3nc(0, 240); - case 'r': return u3nc(0, 225); - case 's': return u3nc(0, 128); - case 't': return u3nc(0, 134); - case 'v': return u3nc(0, 252); - default: return 0; - } - case 'i': switch (three) { - case 'b': return u3nc(0, 39); - case 'd': return u3nc(0, 21); - case 'g': return u3nc(0, 111); - case 'n': return u3nc(0, 178); - case 's': return u3nc(0, 9); - case 't': return u3nc(0, 5); - case 'v': return u3nc(0, 36); - default: return 0; - } - case 'o': switch (three) { - case 'c': return u3nc(0, 69); - case 'd': return u3nc(0, 186); - case 'm': return u3nc(0, 166); - case 'n': return u3nc(0, 135); - case 'p': return u3nc(0, 63); - case 'r': return u3nc(0, 25); - case 's': return u3nc(0, 48); - default: return 0; - } - default: return 0; - } - case 'm': switch (two) { - case 'a': switch (three) { - case 'c': return u3nc(0, 191); - case 'g': return u3nc(0, 103); - case 'l': return u3nc(0, 110); - case 'p': return u3nc(0, 130); - case 'r': return u3nc(0, 1); - case 's': return u3nc(0, 202); - case 't': return u3nc(0, 253); - default: return 0; - } - case 'i': switch (three) { - case 'c': return u3nc(0, 157); - case 'd': return u3nc(0, 62); - case 'g': return u3nc(0, 199); - case 'l': return u3nc(0, 212); - case 'n': return u3nc(0, 79); - case 'p': return u3nc(0, 254); - case 'r': return u3nc(0, 31); - case 's': return u3nc(0, 126); - case 't': return u3nc(0, 196); - default: return 0; - } - case 'o': switch (three) { - case 'c': return u3nc(0, 148); - case 'd': return u3nc(0, 19); - case 'g': return u3nc(0, 162); - case 'l': return u3nc(0, 67); - case 'n': return u3nc(0, 122); - case 'p': return u3nc(0, 208); - case 'r': return u3nc(0, 93); - case 's': return u3nc(0, 231); - case 't': return u3nc(0, 82); - default: return 0; - } - default: return 0; - } - case 'n': switch (two) { - case 'a': switch (three) { - case 'c': return u3nc(0, 219); - case 'l': return u3nc(0, 230); - case 'm': return u3nc(0, 243); - case 'p': return u3nc(0, 87); - case 'r': return u3nc(0, 65); - case 't': return u3nc(0, 77); - case 'v': return u3nc(0, 137); - default: return 0; - } - case 'i': switch (three) { - case 'b': return u3nc(0, 140); - case 'd': return u3nc(0, 72); - case 'l': return u3nc(0, 210); - case 'm': return u3nc(0, 224); - case 's': return u3nc(0, 124); - default: return 0; - } - case 'o': switch (three) { - case 'c': return u3nc(0, 250); - case 'd': return u3nc(0, 136); - case 'l': return u3nc(0, 216); - case 'm': return u3nc(0, 139); - case 'p': return u3nc(0, 88); - case 'r': return u3nc(0, 97); - case 's': return u3nc(0, 211); - case 'v': return u3nc(0, 70); - default: return 0; - } - default: return 0; - } - case 'p': switch (two) { - case 'a': switch (three) { - case 'c': return u3nc(0, 149); - case 'd': return u3nc(0, 114); - case 'g': return u3nc(0, 141); - case 'l': return u3nc(0, 127); - case 'n': return u3nc(0, 78); - case 'r': return u3nc(0, 185); - case 's': return u3nc(0, 33); - case 't': return u3nc(0, 159); - default: return 0; - } - case 'i': switch (three) { - case 'c': return u3nc(0, 104); - case 'd': return u3nc(0, 43); - case 'l': return u3nc(0, 51); - case 'n': return u3nc(0, 165); - case 't': return u3nc(0, 242); - default: return 0; - } - case 'o': switch (three) { - case 'c': return u3nc(0, 173); - case 'd': return u3nc(0, 81); - case 'l': return u3nc(0, 239); - case 'n': return u3nc(0, 248); - case 's': return u3nc(0, 86); - default: return 0; - } - default: return 0; - } - case 'r': switch (two) { - case 'a': switch (three) { - case 'b': return u3nc(0, 131); - case 'c': return u3nc(0, 184); - case 'd': return u3nc(0, 201); - case 'g': return u3nc(0, 204); - case 'l': return u3nc(0, 143); - case 'm': return u3nc(0, 52); - case 'n': return u3nc(0, 123); - case 'p': return u3nc(0, 228); - case 'v': return u3nc(0, 150); - default: return 0; - } - case 'i': switch (three) { - case 'b': return u3nc(0, 222); - case 'c': return u3nc(0, 167); - case 'd': return u3nc(0, 147); - case 'g': return u3nc(0, 16); - case 'l': return u3nc(0, 64); - case 'n': return u3nc(0, 28); - case 'p': return u3nc(0, 151); - case 's': return u3nc(0, 220); - case 't': return u3nc(0, 80); - case 'v': return u3nc(0, 237); - default: return 0; - } - case 'o': switch (three) { - case 'c': return u3nc(0, 58); - case 'l': return u3nc(0, 133); - case 'n': return u3nc(0, 96); - case 'p': return u3nc(0, 75); - case 's': return u3nc(0, 245); - case 'v': return u3nc(0, 35); - default: return 0; - } - default: return 0; - } - case 's': switch (two) { - case 'a': switch (three) { - case 'b': return u3nc(0, 13); - case 'l': return u3nc(0, 115); - case 'm': return u3nc(0, 4); - case 'n': return u3nc(0, 68); - case 'p': return u3nc(0, 177); - case 'r': return u3nc(0, 229); - case 't': return u3nc(0, 38); - case 'v': return u3nc(0, 85); - default: return 0; - } - case 'i': switch (three) { - case 'b': return u3nc(0, 15); - case 'c': return u3nc(0, 74); - case 'd': return u3nc(0, 119); - case 'g': return u3nc(0, 6); - case 'l': return u3nc(0, 30); - case 'm': return u3nc(0, 163); - case 'p': return u3nc(0, 95); - case 't': return u3nc(0, 71); - case 'v': return u3nc(0, 112); - default: return 0; - } - case 'o': switch (three) { - case 'c': return u3nc(0, 100); - case 'g': return u3nc(0, 10); - case 'l': return u3nc(0, 17); - case 'm': return u3nc(0, 89); - case 'n': return u3nc(0, 164); - case 'p': return u3nc(0, 142); - case 'r': return u3nc(0, 251); - case 'v': return u3nc(0, 249); - default: return 0; - } - default: return 0; - } - case 't': switch (two) { - case 'a': switch (three) { - case 'b': return u3nc(0, 40); - case 'c': return u3nc(0, 160); - case 'd': return u3nc(0, 55); - case 'g': return u3nc(0, 113); - case 'l': return u3nc(0, 241); - case 'm': return u3nc(0, 83); - case 'n': return u3nc(0, 118); - case 'p': return u3nc(0, 168); - case 'r': return u3nc(0, 121); - case 's': return u3nc(0, 109); - default: return 0; - } - case 'i': switch (three) { - case 'c': return u3nc(0, 42); - case 'd': return u3nc(0, 175); - case 'l': return u3nc(0, 154); - case 'm': return u3nc(0, 108); - case 'n': return u3nc(0, 155); - case 'p': return u3nc(0, 73); - case 'r': return u3nc(0, 53); - default: return 0; - } - case 'o': switch (three) { - case 'b': return u3nc(0, 132); - case 'c': return u3nc(0, 189); - case 'd': return u3nc(0, 153); - case 'g': return u3nc(0, 29); - case 'l': return u3nc(0, 84); - case 'm': return u3nc(0, 192); - case 'n': return u3nc(0, 246); - case 'p': return u3nc(0, 207); - case 'r': return u3nc(0, 44); - default: return 0; - } - default: return 0; - } - case 'w': switch (two) { - case 'a': switch (three) { - case 'c': return u3nc(0, 12); - case 'l': return u3nc(0, 227); - case 'n': return u3nc(0, 3); - case 't': return u3nc(0, 101); - default: return 0; - } - case 'i': switch (three) { - case 'c': return u3nc(0, 99); - case 'd': return u3nc(0, 59); - case 'n': return u3nc(0, 54); - case 's': return u3nc(0, 14); - case 't': return u3nc(0, 76); - default: return 0; - } - case 'o': switch (three) { - case 'l': return u3nc(0, 125); - case 'r': return u3nc(0, 94); - default: return 0; - } - default: return 0; - } - default: return 0; - } -} - -void -u3_po_to_prefix(u3_noun id, c3_y* a, c3_y* b, c3_y* c) -{ - switch (id) { - case 0: *a = 'd'; *b = 'o'; *c = 'z'; break; - case 1: *a = 'm'; *b = 'a'; *c = 'r'; break; - case 2: *a = 'b'; *b = 'i'; *c = 'n'; break; - case 3: *a = 'w'; *b = 'a'; *c = 'n'; break; - case 4: *a = 's'; *b = 'a'; *c = 'm'; break; - case 5: *a = 'l'; *b = 'i'; *c = 't'; break; - case 6: *a = 's'; *b = 'i'; *c = 'g'; break; - case 7: *a = 'h'; *b = 'i'; *c = 'd'; break; - case 8: *a = 'f'; *b = 'i'; *c = 'd'; break; - case 9: *a = 'l'; *b = 'i'; *c = 's'; break; - case 10: *a = 's'; *b = 'o'; *c = 'g'; break; - case 11: *a = 'd'; *b = 'i'; *c = 'r'; break; - case 12: *a = 'w'; *b = 'a'; *c = 'c'; break; - case 13: *a = 's'; *b = 'a'; *c = 'b'; break; - case 14: *a = 'w'; *b = 'i'; *c = 's'; break; - case 15: *a = 's'; *b = 'i'; *c = 'b'; break; - case 16: *a = 'r'; *b = 'i'; *c = 'g'; break; - case 17: *a = 's'; *b = 'o'; *c = 'l'; break; - case 18: *a = 'd'; *b = 'o'; *c = 'p'; break; - case 19: *a = 'm'; *b = 'o'; *c = 'd'; break; - case 20: *a = 'f'; *b = 'o'; *c = 'g'; break; - case 21: *a = 'l'; *b = 'i'; *c = 'd'; break; - case 22: *a = 'h'; *b = 'o'; *c = 'p'; break; - case 23: *a = 'd'; *b = 'a'; *c = 'r'; break; - case 24: *a = 'd'; *b = 'o'; *c = 'r'; break; - case 25: *a = 'l'; *b = 'o'; *c = 'r'; break; - case 26: *a = 'h'; *b = 'o'; *c = 'd'; break; - case 27: *a = 'f'; *b = 'o'; *c = 'l'; break; - case 28: *a = 'r'; *b = 'i'; *c = 'n'; break; - case 29: *a = 't'; *b = 'o'; *c = 'g'; break; - case 30: *a = 's'; *b = 'i'; *c = 'l'; break; - case 31: *a = 'm'; *b = 'i'; *c = 'r'; break; - case 32: *a = 'h'; *b = 'o'; *c = 'l'; break; - case 33: *a = 'p'; *b = 'a'; *c = 's'; break; - case 34: *a = 'l'; *b = 'a'; *c = 'c'; break; - case 35: *a = 'r'; *b = 'o'; *c = 'v'; break; - case 36: *a = 'l'; *b = 'i'; *c = 'v'; break; - case 37: *a = 'd'; *b = 'a'; *c = 'l'; break; - case 38: *a = 's'; *b = 'a'; *c = 't'; break; - case 39: *a = 'l'; *b = 'i'; *c = 'b'; break; - case 40: *a = 't'; *b = 'a'; *c = 'b'; break; - case 41: *a = 'h'; *b = 'a'; *c = 'n'; break; - case 42: *a = 't'; *b = 'i'; *c = 'c'; break; - case 43: *a = 'p'; *b = 'i'; *c = 'd'; break; - case 44: *a = 't'; *b = 'o'; *c = 'r'; break; - case 45: *a = 'b'; *b = 'o'; *c = 'l'; break; - case 46: *a = 'f'; *b = 'o'; *c = 's'; break; - case 47: *a = 'd'; *b = 'o'; *c = 't'; break; - case 48: *a = 'l'; *b = 'o'; *c = 's'; break; - case 49: *a = 'd'; *b = 'i'; *c = 'l'; break; - case 50: *a = 'f'; *b = 'o'; *c = 'r'; break; - case 51: *a = 'p'; *b = 'i'; *c = 'l'; break; - case 52: *a = 'r'; *b = 'a'; *c = 'm'; break; - case 53: *a = 't'; *b = 'i'; *c = 'r'; break; - case 54: *a = 'w'; *b = 'i'; *c = 'n'; break; - case 55: *a = 't'; *b = 'a'; *c = 'd'; break; - case 56: *a = 'b'; *b = 'i'; *c = 'c'; break; - case 57: *a = 'd'; *b = 'i'; *c = 'f'; break; - case 58: *a = 'r'; *b = 'o'; *c = 'c'; break; - case 59: *a = 'w'; *b = 'i'; *c = 'd'; break; - case 60: *a = 'b'; *b = 'i'; *c = 's'; break; - case 61: *a = 'd'; *b = 'a'; *c = 's'; break; - case 62: *a = 'm'; *b = 'i'; *c = 'd'; break; - case 63: *a = 'l'; *b = 'o'; *c = 'p'; break; - case 64: *a = 'r'; *b = 'i'; *c = 'l'; break; - case 65: *a = 'n'; *b = 'a'; *c = 'r'; break; - case 66: *a = 'd'; *b = 'a'; *c = 'p'; break; - case 67: *a = 'm'; *b = 'o'; *c = 'l'; break; - case 68: *a = 's'; *b = 'a'; *c = 'n'; break; - case 69: *a = 'l'; *b = 'o'; *c = 'c'; break; - case 70: *a = 'n'; *b = 'o'; *c = 'v'; break; - case 71: *a = 's'; *b = 'i'; *c = 't'; break; - case 72: *a = 'n'; *b = 'i'; *c = 'd'; break; - case 73: *a = 't'; *b = 'i'; *c = 'p'; break; - case 74: *a = 's'; *b = 'i'; *c = 'c'; break; - case 75: *a = 'r'; *b = 'o'; *c = 'p'; break; - case 76: *a = 'w'; *b = 'i'; *c = 't'; break; - case 77: *a = 'n'; *b = 'a'; *c = 't'; break; - case 78: *a = 'p'; *b = 'a'; *c = 'n'; break; - case 79: *a = 'm'; *b = 'i'; *c = 'n'; break; - case 80: *a = 'r'; *b = 'i'; *c = 't'; break; - case 81: *a = 'p'; *b = 'o'; *c = 'd'; break; - case 82: *a = 'm'; *b = 'o'; *c = 't'; break; - case 83: *a = 't'; *b = 'a'; *c = 'm'; break; - case 84: *a = 't'; *b = 'o'; *c = 'l'; break; - case 85: *a = 's'; *b = 'a'; *c = 'v'; break; - case 86: *a = 'p'; *b = 'o'; *c = 's'; break; - case 87: *a = 'n'; *b = 'a'; *c = 'p'; break; - case 88: *a = 'n'; *b = 'o'; *c = 'p'; break; - case 89: *a = 's'; *b = 'o'; *c = 'm'; break; - case 90: *a = 'f'; *b = 'i'; *c = 'n'; break; - case 91: *a = 'f'; *b = 'o'; *c = 'n'; break; - case 92: *a = 'b'; *b = 'a'; *c = 'n'; break; - case 93: *a = 'm'; *b = 'o'; *c = 'r'; break; - case 94: *a = 'w'; *b = 'o'; *c = 'r'; break; - case 95: *a = 's'; *b = 'i'; *c = 'p'; break; - case 96: *a = 'r'; *b = 'o'; *c = 'n'; break; - case 97: *a = 'n'; *b = 'o'; *c = 'r'; break; - case 98: *a = 'b'; *b = 'o'; *c = 't'; break; - case 99: *a = 'w'; *b = 'i'; *c = 'c'; break; - case 100: *a = 's'; *b = 'o'; *c = 'c'; break; - case 101: *a = 'w'; *b = 'a'; *c = 't'; break; - case 102: *a = 'd'; *b = 'o'; *c = 'l'; break; - case 103: *a = 'm'; *b = 'a'; *c = 'g'; break; - case 104: *a = 'p'; *b = 'i'; *c = 'c'; break; - case 105: *a = 'd'; *b = 'a'; *c = 'v'; break; - case 106: *a = 'b'; *b = 'i'; *c = 'd'; break; - case 107: *a = 'b'; *b = 'a'; *c = 'l'; break; - case 108: *a = 't'; *b = 'i'; *c = 'm'; break; - case 109: *a = 't'; *b = 'a'; *c = 's'; break; - case 110: *a = 'm'; *b = 'a'; *c = 'l'; break; - case 111: *a = 'l'; *b = 'i'; *c = 'g'; break; - case 112: *a = 's'; *b = 'i'; *c = 'v'; break; - case 113: *a = 't'; *b = 'a'; *c = 'g'; break; - case 114: *a = 'p'; *b = 'a'; *c = 'd'; break; - case 115: *a = 's'; *b = 'a'; *c = 'l'; break; - case 116: *a = 'd'; *b = 'i'; *c = 'v'; break; - case 117: *a = 'd'; *b = 'a'; *c = 'c'; break; - case 118: *a = 't'; *b = 'a'; *c = 'n'; break; - case 119: *a = 's'; *b = 'i'; *c = 'd'; break; - case 120: *a = 'f'; *b = 'a'; *c = 'b'; break; - case 121: *a = 't'; *b = 'a'; *c = 'r'; break; - case 122: *a = 'm'; *b = 'o'; *c = 'n'; break; - case 123: *a = 'r'; *b = 'a'; *c = 'n'; break; - case 124: *a = 'n'; *b = 'i'; *c = 's'; break; - case 125: *a = 'w'; *b = 'o'; *c = 'l'; break; - case 126: *a = 'm'; *b = 'i'; *c = 's'; break; - case 127: *a = 'p'; *b = 'a'; *c = 'l'; break; - case 128: *a = 'l'; *b = 'a'; *c = 's'; break; - case 129: *a = 'd'; *b = 'i'; *c = 's'; break; - case 130: *a = 'm'; *b = 'a'; *c = 'p'; break; - case 131: *a = 'r'; *b = 'a'; *c = 'b'; break; - case 132: *a = 't'; *b = 'o'; *c = 'b'; break; - case 133: *a = 'r'; *b = 'o'; *c = 'l'; break; - case 134: *a = 'l'; *b = 'a'; *c = 't'; break; - case 135: *a = 'l'; *b = 'o'; *c = 'n'; break; - case 136: *a = 'n'; *b = 'o'; *c = 'd'; break; - case 137: *a = 'n'; *b = 'a'; *c = 'v'; break; - case 138: *a = 'f'; *b = 'i'; *c = 'g'; break; - case 139: *a = 'n'; *b = 'o'; *c = 'm'; break; - case 140: *a = 'n'; *b = 'i'; *c = 'b'; break; - case 141: *a = 'p'; *b = 'a'; *c = 'g'; break; - case 142: *a = 's'; *b = 'o'; *c = 'p'; break; - case 143: *a = 'r'; *b = 'a'; *c = 'l'; break; - case 144: *a = 'b'; *b = 'i'; *c = 'l'; break; - case 145: *a = 'h'; *b = 'a'; *c = 'd'; break; - case 146: *a = 'd'; *b = 'o'; *c = 'c'; break; - case 147: *a = 'r'; *b = 'i'; *c = 'd'; break; - case 148: *a = 'm'; *b = 'o'; *c = 'c'; break; - case 149: *a = 'p'; *b = 'a'; *c = 'c'; break; - case 150: *a = 'r'; *b = 'a'; *c = 'v'; break; - case 151: *a = 'r'; *b = 'i'; *c = 'p'; break; - case 152: *a = 'f'; *b = 'a'; *c = 'l'; break; - case 153: *a = 't'; *b = 'o'; *c = 'd'; break; - case 154: *a = 't'; *b = 'i'; *c = 'l'; break; - case 155: *a = 't'; *b = 'i'; *c = 'n'; break; - case 156: *a = 'h'; *b = 'a'; *c = 'p'; break; - case 157: *a = 'm'; *b = 'i'; *c = 'c'; break; - case 158: *a = 'f'; *b = 'a'; *c = 'n'; break; - case 159: *a = 'p'; *b = 'a'; *c = 't'; break; - case 160: *a = 't'; *b = 'a'; *c = 'c'; break; - case 161: *a = 'l'; *b = 'a'; *c = 'b'; break; - case 162: *a = 'm'; *b = 'o'; *c = 'g'; break; - case 163: *a = 's'; *b = 'i'; *c = 'm'; break; - case 164: *a = 's'; *b = 'o'; *c = 'n'; break; - case 165: *a = 'p'; *b = 'i'; *c = 'n'; break; - case 166: *a = 'l'; *b = 'o'; *c = 'm'; break; - case 167: *a = 'r'; *b = 'i'; *c = 'c'; break; - case 168: *a = 't'; *b = 'a'; *c = 'p'; break; - case 169: *a = 'f'; *b = 'i'; *c = 'r'; break; - case 170: *a = 'h'; *b = 'a'; *c = 's'; break; - case 171: *a = 'b'; *b = 'o'; *c = 's'; break; - case 172: *a = 'b'; *b = 'a'; *c = 't'; break; - case 173: *a = 'p'; *b = 'o'; *c = 'c'; break; - case 174: *a = 'h'; *b = 'a'; *c = 'c'; break; - case 175: *a = 't'; *b = 'i'; *c = 'd'; break; - case 176: *a = 'h'; *b = 'a'; *c = 'v'; break; - case 177: *a = 's'; *b = 'a'; *c = 'p'; break; - case 178: *a = 'l'; *b = 'i'; *c = 'n'; break; - case 179: *a = 'd'; *b = 'i'; *c = 'b'; break; - case 180: *a = 'h'; *b = 'o'; *c = 's'; break; - case 181: *a = 'd'; *b = 'a'; *c = 'b'; break; - case 182: *a = 'b'; *b = 'i'; *c = 't'; break; - case 183: *a = 'b'; *b = 'a'; *c = 'r'; break; - case 184: *a = 'r'; *b = 'a'; *c = 'c'; break; - case 185: *a = 'p'; *b = 'a'; *c = 'r'; break; - case 186: *a = 'l'; *b = 'o'; *c = 'd'; break; - case 187: *a = 'd'; *b = 'o'; *c = 's'; break; - case 188: *a = 'b'; *b = 'o'; *c = 'r'; break; - case 189: *a = 't'; *b = 'o'; *c = 'c'; break; - case 190: *a = 'h'; *b = 'i'; *c = 'l'; break; - case 191: *a = 'm'; *b = 'a'; *c = 'c'; break; - case 192: *a = 't'; *b = 'o'; *c = 'm'; break; - case 193: *a = 'd'; *b = 'i'; *c = 'g'; break; - case 194: *a = 'f'; *b = 'i'; *c = 'l'; break; - case 195: *a = 'f'; *b = 'a'; *c = 's'; break; - case 196: *a = 'm'; *b = 'i'; *c = 't'; break; - case 197: *a = 'h'; *b = 'o'; *c = 'b'; break; - case 198: *a = 'h'; *b = 'a'; *c = 'r'; break; - case 199: *a = 'm'; *b = 'i'; *c = 'g'; break; - case 200: *a = 'h'; *b = 'i'; *c = 'n'; break; - case 201: *a = 'r'; *b = 'a'; *c = 'd'; break; - case 202: *a = 'm'; *b = 'a'; *c = 's'; break; - case 203: *a = 'h'; *b = 'a'; *c = 'l'; break; - case 204: *a = 'r'; *b = 'a'; *c = 'g'; break; - case 205: *a = 'l'; *b = 'a'; *c = 'g'; break; - case 206: *a = 'f'; *b = 'a'; *c = 'd'; break; - case 207: *a = 't'; *b = 'o'; *c = 'p'; break; - case 208: *a = 'm'; *b = 'o'; *c = 'p'; break; - case 209: *a = 'h'; *b = 'a'; *c = 'b'; break; - case 210: *a = 'n'; *b = 'i'; *c = 'l'; break; - case 211: *a = 'n'; *b = 'o'; *c = 's'; break; - case 212: *a = 'm'; *b = 'i'; *c = 'l'; break; - case 213: *a = 'f'; *b = 'o'; *c = 'p'; break; - case 214: *a = 'f'; *b = 'a'; *c = 'm'; break; - case 215: *a = 'd'; *b = 'a'; *c = 't'; break; - case 216: *a = 'n'; *b = 'o'; *c = 'l'; break; - case 217: *a = 'd'; *b = 'i'; *c = 'n'; break; - case 218: *a = 'h'; *b = 'a'; *c = 't'; break; - case 219: *a = 'n'; *b = 'a'; *c = 'c'; break; - case 220: *a = 'r'; *b = 'i'; *c = 's'; break; - case 221: *a = 'f'; *b = 'o'; *c = 't'; break; - case 222: *a = 'r'; *b = 'i'; *c = 'b'; break; - case 223: *a = 'h'; *b = 'o'; *c = 'c'; break; - case 224: *a = 'n'; *b = 'i'; *c = 'm'; break; - case 225: *a = 'l'; *b = 'a'; *c = 'r'; break; - case 226: *a = 'f'; *b = 'i'; *c = 't'; break; - case 227: *a = 'w'; *b = 'a'; *c = 'l'; break; - case 228: *a = 'r'; *b = 'a'; *c = 'p'; break; - case 229: *a = 's'; *b = 'a'; *c = 'r'; break; - case 230: *a = 'n'; *b = 'a'; *c = 'l'; break; - case 231: *a = 'm'; *b = 'o'; *c = 's'; break; - case 232: *a = 'l'; *b = 'a'; *c = 'n'; break; - case 233: *a = 'd'; *b = 'o'; *c = 'n'; break; - case 234: *a = 'd'; *b = 'a'; *c = 'n'; break; - case 235: *a = 'l'; *b = 'a'; *c = 'd'; break; - case 236: *a = 'd'; *b = 'o'; *c = 'v'; break; - case 237: *a = 'r'; *b = 'i'; *c = 'v'; break; - case 238: *a = 'b'; *b = 'a'; *c = 'c'; break; - case 239: *a = 'p'; *b = 'o'; *c = 'l'; break; - case 240: *a = 'l'; *b = 'a'; *c = 'p'; break; - case 241: *a = 't'; *b = 'a'; *c = 'l'; break; - case 242: *a = 'p'; *b = 'i'; *c = 't'; break; - case 243: *a = 'n'; *b = 'a'; *c = 'm'; break; - case 244: *a = 'b'; *b = 'o'; *c = 'n'; break; - case 245: *a = 'r'; *b = 'o'; *c = 's'; break; - case 246: *a = 't'; *b = 'o'; *c = 'n'; break; - case 247: *a = 'f'; *b = 'o'; *c = 'd'; break; - case 248: *a = 'p'; *b = 'o'; *c = 'n'; break; - case 249: *a = 's'; *b = 'o'; *c = 'v'; break; - case 250: *a = 'n'; *b = 'o'; *c = 'c'; break; - case 251: *a = 's'; *b = 'o'; *c = 'r'; break; - case 252: *a = 'l'; *b = 'a'; *c = 'v'; break; - case 253: *a = 'm'; *b = 'a'; *c = 't'; break; - case 254: *a = 'm'; *b = 'i'; *c = 'p'; break; - case 255: *a = 'f'; *b = 'i'; *c = 'p'; break; - default: u3m_bail(c3__exit); - } -} - -u3_noun -u3_po_find_suffix(c3_y one, c3_y two, c3_y three) { - switch (one) { - case 'b': switch (two) { - case 'e': switch (three) { - case 'c': return u3nc(0, 238); - case 'l': return u3nc(0, 107); - case 'n': return u3nc(0, 92); - case 'p': return u3nc(0, 183); - case 'r': return u3nc(0, 172); - case 's': return u3nc(0, 56); - case 't': return u3nc(0, 106); - case 'x': return u3nc(0, 144); - default: return 0; - } - case 'u': switch (three) { - case 'd': return u3nc(0, 2); - case 'r': return u3nc(0, 60); - case 's': return u3nc(0, 182); - default: return 0; - } - case 'y': switch (three) { - case 'l': return u3nc(0, 176); - case 'n': return u3nc(0, 45); - case 'r': return u3nc(0, 244); - case 't': return u3nc(0, 188); - default: return 0; - } - default: return 0; - } - case 'd': switch (two) { - case 'e': switch (three) { - case 'b': return u3nc(0, 171); - case 'c': return u3nc(0, 98); - case 'f': return u3nc(0, 181); - case 'g': return u3nc(0, 117); - case 'l': return u3nc(0, 37); - case 'm': return u3nc(0, 234); - case 'n': return u3nc(0, 66); - case 'p': return u3nc(0, 23); - case 'r': return u3nc(0, 61); - case 's': return u3nc(0, 215); - case 't': return u3nc(0, 105); - case 'v': return u3nc(0, 179); - case 'x': return u3nc(0, 57); - default: return 0; - } - case 'u': switch (three) { - case 'c': return u3nc(0, 193); - case 'l': return u3nc(0, 49); - case 'n': return u3nc(0, 217); - case 'r': return u3nc(0, 11); - case 's': return u3nc(0, 129); - case 't': return u3nc(0, 116); - case 'x': return u3nc(0, 146); - default: return 0; - } - case 'y': switch (three) { - case 'l': return u3nc(0, 102); - case 'n': return u3nc(0, 233); - case 'r': return u3nc(0, 18); - case 's': return u3nc(0, 24); - case 't': return u3nc(0, 187); - default: return 0; - } - default: return 0; - } - case 'f': switch (two) { - case 'e': switch (three) { - case 'b': return u3nc(0, 47); - case 'd': return u3nc(0, 236); - case 'l': return u3nc(0, 120); - case 'n': return u3nc(0, 206); - case 'p': return u3nc(0, 152); - case 'r': return u3nc(0, 158); - case 's': return u3nc(0, 255); - case 't': return u3nc(0, 214); - case 'x': return u3nc(0, 195); - default: return 0; - } - case 'u': switch (three) { - case 'l': return u3nc(0, 8); - case 'n': return u3nc(0, 138); - case 'r': return u3nc(0, 194); - case 's': return u3nc(0, 90); - default: return 0; - } - case 'y': switch (three) { - case 'l': return u3nc(0, 169); - case 'n': return u3nc(0, 226); - case 'r': return u3nc(0, 247); - default: return 0; - } - default: return 0; - } - case 'h': switch (two) { - case 'e': switch (three) { - case 'b': return u3nc(0, 20); - case 'c': return u3nc(0, 27); - case 'p': return u3nc(0, 91); - case 's': return u3nc(0, 213); - case 't': return u3nc(0, 50); - case 'x': return u3nc(0, 46); - default: return 0; - } - case 'u': switch (three) { - case 'l': return u3nc(0, 221); - case 's': return u3nc(0, 209); - case 't': return u3nc(0, 174); - default: return 0; - } - default: return 0; - } - case 'l': switch (two) { - case 'e': switch (three) { - case 'b': return u3nc(0, 145); - case 'c': return u3nc(0, 203); - case 'd': return u3nc(0, 41); - case 'g': return u3nc(0, 156); - case 'n': return u3nc(0, 198); - case 'p': return u3nc(0, 170); - case 'r': return u3nc(0, 218); - case 't': return u3nc(0, 7); - case 'v': return u3nc(0, 190); - case 'x': return u3nc(0, 200); - default: return 0; - } - case 'u': switch (three) { - case 'c': return u3nc(0, 197); - case 'd': return u3nc(0, 223); - case 'g': return u3nc(0, 26); - case 'n': return u3nc(0, 32); - case 'p': return u3nc(0, 22); - case 'r': return u3nc(0, 180); - case 's': return u3nc(0, 161); - case 't': return u3nc(0, 34); - case 'x': return u3nc(0, 235); - default: return 0; - } - case 'y': switch (three) { - case 'd': return u3nc(0, 205); - case 'n': return u3nc(0, 232); - case 'r': return u3nc(0, 240); - case 's': return u3nc(0, 225); - case 't': return u3nc(0, 128); - case 'x': return u3nc(0, 134); - default: return 0; - } - default: return 0; - } - case 'm': switch (two) { - case 'e': switch (three) { - case 'b': return u3nc(0, 114); - case 'c': return u3nc(0, 141); - case 'd': return u3nc(0, 127); - case 'g': return u3nc(0, 78); - case 'l': return u3nc(0, 185); - case 'p': return u3nc(0, 33); - case 'r': return u3nc(0, 159); - case 's': return u3nc(0, 104); - case 't': return u3nc(0, 43); - case 'v': return u3nc(0, 51); - case 'x': return u3nc(0, 165); - default: return 0; - } - case 'u': switch (three) { - case 'd': return u3nc(0, 242); - case 'g': return u3nc(0, 173); - case 'l': return u3nc(0, 81); - case 'n': return u3nc(0, 239); - case 'r': return u3nc(0, 248); - case 's': return u3nc(0, 93); - case 't': return u3nc(0, 86); - default: return 0; - } - case 'y': switch (three) { - case 'l': return u3nc(0, 191); - case 'n': return u3nc(0, 103); - case 'r': return u3nc(0, 110); - default: return 0; - } - default: return 0; - } - case 'n': switch (two) { - case 'e': switch (three) { - case 'b': return u3nc(0, 130); - case 'c': return u3nc(0, 1); - case 'd': return u3nc(0, 202); - case 'l': return u3nc(0, 253); - case 'm': return u3nc(0, 157); - case 'p': return u3nc(0, 62); - case 'r': return u3nc(0, 199); - case 's': return u3nc(0, 212); - case 't': return u3nc(0, 79); - case 'v': return u3nc(0, 254); - case 'x': return u3nc(0, 31); - default: return 0; - } - case 'u': switch (three) { - case 'b': return u3nc(0, 126); - case 'l': return u3nc(0, 196); - case 'm': return u3nc(0, 148); - case 'p': return u3nc(0, 19); - case 's': return u3nc(0, 162); - case 't': return u3nc(0, 67); - case 'x': return u3nc(0, 122); - default: return 0; - } - case 'y': switch (three) { - case 'd': return u3nc(0, 208); - case 'l': return u3nc(0, 231); - case 'm': return u3nc(0, 82); - case 'r': return u3nc(0, 219); - case 's': return u3nc(0, 230); - case 't': return u3nc(0, 243); - case 'x': return u3nc(0, 87); - default: return 0; - } - default: return 0; - } - case 'p': switch (two) { - case 'e': switch (three) { - case 'c': return u3nc(0, 252); - case 'd': return u3nc(0, 39); - case 'g': return u3nc(0, 21); - case 'l': return u3nc(0, 111); - case 'm': return u3nc(0, 178); - case 'n': return u3nc(0, 9); - case 'r': return u3nc(0, 5); - case 's': return u3nc(0, 36); - case 't': return u3nc(0, 69); - case 'x': return u3nc(0, 186); - default: return 0; - } - case 'u': switch (three) { - case 'b': return u3nc(0, 166); - case 'n': return u3nc(0, 135); - case 'r': return u3nc(0, 63); - case 't': return u3nc(0, 25); - default: return 0; - } - case 'y': switch (three) { - case 'l': return u3nc(0, 48); - case 'x': return u3nc(0, 149); - default: return 0; - } - default: return 0; - } - case 'r': switch (two) { - case 'e': switch (three) { - case 'b': return u3nc(0, 65); - case 'c': return u3nc(0, 77); - case 'd': return u3nc(0, 137); - case 'f': return u3nc(0, 140); - case 'g': return u3nc(0, 72); - case 'l': return u3nc(0, 210); - case 'm': return u3nc(0, 224); - case 'n': return u3nc(0, 124); - case 'p': return u3nc(0, 250); - case 's': return u3nc(0, 136); - case 't': return u3nc(0, 216); - case 'v': return u3nc(0, 139); - case 'x': return u3nc(0, 88); - default: return 0; - } - case 'u': switch (three) { - case 'c': return u3nc(0, 97); - case 'd': return u3nc(0, 211); - case 'l': return u3nc(0, 70); - case 'm': return u3nc(0, 131); - case 'n': return u3nc(0, 184); - case 'p': return u3nc(0, 201); - case 's': return u3nc(0, 143); - case 't': return u3nc(0, 52); - case 'x': return u3nc(0, 123); - default: return 0; - } - case 'y': switch (three) { - case 'c': return u3nc(0, 228); - case 'd': return u3nc(0, 204); - case 'g': return u3nc(0, 150); - case 'l': return u3nc(0, 222); - case 'm': return u3nc(0, 167); - case 'n': return u3nc(0, 147); - case 'p': return u3nc(0, 16); - case 's': return u3nc(0, 64); - case 't': return u3nc(0, 28); - case 'x': return u3nc(0, 151); - default: return 0; - } - default: return 0; - } - case 's': switch (two) { - case 'e': switch (three) { - case 'b': return u3nc(0, 220); - case 'c': return u3nc(0, 80); - case 'd': return u3nc(0, 237); - case 'f': return u3nc(0, 58); - case 'g': return u3nc(0, 133); - case 'l': return u3nc(0, 96); - case 'm': return u3nc(0, 75); - case 'n': return u3nc(0, 245); - case 'p': return u3nc(0, 35); - case 'r': return u3nc(0, 13); - case 't': return u3nc(0, 115); - case 'v': return u3nc(0, 4); - default: return 0; - } - case 'u': switch (three) { - case 'b': return u3nc(0, 68); - case 'd': return u3nc(0, 177); - case 'g': return u3nc(0, 229); - case 'l': return u3nc(0, 38); - case 'm': return u3nc(0, 85); - case 'n': return u3nc(0, 15); - case 'p': return u3nc(0, 74); - case 'r': return u3nc(0, 119); - case 't': return u3nc(0, 6); - default: return 0; - } - case 'y': switch (three) { - case 'd': return u3nc(0, 30); - case 'l': return u3nc(0, 163); - case 'm': return u3nc(0, 95); - case 'n': return u3nc(0, 71); - case 'p': return u3nc(0, 112); - case 'r': return u3nc(0, 100); - case 't': return u3nc(0, 10); - case 'x': return u3nc(0, 17); - default: return 0; - } - default: return 0; - } - case 't': switch (two) { - case 'e': switch (three) { - case 'b': return u3nc(0, 89); - case 'c': return u3nc(0, 164); - case 'd': return u3nc(0, 142); - case 'g': return u3nc(0, 251); - case 'l': return u3nc(0, 249); - case 'm': return u3nc(0, 40); - case 'n': return u3nc(0, 160); - case 'p': return u3nc(0, 55); - case 'r': return u3nc(0, 113); - case 's': return u3nc(0, 241); - case 'v': return u3nc(0, 83); - case 'x': return u3nc(0, 118); - default: return 0; - } - case 'u': switch (three) { - case 'c': return u3nc(0, 168); - case 'd': return u3nc(0, 121); - case 'g': return u3nc(0, 109); - case 'l': return u3nc(0, 42); - case 'n': return u3nc(0, 175); - case 's': return u3nc(0, 154); - case 'x': return u3nc(0, 108); - default: return 0; - } - case 'y': switch (three) { - case 'c': return u3nc(0, 155); - case 'd': return u3nc(0, 73); - case 'l': return u3nc(0, 53); - case 'n': return u3nc(0, 132); - case 'p': return u3nc(0, 189); - case 'r': return u3nc(0, 153); - case 'v': return u3nc(0, 29); - default: return 0; - } - default: return 0; - } - case 'w': switch (two) { - case 'e': switch (three) { - case 'b': return u3nc(0, 84); - case 'd': return u3nc(0, 192); - case 'g': return u3nc(0, 246); - case 'l': return u3nc(0, 207); - case 'n': return u3nc(0, 44); - case 'p': return u3nc(0, 12); - case 'r': return u3nc(0, 227); - case 's': return u3nc(0, 3); - case 't': return u3nc(0, 101); - case 'x': return u3nc(0, 99); - default: return 0; - } - case 'y': switch (three) { - case 'c': return u3nc(0, 59); - case 'd': return u3nc(0, 54); - case 'l': return u3nc(0, 14); - case 'n': return u3nc(0, 76); - case 't': return u3nc(0, 125); - case 'x': return u3nc(0, 94); - default: return 0; - } - default: return 0; - } - case 'z': switch (two) { - case 'o': switch (three) { - case 'd': return u3nc(0, 0); - default: return 0; - } - default: return 0; - } - default: return 0; - } -} - -void -u3_po_to_suffix(u3_noun id, c3_y* a, c3_y* b, c3_y* c) -{ - switch (id) { - case 0: *a = 'z'; *b = 'o'; *c = 'd'; break; - case 1: *a = 'n'; *b = 'e'; *c = 'c'; break; - case 2: *a = 'b'; *b = 'u'; *c = 'd'; break; - case 3: *a = 'w'; *b = 'e'; *c = 's'; break; - case 4: *a = 's'; *b = 'e'; *c = 'v'; break; - case 5: *a = 'p'; *b = 'e'; *c = 'r'; break; - case 6: *a = 's'; *b = 'u'; *c = 't'; break; - case 7: *a = 'l'; *b = 'e'; *c = 't'; break; - case 8: *a = 'f'; *b = 'u'; *c = 'l'; break; - case 9: *a = 'p'; *b = 'e'; *c = 'n'; break; - case 10: *a = 's'; *b = 'y'; *c = 't'; break; - case 11: *a = 'd'; *b = 'u'; *c = 'r'; break; - case 12: *a = 'w'; *b = 'e'; *c = 'p'; break; - case 13: *a = 's'; *b = 'e'; *c = 'r'; break; - case 14: *a = 'w'; *b = 'y'; *c = 'l'; break; - case 15: *a = 's'; *b = 'u'; *c = 'n'; break; - case 16: *a = 'r'; *b = 'y'; *c = 'p'; break; - case 17: *a = 's'; *b = 'y'; *c = 'x'; break; - case 18: *a = 'd'; *b = 'y'; *c = 'r'; break; - case 19: *a = 'n'; *b = 'u'; *c = 'p'; break; - case 20: *a = 'h'; *b = 'e'; *c = 'b'; break; - case 21: *a = 'p'; *b = 'e'; *c = 'g'; break; - case 22: *a = 'l'; *b = 'u'; *c = 'p'; break; - case 23: *a = 'd'; *b = 'e'; *c = 'p'; break; - case 24: *a = 'd'; *b = 'y'; *c = 's'; break; - case 25: *a = 'p'; *b = 'u'; *c = 't'; break; - case 26: *a = 'l'; *b = 'u'; *c = 'g'; break; - case 27: *a = 'h'; *b = 'e'; *c = 'c'; break; - case 28: *a = 'r'; *b = 'y'; *c = 't'; break; - case 29: *a = 't'; *b = 'y'; *c = 'v'; break; - case 30: *a = 's'; *b = 'y'; *c = 'd'; break; - case 31: *a = 'n'; *b = 'e'; *c = 'x'; break; - case 32: *a = 'l'; *b = 'u'; *c = 'n'; break; - case 33: *a = 'm'; *b = 'e'; *c = 'p'; break; - case 34: *a = 'l'; *b = 'u'; *c = 't'; break; - case 35: *a = 's'; *b = 'e'; *c = 'p'; break; - case 36: *a = 'p'; *b = 'e'; *c = 's'; break; - case 37: *a = 'd'; *b = 'e'; *c = 'l'; break; - case 38: *a = 's'; *b = 'u'; *c = 'l'; break; - case 39: *a = 'p'; *b = 'e'; *c = 'd'; break; - case 40: *a = 't'; *b = 'e'; *c = 'm'; break; - case 41: *a = 'l'; *b = 'e'; *c = 'd'; break; - case 42: *a = 't'; *b = 'u'; *c = 'l'; break; - case 43: *a = 'm'; *b = 'e'; *c = 't'; break; - case 44: *a = 'w'; *b = 'e'; *c = 'n'; break; - case 45: *a = 'b'; *b = 'y'; *c = 'n'; break; - case 46: *a = 'h'; *b = 'e'; *c = 'x'; break; - case 47: *a = 'f'; *b = 'e'; *c = 'b'; break; - case 48: *a = 'p'; *b = 'y'; *c = 'l'; break; - case 49: *a = 'd'; *b = 'u'; *c = 'l'; break; - case 50: *a = 'h'; *b = 'e'; *c = 't'; break; - case 51: *a = 'm'; *b = 'e'; *c = 'v'; break; - case 52: *a = 'r'; *b = 'u'; *c = 't'; break; - case 53: *a = 't'; *b = 'y'; *c = 'l'; break; - case 54: *a = 'w'; *b = 'y'; *c = 'd'; break; - case 55: *a = 't'; *b = 'e'; *c = 'p'; break; - case 56: *a = 'b'; *b = 'e'; *c = 's'; break; - case 57: *a = 'd'; *b = 'e'; *c = 'x'; break; - case 58: *a = 's'; *b = 'e'; *c = 'f'; break; - case 59: *a = 'w'; *b = 'y'; *c = 'c'; break; - case 60: *a = 'b'; *b = 'u'; *c = 'r'; break; - case 61: *a = 'd'; *b = 'e'; *c = 'r'; break; - case 62: *a = 'n'; *b = 'e'; *c = 'p'; break; - case 63: *a = 'p'; *b = 'u'; *c = 'r'; break; - case 64: *a = 'r'; *b = 'y'; *c = 's'; break; - case 65: *a = 'r'; *b = 'e'; *c = 'b'; break; - case 66: *a = 'd'; *b = 'e'; *c = 'n'; break; - case 67: *a = 'n'; *b = 'u'; *c = 't'; break; - case 68: *a = 's'; *b = 'u'; *c = 'b'; break; - case 69: *a = 'p'; *b = 'e'; *c = 't'; break; - case 70: *a = 'r'; *b = 'u'; *c = 'l'; break; - case 71: *a = 's'; *b = 'y'; *c = 'n'; break; - case 72: *a = 'r'; *b = 'e'; *c = 'g'; break; - case 73: *a = 't'; *b = 'y'; *c = 'd'; break; - case 74: *a = 's'; *b = 'u'; *c = 'p'; break; - case 75: *a = 's'; *b = 'e'; *c = 'm'; break; - case 76: *a = 'w'; *b = 'y'; *c = 'n'; break; - case 77: *a = 'r'; *b = 'e'; *c = 'c'; break; - case 78: *a = 'm'; *b = 'e'; *c = 'g'; break; - case 79: *a = 'n'; *b = 'e'; *c = 't'; break; - case 80: *a = 's'; *b = 'e'; *c = 'c'; break; - case 81: *a = 'm'; *b = 'u'; *c = 'l'; break; - case 82: *a = 'n'; *b = 'y'; *c = 'm'; break; - case 83: *a = 't'; *b = 'e'; *c = 'v'; break; - case 84: *a = 'w'; *b = 'e'; *c = 'b'; break; - case 85: *a = 's'; *b = 'u'; *c = 'm'; break; - case 86: *a = 'm'; *b = 'u'; *c = 't'; break; - case 87: *a = 'n'; *b = 'y'; *c = 'x'; break; - case 88: *a = 'r'; *b = 'e'; *c = 'x'; break; - case 89: *a = 't'; *b = 'e'; *c = 'b'; break; - case 90: *a = 'f'; *b = 'u'; *c = 's'; break; - case 91: *a = 'h'; *b = 'e'; *c = 'p'; break; - case 92: *a = 'b'; *b = 'e'; *c = 'n'; break; - case 93: *a = 'm'; *b = 'u'; *c = 's'; break; - case 94: *a = 'w'; *b = 'y'; *c = 'x'; break; - case 95: *a = 's'; *b = 'y'; *c = 'm'; break; - case 96: *a = 's'; *b = 'e'; *c = 'l'; break; - case 97: *a = 'r'; *b = 'u'; *c = 'c'; break; - case 98: *a = 'd'; *b = 'e'; *c = 'c'; break; - case 99: *a = 'w'; *b = 'e'; *c = 'x'; break; - case 100: *a = 's'; *b = 'y'; *c = 'r'; break; - case 101: *a = 'w'; *b = 'e'; *c = 't'; break; - case 102: *a = 'd'; *b = 'y'; *c = 'l'; break; - case 103: *a = 'm'; *b = 'y'; *c = 'n'; break; - case 104: *a = 'm'; *b = 'e'; *c = 's'; break; - case 105: *a = 'd'; *b = 'e'; *c = 't'; break; - case 106: *a = 'b'; *b = 'e'; *c = 't'; break; - case 107: *a = 'b'; *b = 'e'; *c = 'l'; break; - case 108: *a = 't'; *b = 'u'; *c = 'x'; break; - case 109: *a = 't'; *b = 'u'; *c = 'g'; break; - case 110: *a = 'm'; *b = 'y'; *c = 'r'; break; - case 111: *a = 'p'; *b = 'e'; *c = 'l'; break; - case 112: *a = 's'; *b = 'y'; *c = 'p'; break; - case 113: *a = 't'; *b = 'e'; *c = 'r'; break; - case 114: *a = 'm'; *b = 'e'; *c = 'b'; break; - case 115: *a = 's'; *b = 'e'; *c = 't'; break; - case 116: *a = 'd'; *b = 'u'; *c = 't'; break; - case 117: *a = 'd'; *b = 'e'; *c = 'g'; break; - case 118: *a = 't'; *b = 'e'; *c = 'x'; break; - case 119: *a = 's'; *b = 'u'; *c = 'r'; break; - case 120: *a = 'f'; *b = 'e'; *c = 'l'; break; - case 121: *a = 't'; *b = 'u'; *c = 'd'; break; - case 122: *a = 'n'; *b = 'u'; *c = 'x'; break; - case 123: *a = 'r'; *b = 'u'; *c = 'x'; break; - case 124: *a = 'r'; *b = 'e'; *c = 'n'; break; - case 125: *a = 'w'; *b = 'y'; *c = 't'; break; - case 126: *a = 'n'; *b = 'u'; *c = 'b'; break; - case 127: *a = 'm'; *b = 'e'; *c = 'd'; break; - case 128: *a = 'l'; *b = 'y'; *c = 't'; break; - case 129: *a = 'd'; *b = 'u'; *c = 's'; break; - case 130: *a = 'n'; *b = 'e'; *c = 'b'; break; - case 131: *a = 'r'; *b = 'u'; *c = 'm'; break; - case 132: *a = 't'; *b = 'y'; *c = 'n'; break; - case 133: *a = 's'; *b = 'e'; *c = 'g'; break; - case 134: *a = 'l'; *b = 'y'; *c = 'x'; break; - case 135: *a = 'p'; *b = 'u'; *c = 'n'; break; - case 136: *a = 'r'; *b = 'e'; *c = 's'; break; - case 137: *a = 'r'; *b = 'e'; *c = 'd'; break; - case 138: *a = 'f'; *b = 'u'; *c = 'n'; break; - case 139: *a = 'r'; *b = 'e'; *c = 'v'; break; - case 140: *a = 'r'; *b = 'e'; *c = 'f'; break; - case 141: *a = 'm'; *b = 'e'; *c = 'c'; break; - case 142: *a = 't'; *b = 'e'; *c = 'd'; break; - case 143: *a = 'r'; *b = 'u'; *c = 's'; break; - case 144: *a = 'b'; *b = 'e'; *c = 'x'; break; - case 145: *a = 'l'; *b = 'e'; *c = 'b'; break; - case 146: *a = 'd'; *b = 'u'; *c = 'x'; break; - case 147: *a = 'r'; *b = 'y'; *c = 'n'; break; - case 148: *a = 'n'; *b = 'u'; *c = 'm'; break; - case 149: *a = 'p'; *b = 'y'; *c = 'x'; break; - case 150: *a = 'r'; *b = 'y'; *c = 'g'; break; - case 151: *a = 'r'; *b = 'y'; *c = 'x'; break; - case 152: *a = 'f'; *b = 'e'; *c = 'p'; break; - case 153: *a = 't'; *b = 'y'; *c = 'r'; break; - case 154: *a = 't'; *b = 'u'; *c = 's'; break; - case 155: *a = 't'; *b = 'y'; *c = 'c'; break; - case 156: *a = 'l'; *b = 'e'; *c = 'g'; break; - case 157: *a = 'n'; *b = 'e'; *c = 'm'; break; - case 158: *a = 'f'; *b = 'e'; *c = 'r'; break; - case 159: *a = 'm'; *b = 'e'; *c = 'r'; break; - case 160: *a = 't'; *b = 'e'; *c = 'n'; break; - case 161: *a = 'l'; *b = 'u'; *c = 's'; break; - case 162: *a = 'n'; *b = 'u'; *c = 's'; break; - case 163: *a = 's'; *b = 'y'; *c = 'l'; break; - case 164: *a = 't'; *b = 'e'; *c = 'c'; break; - case 165: *a = 'm'; *b = 'e'; *c = 'x'; break; - case 166: *a = 'p'; *b = 'u'; *c = 'b'; break; - case 167: *a = 'r'; *b = 'y'; *c = 'm'; break; - case 168: *a = 't'; *b = 'u'; *c = 'c'; break; - case 169: *a = 'f'; *b = 'y'; *c = 'l'; break; - case 170: *a = 'l'; *b = 'e'; *c = 'p'; break; - case 171: *a = 'd'; *b = 'e'; *c = 'b'; break; - case 172: *a = 'b'; *b = 'e'; *c = 'r'; break; - case 173: *a = 'm'; *b = 'u'; *c = 'g'; break; - case 174: *a = 'h'; *b = 'u'; *c = 't'; break; - case 175: *a = 't'; *b = 'u'; *c = 'n'; break; - case 176: *a = 'b'; *b = 'y'; *c = 'l'; break; - case 177: *a = 's'; *b = 'u'; *c = 'd'; break; - case 178: *a = 'p'; *b = 'e'; *c = 'm'; break; - case 179: *a = 'd'; *b = 'e'; *c = 'v'; break; - case 180: *a = 'l'; *b = 'u'; *c = 'r'; break; - case 181: *a = 'd'; *b = 'e'; *c = 'f'; break; - case 182: *a = 'b'; *b = 'u'; *c = 's'; break; - case 183: *a = 'b'; *b = 'e'; *c = 'p'; break; - case 184: *a = 'r'; *b = 'u'; *c = 'n'; break; - case 185: *a = 'm'; *b = 'e'; *c = 'l'; break; - case 186: *a = 'p'; *b = 'e'; *c = 'x'; break; - case 187: *a = 'd'; *b = 'y'; *c = 't'; break; - case 188: *a = 'b'; *b = 'y'; *c = 't'; break; - case 189: *a = 't'; *b = 'y'; *c = 'p'; break; - case 190: *a = 'l'; *b = 'e'; *c = 'v'; break; - case 191: *a = 'm'; *b = 'y'; *c = 'l'; break; - case 192: *a = 'w'; *b = 'e'; *c = 'd'; break; - case 193: *a = 'd'; *b = 'u'; *c = 'c'; break; - case 194: *a = 'f'; *b = 'u'; *c = 'r'; break; - case 195: *a = 'f'; *b = 'e'; *c = 'x'; break; - case 196: *a = 'n'; *b = 'u'; *c = 'l'; break; - case 197: *a = 'l'; *b = 'u'; *c = 'c'; break; - case 198: *a = 'l'; *b = 'e'; *c = 'n'; break; - case 199: *a = 'n'; *b = 'e'; *c = 'r'; break; - case 200: *a = 'l'; *b = 'e'; *c = 'x'; break; - case 201: *a = 'r'; *b = 'u'; *c = 'p'; break; - case 202: *a = 'n'; *b = 'e'; *c = 'd'; break; - case 203: *a = 'l'; *b = 'e'; *c = 'c'; break; - case 204: *a = 'r'; *b = 'y'; *c = 'd'; break; - case 205: *a = 'l'; *b = 'y'; *c = 'd'; break; - case 206: *a = 'f'; *b = 'e'; *c = 'n'; break; - case 207: *a = 'w'; *b = 'e'; *c = 'l'; break; - case 208: *a = 'n'; *b = 'y'; *c = 'd'; break; - case 209: *a = 'h'; *b = 'u'; *c = 's'; break; - case 210: *a = 'r'; *b = 'e'; *c = 'l'; break; - case 211: *a = 'r'; *b = 'u'; *c = 'd'; break; - case 212: *a = 'n'; *b = 'e'; *c = 's'; break; - case 213: *a = 'h'; *b = 'e'; *c = 's'; break; - case 214: *a = 'f'; *b = 'e'; *c = 't'; break; - case 215: *a = 'd'; *b = 'e'; *c = 's'; break; - case 216: *a = 'r'; *b = 'e'; *c = 't'; break; - case 217: *a = 'd'; *b = 'u'; *c = 'n'; break; - case 218: *a = 'l'; *b = 'e'; *c = 'r'; break; - case 219: *a = 'n'; *b = 'y'; *c = 'r'; break; - case 220: *a = 's'; *b = 'e'; *c = 'b'; break; - case 221: *a = 'h'; *b = 'u'; *c = 'l'; break; - case 222: *a = 'r'; *b = 'y'; *c = 'l'; break; - case 223: *a = 'l'; *b = 'u'; *c = 'd'; break; - case 224: *a = 'r'; *b = 'e'; *c = 'm'; break; - case 225: *a = 'l'; *b = 'y'; *c = 's'; break; - case 226: *a = 'f'; *b = 'y'; *c = 'n'; break; - case 227: *a = 'w'; *b = 'e'; *c = 'r'; break; - case 228: *a = 'r'; *b = 'y'; *c = 'c'; break; - case 229: *a = 's'; *b = 'u'; *c = 'g'; break; - case 230: *a = 'n'; *b = 'y'; *c = 's'; break; - case 231: *a = 'n'; *b = 'y'; *c = 'l'; break; - case 232: *a = 'l'; *b = 'y'; *c = 'n'; break; - case 233: *a = 'd'; *b = 'y'; *c = 'n'; break; - case 234: *a = 'd'; *b = 'e'; *c = 'm'; break; - case 235: *a = 'l'; *b = 'u'; *c = 'x'; break; - case 236: *a = 'f'; *b = 'e'; *c = 'd'; break; - case 237: *a = 's'; *b = 'e'; *c = 'd'; break; - case 238: *a = 'b'; *b = 'e'; *c = 'c'; break; - case 239: *a = 'm'; *b = 'u'; *c = 'n'; break; - case 240: *a = 'l'; *b = 'y'; *c = 'r'; break; - case 241: *a = 't'; *b = 'e'; *c = 's'; break; - case 242: *a = 'm'; *b = 'u'; *c = 'd'; break; - case 243: *a = 'n'; *b = 'y'; *c = 't'; break; - case 244: *a = 'b'; *b = 'y'; *c = 'r'; break; - case 245: *a = 's'; *b = 'e'; *c = 'n'; break; - case 246: *a = 'w'; *b = 'e'; *c = 'g'; break; - case 247: *a = 'f'; *b = 'y'; *c = 'r'; break; - case 248: *a = 'm'; *b = 'u'; *c = 'r'; break; - case 249: *a = 't'; *b = 'e'; *c = 'l'; break; - case 250: *a = 'r'; *b = 'e'; *c = 'p'; break; - case 251: *a = 't'; *b = 'e'; *c = 'g'; break; - case 252: *a = 'p'; *b = 'e'; *c = 'c'; break; - case 253: *a = 'n'; *b = 'e'; *c = 'l'; break; - case 254: *a = 'n'; *b = 'e'; *c = 'v'; break; - case 255: *a = 'f'; *b = 'e'; *c = 's'; break; - default: u3m_bail(c3__exit); - } -} - -u3_noun -u3qc_po_ins(u3_noun a) -{ - c3_y byt_y[3]; - u3r_bytes(0, 3, byt_y, a); - - return u3_po_find_prefix(byt_y[0], byt_y[1], byt_y[2]); -} - -u3_noun -u3wcp_ins(u3_noun cor) -{ - u3_noun a; - u3x_mean(cor, u3x_sam, &a, 0); - - if ( c3n == u3ud(a) ) { - return u3m_bail(c3__fail); - } - - return u3qc_po_ins(a); -} - -u3_noun -u3qc_po_ind(u3_noun a) -{ - c3_y byt_y[3]; - u3r_bytes(0, 3, byt_y, a); - - return u3_po_find_suffix(byt_y[0], byt_y[1], byt_y[2]); -} - -u3_noun -u3wcp_ind(u3_noun cor) -{ - u3_noun a; - u3x_mean(cor, u3x_sam, &a, 0); - - if ( c3n == u3ud(a) ) { - return u3m_bail(c3__fail); - } - - return u3qc_po_ind(a); -} - -u3_noun -u3wcp_tos(u3_noun cor) -{ - u3_noun a; - - if ( (c3n == u3r_mean(cor, u3x_sam, &a, 0)) || - (c3n == u3ud(a)) || - (a >= 256) ) - { - return u3m_bail(c3__exit); - } - else { - c3_y byt_y[3]; - u3_po_to_prefix(a, &byt_y[0], &byt_y[1], &byt_y[2]); - return (byt_y[0] | (byt_y[1] << 8) | (byt_y[2] << 16)); - } -} - -u3_noun -u3wcp_tod(u3_noun cor) -{ - u3_noun a; - - if ( (c3n == u3r_mean(cor, u3x_sam, &a, 0)) || - (c3n == u3ud(a)) || - (a >= 256) ) - { - return u3m_bail(c3__exit); - } else { - c3_y byt_y[3]; - u3_po_to_suffix(a, &byt_y[0], &byt_y[1], &byt_y[2]); - return (byt_y[0] | (byt_y[1] << 8) | (byt_y[2] << 16)); - } -} diff --git a/pkg/urbit/jets/c/pow.c b/pkg/urbit/jets/c/pow.c deleted file mode 100644 index 541500f21..000000000 --- a/pkg/urbit/jets/c/pow.c +++ /dev/null @@ -1,38 +0,0 @@ -/* j/3/pow.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_pow(u3_atom a, - u3_atom b) - { - if ( !_(u3a_is_cat(b)) ) { - return u3m_bail(c3__fail); - } - else { - mpz_t a_mp; - - u3r_mp(a_mp, a); - mpz_pow_ui(a_mp, a_mp, b); - - return u3i_mp(a_mp); - } - } - u3_noun - u3wc_pow(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qc_pow(a, b); - } - } - diff --git a/pkg/urbit/jets/c/rap.c b/pkg/urbit/jets/c/rap.c deleted file mode 100644 index 6daf6555c..000000000 --- a/pkg/urbit/jets/c/rap.c +++ /dev/null @@ -1,88 +0,0 @@ -/* j/3/rap.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_rap(u3_atom a, - u3_noun b) - { - if ( !_(u3a_is_cat(a)) || (a >= 32) ) { - return u3m_bail(c3__fail); - } - else { - c3_g a_g = a; - c3_w tot_w = 0; - u3i_slab sab_u; - - /* Measure and validate the slab required. - */ - { - u3_noun cab = b; - - while ( 1 ) { - u3_noun h_cab; - c3_w len_w; - - if ( 0 == cab ) { - break; - } - else if ( c3n == u3du(cab) ) { - return u3m_bail(c3__exit); - } - else if ( c3n == u3ud(h_cab = u3h(cab)) ) { - return u3m_bail(c3__exit); - } - else if ( (tot_w + (len_w = u3r_met(a_g, h_cab))) < tot_w ) { - return u3m_bail(c3__fail); - } - tot_w += len_w; - cab = u3t(cab); - } - - if ( 0 == tot_w ) { - return 0; - } - - u3i_slab_init(&sab_u, a_g, tot_w); - } - - /* Chop the list atoms in. - */ - { - u3_noun cab = b; - c3_w pos_w = 0; - - while ( 0 != cab ) { - u3_noun h_cab = u3h(cab); - c3_w len_w = u3r_met(a_g, h_cab); - - u3r_chop(a_g, 0, len_w, pos_w, sab_u.buf_w, h_cab); - pos_w += len_w; - cab = u3t(cab); - } - } - - return u3i_slab_mint(&sab_u); - } - } - u3_noun - u3wc_rap(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) ) - { - return u3m_bail(c3__exit); - } else { - u3_noun pro; - - pro = u3qc_rap(a, b); - return pro; - } - } - diff --git a/pkg/urbit/jets/c/rep.c b/pkg/urbit/jets/c/rep.c deleted file mode 100644 index 14a959110..000000000 --- a/pkg/urbit/jets/c/rep.c +++ /dev/null @@ -1,196 +0,0 @@ -/* j/3/rep.c -** -*/ -#include "all.h" - -/* - Get the lowest `n` bits of a word `w` using a bitmask. -*/ -#define TAKEBITS(n,w) \ - ((n)==32) ? (w) : \ - ((n)==0) ? 0 : \ - ((w) & ((1 << (n)) - 1)) - -/* - Divide, rounding up. -*/ -#define DIVCEIL(x,y) \ - (x==0) ? 0 : \ - 1 + ((x - 1) / y); - -static u3_noun -_bit_rep(u3_atom bits, u3_noun blox) -{ - if ( (c3n == u3a_is_cat(bits) || bits==0 || bits>31) ) { - return u3m_bail(c3__fail); - } - - // - // Calculate input and output size. - // - c3_w num_blox_w = u3qb_lent(blox); - c3_w bit_widt_w = num_blox_w * bits; - c3_w wor_widt_w = DIVCEIL(bit_widt_w, 32); - u3i_slab sab_u; - u3i_slab_bare(&sab_u, 5, wor_widt_w); - - // - // Fill the atom buffer with bits from each block. - // - // Bits are pushed into the `acc_w` register and flushed to the buffer - // once full. - // - // acc_w register - // use_w number of register bits filled (used) - // cur_w next buffer word to flush into. - // - { - c3_w acc_w=0, use_w=0, *cur_w=sab_u.buf_w; - -# define FLUSH() *cur_w++=acc_w; acc_w=use_w=0 -# define SLICE(sz,off,val) TAKEBITS(sz, val) << off - - for (c3_w i=0; i> rem_in_acc_w; - FLUSH(); - } - } - } - - // - // If the last word isn't fully used, it will still need to be - // flushed. - // - if (use_w) { - FLUSH(); - } - } - - return u3i_slab_mint(&sab_u); -} - -static u3_noun -_block_rep(u3_atom a, - u3_noun b) -{ - if ( !_(u3a_is_cat(a)) || (a >= 32) ) { - return u3m_bail(c3__fail); - } - else { - c3_g a_g = a; - c3_w tot_w = 0; - u3i_slab sab_u; - - /* Measure and validate the slab required. - */ - { - u3_noun cab = b; - - while ( 1 ) { - u3_noun h_cab; - c3_w len_w; - - if ( 0 == cab ) { - break; - } - else if ( c3n == u3du(cab) ) { - return u3m_bail(c3__exit); - } - else if ( c3n == u3ud(h_cab = u3h(cab)) ) { - return u3m_bail(c3__exit); - } - else if ( (tot_w + (len_w = u3r_met(a_g, h_cab))) < tot_w ) { - return u3m_bail(c3__fail); - } - tot_w++; - cab = u3t(cab); - } - - if ( 0 == tot_w ) { - return 0; - } - - u3i_slab_init(&sab_u, a_g, tot_w); - } - - /* Chop the list atoms in. - */ - { - u3_noun cab = b; - c3_w pos_w = 0; - - while ( 0 != cab ) { - u3_noun h_cab = u3h(cab); - - u3r_chop(a_g, 0, 1, pos_w, sab_u.buf_w, h_cab); - pos_w++; - cab = u3t(cab); - } - } - - return u3i_slab_mint(&sab_u); - } -} - -u3_noun -u3qc_rep(u3_atom a, - u3_atom b, - u3_noun c) -{ - if ( 1 == b ) { - return _block_rep(a, c); - } - - if ( 0 == a ) { - return _bit_rep(b, c); - } - - u3l_log("rep: stub"); - return u3_none; -} - -u3_noun -u3wc_rep(u3_noun cor) -{ - u3_atom bloq, step; - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, - u3x_sam_3, &b, 0); - u3x_bite(a, &bloq, &step); - - return u3qc_rep(bloq, step, b); -} - -u3_noun -u3kc_rep(u3_atom a, - u3_atom b, - u3_noun c) -{ - u3_noun res = u3qc_rep(a, b, c); - u3z(a); u3z(b); u3z(c); - return res; -} diff --git a/pkg/urbit/jets/c/rev.c b/pkg/urbit/jets/c/rev.c deleted file mode 100644 index 73ece5baa..000000000 --- a/pkg/urbit/jets/c/rev.c +++ /dev/null @@ -1,50 +0,0 @@ -/* j/3/rev.c -** -*/ -#include "all.h" - -/* functions -*/ - - u3_noun - u3qc_rev(u3_atom boz, - u3_atom len, - u3_atom dat) - { - if ( !_(u3a_is_cat(boz)) || (boz >= 32) || - !_(u3a_is_cat(len)) ) { - return u3m_bail(c3__fail); - } - - dat = u3qc_end(boz, len, dat); - c3_w met = u3r_met(boz, dat); - return u3kc_lsh(boz, (len - met), u3kc_swp(boz, dat)); - } - - u3_noun - u3wc_rev(u3_noun cor) - { - u3_noun boz, len, dat; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &boz, - u3x_sam_6, &len, - u3x_sam_7, &dat, 0)) || - (c3n == u3ud(boz)) || - (c3n == u3ud(len)) || - (c3n == u3ud(dat)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qc_rev(boz, len, dat); - } - } - - u3_noun - u3kc_rev(u3_atom boz, - u3_atom len, - u3_atom dat) - { - u3_noun res = u3qc_rev(boz, len, dat); - u3z(boz); u3z(len); u3z(dat); - return res; - } diff --git a/pkg/urbit/jets/c/rip.c b/pkg/urbit/jets/c/rip.c deleted file mode 100644 index ea620c0f9..000000000 --- a/pkg/urbit/jets/c/rip.c +++ /dev/null @@ -1,186 +0,0 @@ -#include "all.h" - -/* - Get the lowest `n` bits of a word `w` using a bitmask. -*/ -#define TAKEBITS(n,w) \ - ((n)==32) ? (w) : \ - ((n)==0) ? 0 : \ - ((w) & ((1 << (n)) - 1)) - -/* - Divide, rounding up. -*/ -#define DIVCEIL(x,y) \ - (x==0) ? 0 : \ - 1 + ((x - 1) / y); - -/* - `ripn` breaks `atom` into a list of blocks, of bit-width `bits`. The - resulting list will be least-significant block first. - - XX TODO This only handles cases where the bit-width is <= 32. - - For each block we produce, we need to grab the relevant words inside - `atom`, so we first compute their indicies. - - `ins_idx` is the word-index of the least-significant word we - care about, and `sig_idx` is the word after that. - - Next we grab those words (`ins_word` and `sig_word`) from the atom - using `u3r_word`. Note that `sig_idx` might be out-of-bounds for the - underlying array of `atom`, but `u3r_word` returns 0 in that case, - which is exatly what we want. - - Now, we need to grab the relevant bits out of both words, and combine - them. `bits_rem_in_ins_word` is the number of remaining (insignificant) - bits in `ins_word`, `nbits_ins` is the number of bits we want from the - less-significant word, and `nbits_sig` from the more-significant one. - - Take the least significant `nbits_sig` bits from `sig_word`, and take - the slice we care about from `ins_word`. In order to take that slice, - we drop `bits_rem_in_ins_word` insignificant bits, and then take the - `nbits_sig` most-significant bits. - - Last, we slice out those bits from the two words, combine them into - one word, and cons them onto the front of the result. -*/ -static u3_noun -_bit_rip(u3_atom bits, u3_atom atom) -{ - if ( !_(u3a_is_cat(bits) || bits==0 || bits>31) ) { - return u3m_bail(c3__fail); - } - - c3_w bit_width = u3r_met(0, atom); - c3_w num_blocks = DIVCEIL(bit_width, bits); - - u3_noun res = u3_nul; - - for ( c3_w blk = 0; blk < num_blocks; blk++ ) { - c3_w next_blk = blk + 1; - c3_w blks_rem = num_blocks - next_blk; - c3_w bits_rem = blks_rem * bits; - c3_w ins_idx = bits_rem / 32; - c3_w sig_idx = ins_idx + 1; - - c3_w bits_rem_in_ins_word = bits_rem % 32; - - c3_w ins_word = u3r_word(ins_idx, atom); - c3_w sig_word = u3r_word(sig_idx, atom); - c3_w nbits_ins = c3_min(bits, 32 - bits_rem_in_ins_word); - c3_w nbits_sig = bits - nbits_ins; - - c3_w ins_word_bits = TAKEBITS(nbits_ins, ins_word >> bits_rem_in_ins_word); - c3_w sig_word_bits = TAKEBITS(nbits_sig, sig_word); - - c3_w item = ins_word_bits | (sig_word_bits << nbits_ins); - - res = u3nc(item, res); - } - - return res; -} - -static u3_noun -_block_rip(u3_atom bloq, u3_atom b) -{ - if ( !_(u3a_is_cat(bloq)) || (bloq >= 32) ) { - return u3m_bail(c3__fail); - } - - c3_g bloq_g = bloq; - - /* - This is a fast-path for the case where all the resulting blocks will - fit in 31-bit direct atoms. - */ - if ( bloq_g < 5 ) { // produce direct atoms - u3_noun acc = u3_nul; - - c3_w met_w = u3r_met(bloq_g, b); // num blocks in atom - c3_w nbits_w = 1 << bloq_g; // block size in bits - c3_w bmask_w = (1 << nbits_w) - 1; // result mask - - for ( c3_w i_w = 0; i_w < met_w; i_w++ ) { // `i_w` is block index - c3_w nex_w = i_w + 1; // next block - c3_w pat_w = met_w - nex_w; // blks left after this - c3_w bit_w = pat_w << bloq_g; // bits left after this - c3_w wor_w = bit_w >> 5; // wrds left after this - c3_w sif_w = bit_w & 31; // bits left in word - c3_w src_w = u3r_word(wor_w, b); // find word by index - c3_w rip_w = (src_w >> sif_w) & bmask_w; // get item from word - - acc = u3nc(rip_w, acc); - } - - return acc; - } - - u3_noun acc = u3_nul; - c3_w met_w = u3r_met(bloq_g, b); - c3_w len_w = u3r_met(5, b); - c3_g san_g = (bloq_g - 5); - c3_w san_w = 1 << san_g; - c3_w dif_w = (met_w << san_g) - len_w; - c3_w tub_w = ((dif_w == 0) ? san_w : (san_w - dif_w)); - - for ( c3_w i_w = 0; i_w < met_w; i_w++ ) { - c3_w pat_w = (met_w - (i_w + 1)); - c3_w wut_w = (pat_w << san_g); - c3_w sap_w = ((0 == i_w) ? tub_w : san_w); - c3_w j_w; - u3_atom rip; - u3i_slab sab_u; - u3i_slab_bare(&sab_u, 5, sap_w); - - for ( j_w = 0; j_w < sap_w; j_w++ ) { - sab_u.buf_w[j_w] = u3r_word(wut_w + j_w, b); - } - - rip = u3i_slab_mint(&sab_u); - acc = u3nc(rip, acc); - len_w -= san_w; - } - - return acc; -} - -u3_noun -u3qc_rip(u3_atom a, - u3_atom b, - u3_atom c) -{ - if ( 1 == b ) { - return _block_rip(a, c); - } - - if ( 0 == a ) { - return _bit_rip(b, c); - } - - u3l_log("rip: stub"); - return u3_none; -} - -u3_noun -u3wc_rip(u3_noun cor) -{ - u3_atom bloq, step; - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, - u3x_sam_3, &b, 0); - u3x_bite(a, &bloq, &step); - - return u3qc_rip(bloq, step, u3x_atom(b)); -} - -u3_noun -u3kc_rip(u3_atom a, - u3_atom b, - u3_atom c) -{ - u3_noun pro = u3qc_rip(a, b, c); - u3z(a); u3z(b); u3z(c); - return pro; -} diff --git a/pkg/urbit/jets/c/rsh.c b/pkg/urbit/jets/c/rsh.c deleted file mode 100644 index 4922e0c58..000000000 --- a/pkg/urbit/jets/c/rsh.c +++ /dev/null @@ -1,57 +0,0 @@ -/* j/3/rsh.c -** -*/ -#include "all.h" - -u3_noun -u3qc_rsh(u3_atom a, - u3_atom b, - u3_atom c) -{ - if ( !_(u3a_is_cat(a)) || (a >= 32) ) { - return u3m_bail(c3__fail); - } - else if ( !_(u3a_is_cat(b)) ) { - return 0; - } - else { - c3_g a_g = a; - c3_w b_w = b; - c3_w len_w = u3r_met(a_g, c); - - if ( b_w >= len_w ) { - return 0; - } - else { - u3i_slab sab_u; - u3i_slab_init(&sab_u, a_g, (len_w - b_w)); - - u3r_chop(a_g, b_w, (len_w - b_w), 0, sab_u.buf_w, c); - - return u3i_slab_mint(&sab_u); - } - } -} - -u3_noun -u3wc_rsh(u3_noun cor) -{ - u3_atom bloq, step; - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, - u3x_sam_3, &b, 0); - u3x_bite(a, &bloq, &step); - - return u3qc_rsh(bloq, step, u3x_atom(b)); -} - -u3_noun -u3kc_rsh(u3_noun a, - u3_noun b, - u3_noun c) -{ - u3_noun d = u3qc_rsh(a, b, c); - - u3z(a); u3z(b); u3z(c); - return d; -} diff --git a/pkg/urbit/jets/c/sqt.c b/pkg/urbit/jets/c/sqt.c deleted file mode 100644 index 160967d60..000000000 --- a/pkg/urbit/jets/c/sqt.c +++ /dev/null @@ -1,33 +0,0 @@ -/* j/3/sqt.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_sqt(u3_atom a) - { - mpz_t a_mp, b_mp; - - u3r_mp(a_mp, a); - mpz_init(b_mp); - mpz_sqrtrem(a_mp, b_mp, a_mp); - - return u3nc(u3i_mp(a_mp), u3i_mp(b_mp)); - } - u3_noun - u3wc_sqt(u3_noun cor) - { - u3_noun a; - - if ( (u3_none == (a = u3r_at(u3x_sam, cor))) || - (c3n == u3ud(a)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qc_sqt(a); - } - } - diff --git a/pkg/urbit/jets/c/swp.c b/pkg/urbit/jets/c/swp.c deleted file mode 100644 index 9f7a68c9a..000000000 --- a/pkg/urbit/jets/c/swp.c +++ /dev/null @@ -1,37 +0,0 @@ -/* j/3/swp.c -** -*/ -#include "all.h" - -u3_noun -u3qc_swp(u3_atom a, - u3_atom b) -{ - //XX write a proper c-style swp, maybe - // - return u3kc_rep(u3k(a), 1, u3kb_flop(u3qc_rip(a, 1, b))); -} - -u3_noun -u3wc_swp(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); - - if ( (c3n == u3ud(a)) - || (c3n == u3ud(b)) ) - { - return u3m_bail(c3__exit); - } - - return u3qc_swp(a, b); - } - -u3_noun -u3kc_swp(u3_atom a, - u3_atom b) -{ - u3_noun pro = u3qc_swp(a, b); - u3z(a); u3z(b); - return pro; -} diff --git a/pkg/urbit/jets/c/xeb.c b/pkg/urbit/jets/c/xeb.c deleted file mode 100644 index f0a191fcb..000000000 --- a/pkg/urbit/jets/c/xeb.c +++ /dev/null @@ -1,32 +0,0 @@ -/* j/3/xeb.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qc_xeb(u3_atom a) - { - c3_w met_w = u3r_met(0, a); - - if ( !_(u3a_is_cat(met_w)) ) { - return u3i_words(1, &met_w); - } - else return met_w; - } - u3_noun - u3wc_xeb(u3_noun cor) - { - u3_noun a; - - if ( (u3_none == (a = u3r_at(u3x_sam, cor))) || - (c3n == u3ud(a)) ) - { - return u3m_bail(c3__exit); - } else { - return u3qc_xeb(a); - } - } - diff --git a/pkg/urbit/jets/d/by_all.c b/pkg/urbit/jets/d/by_all.c deleted file mode 100644 index 2a800f5d9..000000000 --- a/pkg/urbit/jets/d/by_all.c +++ /dev/null @@ -1,49 +0,0 @@ -/* j/4/by_all.c -** -*/ -#include "all.h" - -static u3_noun -_by_all(u3_noun a, u3j_site* sit_u) -{ - if ( u3_nul == a ) { - return c3y; - } - else { - u3_noun n_a, l_a, r_a; - u3x_trel(a, &n_a, &l_a, &r_a); - - switch ( u3j_gate_slam(sit_u, u3k(u3t(n_a))) ) { - case c3y: break; - case c3n: return c3n; - default: return u3m_bail(c3__exit); - } - - if ( c3n == _by_all(l_a, sit_u) ) { - return c3n; - } - - return _by_all(r_a, sit_u); - } -} - -u3_noun -u3qdb_all(u3_noun a, u3_noun b) -{ - u3_noun pro; - u3j_site sit_u; - - u3j_gate_prep(&sit_u, u3k(b)); - pro = _by_all(a, &sit_u); - u3j_gate_lose(&sit_u); - - return pro; -} - -u3_noun -u3wdb_all(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdb_all(a, b); -} diff --git a/pkg/urbit/jets/d/by_any.c b/pkg/urbit/jets/d/by_any.c deleted file mode 100644 index 047eb505c..000000000 --- a/pkg/urbit/jets/d/by_any.c +++ /dev/null @@ -1,49 +0,0 @@ -/* j/4/by_any.c -** -*/ -#include "all.h" - -static u3_noun -_by_any(u3_noun a, u3j_site* sit_u) -{ - if ( u3_nul == a ) { - return c3n; - } - else { - u3_noun n_a, l_a, r_a; - u3x_trel(a, &n_a, &l_a, &r_a); - - switch ( u3j_gate_slam(sit_u, u3k(u3t(n_a))) ) { - case c3y: return c3y; - case c3n: break; - default: return u3m_bail(c3__exit); - } - - if ( c3y == _by_any(l_a, sit_u) ) { - return c3y; - } - - return _by_any(r_a, sit_u); - } -} - -u3_noun -u3qdb_any(u3_noun a, u3_noun b) -{ - u3_noun pro; - u3j_site sit_u; - - u3j_gate_prep(&sit_u, u3k(b)); - pro = _by_any(a, &sit_u); - u3j_gate_lose(&sit_u); - - return pro; -} - -u3_noun -u3wdb_any(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdb_any(a, b); -} diff --git a/pkg/urbit/jets/d/by_apt.c b/pkg/urbit/jets/d/by_apt.c deleted file mode 100644 index e85bc7f9c..000000000 --- a/pkg/urbit/jets/d/by_apt.c +++ /dev/null @@ -1,76 +0,0 @@ -/* j/4/by_apt.c -** -*/ -#include "all.h" - -static c3_o -_by_apt(u3_noun a, u3_weak l, u3_weak r) -{ - if ( u3_nul == a ) { - return c3y; - } - else { - u3_noun p_n_a, l_a, r_a; - { - u3_noun n_a; - u3x_trel(a, &n_a, &l_a, &r_a); - p_n_a = u3h(n_a); - } - - if ( u3_none != l ) { - if ( (c3n == u3qc_gor(p_n_a, l)) - || (c3y == u3r_sing(p_n_a, l)) ) - { - return c3n; - } - } - - if ( u3_none != r ) { - if ( (c3n == u3qc_gor(r, p_n_a)) - || (c3y == u3r_sing(r, p_n_a)) ) - { - return c3n; - } - } - - if ( u3_nul != l_a ) { - u3_noun p_n_l_a = u3h(u3h(l_a)); - - if ( (c3n == u3qc_mor(p_n_a, p_n_l_a)) - || (c3y == u3r_sing(p_n_a, p_n_l_a)) ) - { - return c3n; - } - - if ( c3n == _by_apt(l_a, p_n_a, r) ) { - return c3n; - } - } - - if ( u3_nul != r_a ) { - u3_noun p_n_r_a = u3h(u3h(r_a)); - - if ( (c3n == u3qc_mor(p_n_a, p_n_r_a)) - || (c3y == u3r_sing(p_n_a, p_n_r_a)) ) - { - return c3n; - } - - return _by_apt(r_a, l, p_n_a); - } - - return c3y; - } -} - -u3_noun -u3qdb_apt(u3_noun a) -{ - return _by_apt(a, u3_none, u3_none); -} - -u3_noun -u3wdb_apt(u3_noun cor) -{ - return u3qdb_apt(u3x_at(u3x_con_sam, cor)); -} diff --git a/pkg/urbit/jets/d/by_bif.c b/pkg/urbit/jets/d/by_bif.c deleted file mode 100644 index 0edd9f8b1..000000000 --- a/pkg/urbit/jets/d/by_bif.c +++ /dev/null @@ -1,76 +0,0 @@ -/* jets/d/by_bif.c -** -*/ -#include "all.h" - -/* internal functions -*/ -static u3_noun -_b_bif_putroot(u3_noun a, - u3_noun b) -{ - if ( u3_nul == a ) { - return u3nt(u3k(b), u3_nul, u3_nul); - } - else { - u3_noun n_a, l_a, r_a; - u3_noun p_n_a, q_n_a; - u3_noun p_b, q_b; - u3x_trel(a, &n_a, &l_a, &r_a); - u3x_cell(b, &p_b, &q_b); - u3x_cell(n_a, &p_n_a, &q_n_a); - - if ( c3y == u3r_sing(p_b, p_n_a) ) { - return u3nt(u3k(b), u3k(l_a), u3k(r_a)); - } - else { - u3_noun c, n_c, l_c, r_c; - u3_noun d; - - if ( c3y == u3qc_gor(p_b, p_n_a) ) { - c = _b_bif_putroot(l_a, b); - u3r_trel(c, &n_c, &l_c, &r_c); - d = u3nt(u3k(n_c), - u3k(l_c), - u3nt(u3k(n_a), u3k(r_c), u3k(r_a)) - ); - u3z(c); - return d; - } - else { - c = _b_bif_putroot(r_a, b); - u3r_trel(c, &n_c, &l_c, &r_c); - d = u3nt(u3k(n_c), - u3nt(u3k(n_a), u3k(l_a), u3k(l_c)), - u3k(r_c) - ); - u3z(c); - return d; - } - } - } -} - -/* functions -*/ -u3_noun -u3wdb_bif(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdb_bif(a, b); -} - -u3_noun -u3qdb_bif(u3_noun a, - u3_noun b) -{ - u3_noun c, n_c, l_c, r_c; - u3_noun d; - - c = _b_bif_putroot(a, b); - u3r_trel(c, &n_c, &l_c, &r_c); - d = u3nc(u3k(l_c), u3k(r_c)); - u3z(c); - return d; -} diff --git a/pkg/urbit/jets/d/by_del.c b/pkg/urbit/jets/d/by_del.c deleted file mode 100644 index 1dc719c0a..000000000 --- a/pkg/urbit/jets/d/by_del.c +++ /dev/null @@ -1,93 +0,0 @@ -/* j/4/by_del.c -** -*/ -#include "all.h" - -/* functions -*/ -static u3_noun -_rebalance(u3_noun a) -{ - u3_noun n_a, l_a, r_a; - u3x_trel(a, &n_a, &l_a, &r_a); - - if ( u3_nul == l_a) { - return u3k(r_a); - } - else if ( u3_nul == r_a) { - return u3k(l_a); - } - else { - u3_noun n_l_a, l_l_a, r_l_a; - u3_noun n_r_a, l_r_a, r_r_a; - u3x_trel(l_a, &n_l_a, &l_l_a, &r_l_a); - u3x_trel(r_a, &n_r_a, &l_r_a, &r_r_a); - - if ( c3y == u3qc_mor(u3h(n_l_a), u3h(n_r_a)) ) { - u3_noun new_right = u3nt(u3k(n_a), - u3k(r_l_a), - u3k(r_a)); - - u3_noun ret = u3nt(u3k(n_l_a), - u3k(l_l_a), - _rebalance(new_right)); - u3z(new_right); - - return ret; - } - else { - u3_noun new_left = u3nt(u3k(n_a), - u3k(l_a), - u3k(l_r_a)); - - u3_noun ret = u3nt(u3k(n_r_a), - _rebalance(new_left), - u3k(r_r_a)); - u3z(new_left); - - return ret; - } - } -} - -u3_noun -u3qdb_del(u3_noun a, - u3_noun b) -{ - if ( u3_nul == a ) { - return u3_nul; - } - else { - u3_noun n_a, lr_a; - u3_noun pn_a; - u3x_cell(a, &n_a, &lr_a); - u3x_cell(n_a, &pn_a, 0); - - if ( c3y == u3r_sing(pn_a, b) ) { - return _rebalance(a); - } - else { - u3_noun l_a, r_a; - u3x_cell(lr_a, &l_a, &r_a); - - if ( c3y == u3qc_gor(b, pn_a) ) { - return u3nt(u3k(n_a), - u3qdb_del(l_a, b), - u3k(r_a)); - } - else { - return u3nt(u3k(n_a), - u3k(l_a), - u3qdb_del(r_a, b)); - } - } - } -} - -u3_noun -u3wdb_del(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdb_del(a, b); -} diff --git a/pkg/urbit/jets/d/by_dif.c b/pkg/urbit/jets/d/by_dif.c deleted file mode 100644 index 69b6413e8..000000000 --- a/pkg/urbit/jets/d/by_dif.c +++ /dev/null @@ -1,82 +0,0 @@ -/* jets/d/by_dif.c -** -*/ -#include "all.h" - -/* internal functions -*/ - -/* RETAIN -*/ -static u3_noun -_b_dif_join(u3_noun d, - u3_noun e) -{ - if ( u3_nul == d ) { - return u3k(e); - } - else if ( u3_nul == e ) { - return u3k(d); - } - else { - u3_noun n_d, lr_d; - u3_noun n_e, lr_e; - u3x_cell(d, &n_d, &lr_d); - u3x_cell(e, &n_e, &lr_e); - - if ( c3y == u3qc_mor(u3h(n_d), u3h(n_e)) ) { - u3_noun l_d, r_d; - u3x_cell(lr_d, &l_d, &r_d); - - return u3nt(u3k(n_d), - u3k(l_d), - _b_dif_join(r_d, e)); - } - else { - u3_noun l_e, r_e; - u3x_cell(lr_e, &l_e, &r_e); - - return u3nt(u3k(n_e), - _b_dif_join(d, l_e), - u3k(r_e)); - } - } -} - -/* functions -*/ -u3_noun -u3wdb_dif(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdb_dif(a, b); -} - -u3_noun -u3qdb_dif(u3_noun a, - u3_noun b) -{ - if ( u3_nul == b ) { - return u3k(a); - } - else { - u3_noun n_b, l_b, r_b; - u3_noun c, l_c, r_c; - u3x_trel(b, &n_b, &l_b, &r_b); - - c = u3qdb_bif(a, n_b); - u3x_cell(c, &l_c, &r_c); - - u3_noun d = u3qdb_dif(l_c, l_b); - u3_noun e = u3qdb_dif(r_c, r_b); - - u3z(c); - - u3_noun pro = _b_dif_join(d, e); - u3z(d); - u3z(e); - - return pro; - } -} diff --git a/pkg/urbit/jets/d/by_gas.c b/pkg/urbit/jets/d/by_gas.c deleted file mode 100644 index e14c9833c..000000000 --- a/pkg/urbit/jets/d/by_gas.c +++ /dev/null @@ -1,43 +0,0 @@ -/* j/4/gas.c -** -*/ -#include "all.h" - -/* functions -*/ -u3_noun -u3qdb_gas(u3_noun a, - u3_noun b) -{ - if ( u3_nul == b ) { - return u3k(a); - } - else { - u3_noun i_b, t_b, - pi_b, qi_b; - u3x_cell(b, &i_b, &t_b); - u3x_cell(i_b, &pi_b, &qi_b); - - u3_noun c = u3qdb_put(a, pi_b, qi_b); - u3_noun d = u3qdb_gas(c, t_b); - u3z(c); - return d; - } -} - -u3_noun -u3wdb_gas(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdb_gas(a, b); -} - -u3_noun -u3kdb_gas(u3_noun a, - u3_noun b) -{ - u3_noun c = u3qdb_gas(a, b); - u3z(a); u3z(b); - return c; -} diff --git a/pkg/urbit/jets/d/by_get.c b/pkg/urbit/jets/d/by_get.c deleted file mode 100644 index cecd15d67..000000000 --- a/pkg/urbit/jets/d/by_get.c +++ /dev/null @@ -1,62 +0,0 @@ -/* j/4/by_get.c -** -*/ -#include "all.h" - -/* functions -*/ -u3_noun -u3qdb_get(u3_noun a, - u3_noun b) -{ - if ( u3_nul == a ) { - return u3_nul; - } - else { - u3_noun n_a, lr_a; - u3_noun pn_a, qn_a; - u3x_cell(a, &n_a, &lr_a); - u3x_cell(n_a, &pn_a, &qn_a); - - if ( (c3y == u3r_sing(b, pn_a)) ) { - return u3nc(u3_nul, u3k(qn_a)); - } - else { - return ( c3y == u3qc_gor(b, pn_a) ) ? u3qdb_get(u3h(lr_a), b) - : u3qdb_get(u3t(lr_a), b); - } - } -} - -u3_noun -u3wdb_get(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdb_get(a, b); -} - -u3_weak -u3kdb_get(u3_noun a, - u3_noun b) -{ - u3_noun c = u3qdb_get(a, b); - u3z(a); u3z(b); - - if ( c3n == u3r_du(c) ) { - u3z(c); - return u3_none; - } - else { - u3_noun pro = u3k(u3t(c)); - u3z(c); - return pro; - } -} - -u3_noun -u3kdb_got(u3_noun a, - u3_noun b) -{ - return u3x_good(u3kdb_get(a, b)); -} diff --git a/pkg/urbit/jets/d/by_has.c b/pkg/urbit/jets/d/by_has.c deleted file mode 100644 index 702c38931..000000000 --- a/pkg/urbit/jets/d/by_has.c +++ /dev/null @@ -1,46 +0,0 @@ -/* j/4/by_has.c -** -*/ -#include "all.h" - -/* functions -*/ -u3_noun -u3qdb_has(u3_noun a, - u3_noun b) -{ - if ( u3_nul == a ) { - return c3n; - } - else { - u3_noun n_a, lr_a; - u3_noun pn_a; - u3x_cell(a, &n_a, &lr_a); - u3x_cell(n_a, &pn_a, 0); - - if ( (c3y == u3r_sing(b, pn_a)) ) { - return c3y; - } - else { - return ( c3y == u3qc_gor(b, pn_a) ) ? u3qdb_has(u3h(lr_a), b) - : u3qdb_has(u3t(lr_a), b); - } - } -} - -u3_noun -u3wdb_has(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdb_has(a, b); -} - -u3_noun -u3kdb_has(u3_noun a, - u3_noun b) -{ - u3_noun c = u3qdb_has(a, b); - u3z(a); u3z(b); - return c; -} diff --git a/pkg/urbit/jets/d/by_int.c b/pkg/urbit/jets/d/by_int.c deleted file mode 100644 index f5eb59a15..000000000 --- a/pkg/urbit/jets/d/by_int.c +++ /dev/null @@ -1,69 +0,0 @@ -/* j/4/by_int.c -** -*/ -#include "all.h" - -u3_noun -u3qdb_int(u3_noun a, u3_noun b) -{ - if ( (u3_nul == a) - || (u3_nul == b) ) - { - return u3_nul; - } - else { - u3_noun n_a, l_a, r_a; - u3_noun n_b, l_b, r_b; - u3_noun p_n_a, q_n_a; - u3_noun p_n_b, q_n_b; - u3x_trel(a, &n_a, &l_a, &r_a); - u3x_trel(b, &n_b, &l_b, &r_b); - u3x_cell(n_a, &p_n_a, &q_n_a); - u3x_cell(n_b, &p_n_b, &q_n_b); - - if ( c3y == u3qc_mor(p_n_a, p_n_b) ) { - if ( c3y == u3r_sing(p_n_b, p_n_a) ) { - return u3nt(u3k(n_b), u3qdb_int(l_a, l_b), u3qdb_int(r_a, r_b)); - } - else if ( c3y == u3qc_gor(p_n_b, p_n_a) ) { - u3_noun new_l_b = u3nt(u3k(n_b), u3k(l_b), u3_nul); - u3_noun new_a = u3qdb_int(l_a, new_l_b); - - u3z(new_l_b); - return u3kdb_uni(new_a, u3qdb_int(a, r_b)); - } - else { - u3_noun new_r_b = u3nt(u3k(n_b), u3_nul, u3k(r_b)); - u3_noun new_a = u3qdb_int(r_a, new_r_b); - - u3z(new_r_b); - return u3kdb_uni(new_a, u3qdb_int(a, l_b)); - } - } - else if ( c3y == u3r_sing(p_n_a, p_n_b) ) { - return u3nt(u3k(n_b), u3qdb_int(l_a, l_b), u3qdb_int(r_a, r_b)); - } - else if ( c3y == u3qc_gor(p_n_a, p_n_b) ) { - u3_noun new_l_a = u3nt(u3k(n_a), u3k(l_a), u3_nul); - u3_noun new_a = u3qdb_int(new_l_a, l_b); - - u3z(new_l_a); - return u3kdb_uni(new_a, u3qdb_int(r_a, b)); - } - else { - u3_noun new_r_a = u3nt(u3k(n_a), u3_nul, u3k(r_a)); - u3_noun new_a = u3qdb_int(new_r_a, r_b); - - u3z(new_r_a); - return u3kdb_uni(new_a, u3qdb_int(l_a, b)); - } - } -} - -u3_noun -u3wdb_int(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdb_int(a, b); -} diff --git a/pkg/urbit/jets/d/by_jab.c b/pkg/urbit/jets/d/by_jab.c deleted file mode 100644 index 7b926d35a..000000000 --- a/pkg/urbit/jets/d/by_jab.c +++ /dev/null @@ -1,46 +0,0 @@ -/* j/4/by_jab.c -** -*/ -#include "all.h" - -/* functions -*/ -u3_noun -u3qdb_jab(u3_noun a, - u3_noun key, - u3_noun fun) -{ - if ( u3_nul == a ) { - return u3m_bail(c3__exit); - } - else { - u3_noun n_a, lr_a; - u3_noun pn_a, qn_a; - u3x_cell(a, &n_a, &lr_a); - u3x_cell(n_a, &pn_a, &qn_a); - - if ( (c3y == u3r_sing(key, pn_a)) ) { - u3_noun value = u3n_slam_on(u3k(fun), u3k(qn_a)); - return u3nc(u3nc(u3k(pn_a), value), u3k(u3t(a))); - } - else { - u3_noun l_a, r_a; - u3x_cell(lr_a, &l_a, &r_a); - - return ( c3y == u3qc_gor(key, pn_a) ) - ? u3nt(u3k(n_a), u3qdb_jab(l_a, key, fun), u3k(r_a)) - : u3nt(u3k(n_a), u3k(l_a), u3qdb_jab(r_a, key, fun)); - } - } -} - -u3_noun -u3wdb_jab(u3_noun cor) -{ - u3_noun a, key, fun; - u3x_mean(cor, u3x_sam_2, &key, - u3x_sam_3, &fun, - u3x_con_sam, &a, 0); - - return u3qdb_jab(a, key, fun); -} diff --git a/pkg/urbit/jets/d/by_key.c b/pkg/urbit/jets/d/by_key.c deleted file mode 100644 index e194d71c5..000000000 --- a/pkg/urbit/jets/d/by_key.c +++ /dev/null @@ -1,40 +0,0 @@ -/* j/4/by_run.c -** -*/ -#include "all.h" - -// [a] is RETAINED, [set] is TRANSFERRED -// -static u3_noun -_by_key(u3_noun a, u3_noun set) -{ - if ( u3_nul == a ) { - return set; - } - else { - u3_noun n_a, l_a, r_a; - u3x_trel(a, &n_a, &l_a, &r_a); - - { - u3_noun new = u3qdi_put(set, u3h(n_a)); - u3z(set); - set = new; - } - - set = _by_key(l_a, set); - - return _by_key(r_a, set); - } -} - -u3_noun -u3qdb_key(u3_noun a) -{ - return _by_key(a, u3_nul); -} - -u3_noun -u3wdb_key(u3_noun cor) -{ - return u3qdb_key(u3x_at(u3x_con_sam, cor)); -} diff --git a/pkg/urbit/jets/d/by_put.c b/pkg/urbit/jets/d/by_put.c deleted file mode 100644 index 3734c8adf..000000000 --- a/pkg/urbit/jets/d/by_put.c +++ /dev/null @@ -1,101 +0,0 @@ -/* j/4/put.c -** -*/ -#include "all.h" - -/* functions -*/ -u3_noun -u3qdb_put(u3_noun a, - u3_noun b, - u3_noun c) -{ - if ( u3_nul == a ) { - return u3nt(u3nc(u3k(b), u3k(c)), - u3_nul, - u3_nul); - } - else { - u3_noun n_a, l_a, r_a; - u3_noun pn_a, qn_a; - u3x_trel(a, &n_a, &l_a, &r_a); - u3x_cell(n_a, &pn_a, &qn_a); - - if ( c3y == u3r_sing(pn_a, b) ) { - if ( c3y == u3r_sing(qn_a, c) ) { - return u3k(a); - } - else { - return u3nt(u3nc(u3k(b), u3k(c)), - u3k(l_a), - u3k(r_a)); - } - } - else { - u3_noun d, n_d, l_d, r_d; - - if ( c3y == u3qc_gor(b, pn_a) ) { - d = u3qdb_put(l_a, b, c); - - if ( c3y == u3qc_mor(pn_a, u3h(u3h(d))) ) { - return u3nt(u3k(n_a), - d, - u3k(r_a)); - } - else { - u3r_trel(d, &n_d, &l_d, &r_d); - - u3_noun e = u3nt(u3k(n_d), - u3k(l_d), - u3nt(u3k(n_a), - u3k(r_d), - u3k(r_a))); - - u3z(d); - return e; - } - } - else { - d = u3qdb_put(r_a, b, c); - - if ( c3y == u3qc_mor(pn_a, u3h(u3h(d))) ) { - return u3nt(u3k(n_a), - u3k(l_a), - d); - } - else { - u3r_trel(d, &n_d, &l_d, &r_d); - - u3_noun e = u3nt(u3k(n_d), - u3nt(u3k(n_a), - u3k(l_a), - u3k(l_d)), - u3k(r_d)); - - u3z(d); - return e; - } - } - } - } -} - -u3_noun -u3wdb_put(u3_noun cor) -{ - u3_noun a, b, c; - u3x_mean(cor, u3x_sam_2, &b, - u3x_sam_3, &c, - u3x_con_sam, &a, 0); - return u3qdb_put(a, b, c); -} - -u3_noun -u3kdb_put(u3_noun a, - u3_noun b, - u3_noun c) -{ - u3_noun pro = u3qdb_put(a, b, c); - u3z(a); u3z(b); u3z(c); - return pro; -} diff --git a/pkg/urbit/jets/d/by_run.c b/pkg/urbit/jets/d/by_run.c deleted file mode 100644 index f2710e7fb..000000000 --- a/pkg/urbit/jets/d/by_run.c +++ /dev/null @@ -1,43 +0,0 @@ -/* j/4/by_run.c -** -*/ -#include "all.h" - -static u3_noun -_by_run(u3_noun a, u3j_site* sit_u) -{ - if ( u3_nul == a ) { - return u3_nul; - } - else { - u3_noun n_a, l_a, r_a; - u3_noun p_n_a, q_n_a; - u3x_trel(a, &n_a, &l_a, &r_a); - u3x_cell(n_a, &p_n_a, &q_n_a); - - return u3nt(u3nc(u3k(p_n_a), u3j_gate_slam(sit_u, u3k(q_n_a))), - _by_run(l_a, sit_u), - _by_run(r_a, sit_u)); - } -} - -u3_noun -u3qdb_run(u3_noun a, u3_noun b) -{ - u3_noun pro; - u3j_site sit_u; - - u3j_gate_prep(&sit_u, u3k(b)); - pro = _by_run(a, &sit_u); - u3j_gate_lose(&sit_u); - - return pro; -} - -u3_noun -u3wdb_run(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdb_run(a, b); -} diff --git a/pkg/urbit/jets/d/by_uni.c b/pkg/urbit/jets/d/by_uni.c deleted file mode 100644 index 49761b390..000000000 --- a/pkg/urbit/jets/d/by_uni.c +++ /dev/null @@ -1,98 +0,0 @@ -/* j/4/by_uni.c - */ -#include "all.h" - -u3_noun -u3qdb_uni(u3_noun a, u3_noun b) -{ - if ( u3_nul == b ) { - return u3k(a); - } - else if ( u3_nul == a ) { - return u3k(b); - } - else { - u3_noun n_a, l_a, r_a; - u3_noun n_b, l_b, r_b; - u3_noun p_n_a, q_n_a; - u3_noun p_n_b, q_n_b; - u3x_trel(a, &n_a, &l_a, &r_a); - u3x_trel(b, &n_b, &l_b, &r_b); - u3x_cell(n_a, &p_n_a, &q_n_a); - u3x_cell(n_b, &p_n_b, &q_n_b); - - if ( c3y == u3r_sing(p_n_a, p_n_b) ) { - return u3nt(u3k(n_b), - u3qdb_uni(l_a, l_b), - u3qdb_uni(r_a, r_b)); - } - else if ( c3y == u3qc_mor(p_n_a, p_n_b) ) { - u3_noun new_a, old_b; - - if ( c3y == u3qc_gor(p_n_b, p_n_a) ) { - u3_noun new_b = u3nt(u3k(n_b), u3k(l_b), u3_nul); - u3_noun new_la = u3qdb_uni(l_a, new_b); - u3z(new_b); - - new_a = u3nt(u3k(n_a), new_la, u3k(r_a)); - old_b = r_b; - } - else { - u3_noun new_b = u3nt(u3k(n_b), u3_nul, u3k(r_b)); - u3_noun new_ra = u3qdb_uni(r_a, new_b); - u3z(new_b); - - new_a = u3nt(u3k(n_a), u3k(l_a), new_ra); - old_b = l_b; - } - - { - u3_noun pro = u3qdb_uni(new_a, old_b); - u3z(new_a); - return pro; - } - } - else { - u3_noun old_a, new_b; - - if ( c3y == u3qc_gor(p_n_a, p_n_b) ) { - u3_noun new_a = u3nt(u3k(n_a), u3k(l_a), u3_nul); - u3_noun new_lb = u3qdb_uni(new_a, l_b); - u3z(new_a); - - new_b = u3nt(u3k(n_b), new_lb, u3k(r_b)); - old_a = r_a; - } - else { - u3_noun new_a = u3nt(u3k(n_a), u3_nul, u3k(r_a)); - u3_noun new_rb = u3qdb_uni(new_a, r_b); - u3z(new_a); - - new_b = u3nt(u3k(n_b), u3k(l_b), new_rb); - old_a = l_a; - } - - { - u3_noun pro = u3qdb_uni(old_a, new_b); - u3z(new_b); - return pro; - } - } - } -} - -u3_noun -u3wdb_uni(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdb_uni(a, b); -} - -u3_noun -u3kdb_uni(u3_noun a, u3_noun b) -{ - u3_noun pro = u3qdb_uni(a, b); - u3z(a); u3z(b); - return pro; -} diff --git a/pkg/urbit/jets/d/by_urn.c b/pkg/urbit/jets/d/by_urn.c deleted file mode 100644 index 35ccfa5f3..000000000 --- a/pkg/urbit/jets/d/by_urn.c +++ /dev/null @@ -1,41 +0,0 @@ -/* j/4/by_urn.c -** -*/ -#include "all.h" - -static u3_noun -_by_urn(u3_noun a, u3j_site* sit_u) -{ - if ( u3_nul == a ) { - return u3_nul; - } - else { - u3_noun n_a, l_a, r_a; - u3x_trel(a, &n_a, &l_a, &r_a); - - return u3nt(u3nc(u3k(u3h(n_a)), u3j_gate_slam(sit_u, u3k(n_a))), - _by_urn(l_a, sit_u), - _by_urn(r_a, sit_u)); - } -} - -u3_noun -u3qdb_urn(u3_noun a, u3_noun b) -{ - u3_noun pro; - u3j_site sit_u; - - u3j_gate_prep(&sit_u, u3k(b)); - pro = _by_urn(a, &sit_u); - u3j_gate_lose(&sit_u); - - return pro; -} - -u3_noun -u3wdb_urn(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdb_urn(a, b); -} diff --git a/pkg/urbit/jets/d/in_apt.c b/pkg/urbit/jets/d/in_apt.c deleted file mode 100644 index a5fe0bd9f..000000000 --- a/pkg/urbit/jets/d/in_apt.c +++ /dev/null @@ -1,66 +0,0 @@ -/* j/4/in_apt.c -** -*/ -#include "all.h" - -static c3_o -_in_apt(u3_noun a, u3_weak l, u3_weak r) -{ - if ( u3_nul == a ) { - return c3y; - } - else { - u3_noun n_a, l_a, r_a; - u3x_trel(a, &n_a, &l_a, &r_a); - - if ( (u3_none != l) && - ( (c3y == u3r_sing(n_a, l)) || (c3n == u3qc_gor(n_a, l)) )) { - return c3n; - } - - if ( (u3_none != r) && - ( (c3y == u3r_sing(r, n_a)) || (c3n == u3qc_gor(r, n_a)) )) { - return c3n; - } - - if ( u3_nul != l_a ) { - if ( c3y == u3r_sing(n_a, u3h(l_a)) ) { - return c3n; - } - - if ( c3n == u3qc_mor(n_a, u3h(l_a)) ) { - return c3n; - } - - if ( c3n == _in_apt(l_a, n_a, r) ) { - return c3n; - } - } - - if ( u3_nul != r_a ) { - if ( c3y == u3r_sing(n_a, u3h(r_a)) ) { - return c3n; - } - - if ( c3n == u3qc_mor(n_a, u3h(r_a)) ) { - return c3n; - } - - return _in_apt(r_a, l, n_a); - } - - return c3y; - } -} - -u3_noun -u3qdi_apt(u3_noun a) -{ - return _in_apt(a, u3_none, u3_none); -} - -u3_noun -u3wdi_apt(u3_noun cor) -{ - return u3qdi_apt(u3x_at(u3x_con_sam, cor)); -} diff --git a/pkg/urbit/jets/d/in_bif.c b/pkg/urbit/jets/d/in_bif.c deleted file mode 100644 index 643cd7a29..000000000 --- a/pkg/urbit/jets/d/in_bif.c +++ /dev/null @@ -1,72 +0,0 @@ -/* jets/d/in_bif.c -** -*/ -#include "all.h" - -/* internal functions -*/ -static u3_noun -_i_bif_putroot(u3_noun a, - u3_noun b) -{ - if ( u3_nul == a) { - return u3nt(u3k(b), u3_nul, u3_nul); - } - else { - u3_noun n_a, lr_a; - u3x_cell(a, &n_a, &lr_a); - - if ( c3y == u3r_sing(b, n_a) ) { - return u3k(a); - } - else { - u3_noun c, n_c, l_c, r_c; - u3_noun d; - u3_noun l_a, r_a; - u3x_cell(lr_a, &l_a, &r_a); - - if ( c3y == u3qc_gor(b, n_a) ) { - c = _i_bif_putroot(l_a, b); - u3r_trel(c, &n_c, &l_c, &r_c); - d = u3nt(u3k(n_c), - u3k(l_c), - u3nt(u3k(n_a), u3k(r_c), u3k(r_a))); - u3z(c); - return d; - } - else { - c = _i_bif_putroot(r_a, b); - u3r_trel(c, &n_c, &l_c, &r_c); - d = u3nt(u3k(n_c), - u3nt(u3k(n_a), u3k(l_a), u3k(l_c)), - u3k(r_c)); - u3z(c); - return d; - } - } - } -} - -/* functions -*/ -u3_noun -u3wdi_bif(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdi_bif(a, b); -} - -u3_noun -u3qdi_bif(u3_noun a, - u3_noun b) -{ - u3_noun c, n_c, l_c, r_c; - u3_noun d; - - c = _i_bif_putroot(a, b); - u3r_trel(c, &n_c, &l_c, &r_c); - d = u3nc(u3k(l_c), u3k(r_c)); - u3z(c); - return d; -} diff --git a/pkg/urbit/jets/d/in_del.c b/pkg/urbit/jets/d/in_del.c deleted file mode 100644 index 0d8539efd..000000000 --- a/pkg/urbit/jets/d/in_del.c +++ /dev/null @@ -1,88 +0,0 @@ -/* j/4/in_del.c -** -*/ -#include "all.h" - -/* functions -*/ -static u3_noun -_rebalance(u3_noun a) -{ - u3_noun l_a, n_a, r_a; - u3x_trel(a, &n_a, &l_a, &r_a); - - if ( u3_nul == l_a) { - return u3k(r_a); - } - else if ( u3_nul == r_a) { - return u3k(l_a); - } - else { - u3_noun n_l_a, l_l_a, r_l_a; - u3_noun n_r_a, l_r_a, r_r_a; - u3x_trel(l_a, &n_l_a, &l_l_a, &r_l_a); - u3x_trel(r_a, &n_r_a, &l_r_a, &r_r_a); - - if ( c3y == u3qc_mor(n_l_a, n_r_a) ) { - u3_noun new_right = u3nt(u3k(n_a), - u3k(r_l_a), - u3k(r_a)); - - u3_noun ret = u3nt(u3k(n_l_a), - u3k(l_l_a), - _rebalance(new_right)); - u3z(new_right); - - return ret; - } - else { - u3_noun new_left = u3nt(u3k(n_a), - u3k(l_a), - u3k(l_r_a)); - - u3_noun ret = u3nt(u3k(n_r_a), - _rebalance(new_left), - u3k(r_r_a)); - u3z(new_left); - - return ret; - } - } -} - -u3_noun -u3qdi_del(u3_noun a, - u3_noun b) -{ - if ( u3_nul == a ) { - return u3_nul; - } - else { - u3_noun l_a, n_a, r_a; - u3x_trel(a, &n_a, &l_a, &r_a); - - if ( c3y == u3r_sing(n_a, b) ) { - return _rebalance(a); - } - else { - if ( c3y == u3qc_gor(b, n_a) ) { - return u3nt(u3k(n_a), - u3qdi_del(l_a, b), - u3k(r_a)); - } - else { - return u3nt(u3k(n_a), - u3k(l_a), - u3qdi_del(r_a, b)); - } - } - } -} - -u3_noun -u3wdi_del(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdi_del(a, b); -} diff --git a/pkg/urbit/jets/d/in_dif.c b/pkg/urbit/jets/d/in_dif.c deleted file mode 100644 index 05981e287..000000000 --- a/pkg/urbit/jets/d/in_dif.c +++ /dev/null @@ -1,82 +0,0 @@ -/* jets/d/in_dif.c -** -*/ -#include "all.h" - -/* internal functions -*/ - -/* RETAIN -*/ -static u3_noun -_i_dif_join(u3_noun d, - u3_noun e) -{ - if ( u3_nul == d ) { - return u3k(e); - } - else if ( u3_nul == e ) { - return u3k(d); - } - else { - u3_noun n_d, lr_d; - u3_noun n_e, lr_e; - u3x_cell(d, &n_d, &lr_d); - u3x_cell(e, &n_e, &lr_e); - - if ( c3y == u3qc_mor(n_d, n_e) ) { - u3_noun l_d, r_d; - u3x_cell(lr_d, &l_d, &r_d); - - return u3nt(u3k(n_d), - u3k(l_d), - _i_dif_join(r_d, e)); - } - else { - u3_noun l_e, r_e; - u3x_cell(lr_e, &l_e, &r_e); - - return u3nt(u3k(n_e), - _i_dif_join(d, l_e), - u3k(r_e)); - } - } -} - -/* functions -*/ -u3_noun -u3wdi_dif(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdi_dif(a, b); -} - -u3_noun -u3qdi_dif(u3_noun a, - u3_noun b) -{ - if ( u3_nul == b ) { - return u3k(a); - } - else { - u3_noun n_b, l_b, r_b; - u3_noun c, l_c, r_c; - u3_noun d, e; - - u3x_trel(b, &n_b, &l_b, &r_b); - c = u3qdi_bif(a, n_b); - u3x_cell(c, &l_c, &r_c); - - d = u3qdi_dif(l_c, l_b); - e = u3qdi_dif(r_c, r_b); - u3z(c); - - u3_noun pro = _i_dif_join(d, e); - u3z(d); - u3z(e); - - return pro; - } -} diff --git a/pkg/urbit/jets/d/in_gas.c b/pkg/urbit/jets/d/in_gas.c deleted file mode 100644 index b31982de8..000000000 --- a/pkg/urbit/jets/d/in_gas.c +++ /dev/null @@ -1,41 +0,0 @@ -/* j/4/gas.c -** -*/ -#include "all.h" - -/* functions -*/ -u3_noun -u3qdi_gas(u3_noun a, - u3_noun b) -{ - if ( u3_nul == b ) { - return u3k(a); - } - else { - u3_noun i_b, t_b; - u3x_cell(b, &i_b, &t_b); - - u3_noun c = u3qdi_put(a, i_b); - u3_noun d = u3qdi_gas(c, t_b); - u3z(c); - return d; - } -} - -u3_noun -u3wdi_gas(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdi_gas(a, b); -} - -u3_noun -u3kdi_gas(u3_noun a, - u3_noun b) -{ - u3_noun c = u3qdi_gas(a, b); - u3z(a); u3z(b); - return c; -} diff --git a/pkg/urbit/jets/d/in_has.c b/pkg/urbit/jets/d/in_has.c deleted file mode 100644 index 9e1b1b977..000000000 --- a/pkg/urbit/jets/d/in_has.c +++ /dev/null @@ -1,44 +0,0 @@ -/* j/4/in_has.c -** -*/ -#include "all.h" - -/* functions -*/ -u3_noun -u3qdi_has(u3_noun a, - u3_noun b) -{ - if ( u3_nul == a ) { - return c3n; - } - else { - u3_noun n_a, lr_a; - u3x_cell(a, &n_a, &lr_a); - - if ( (c3y == u3r_sing(b, n_a)) ) { - return c3y; - } - else { - return ( c3y == u3qc_gor(b, n_a) ) ? u3qdi_has(u3h(lr_a), b) - : u3qdi_has(u3t(lr_a), b); - } - } -} - -u3_noun -u3wdi_has(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdi_has(a, b); -} - -u3_noun -u3kdi_has(u3_noun a, - u3_noun b) -{ - u3_noun c = u3qdi_has(a, b); - u3z(a); u3z(b); - return c; -} diff --git a/pkg/urbit/jets/d/in_int.c b/pkg/urbit/jets/d/in_int.c deleted file mode 100644 index 85cfc3bb4..000000000 --- a/pkg/urbit/jets/d/in_int.c +++ /dev/null @@ -1,62 +0,0 @@ -/* j/4/in_int.c -** -*/ -#include "all.h" - -u3_noun -u3qdi_int(u3_noun a, u3_noun b) -{ - if ( (u3_nul == a) - || (u3_nul == b) ) - { - return u3_nul; - } - else { - u3_noun n_a, l_a, r_a; - u3_noun n_b, l_b, r_b; - - { - u3_noun lr_a, lr_b; - u3x_cell(a, &n_a, &lr_a); - u3x_cell(b, &n_b, &lr_b); - - if ( c3y == u3qc_mor(n_a, n_b) ) { - u3_noun c; - 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; - } - - u3x_cell(lr_a, &l_a, &r_a); - u3x_cell(lr_b, &l_b, &r_b); - } - - if ( c3y == u3r_sing(n_b, n_a) ) { - return u3nt(u3k(n_a), - u3qdi_int(l_a, l_b), - u3qdi_int(r_a, r_b)); - } - else if ( c3y == u3qc_gor(n_b, n_a) ) { - u3_noun new_l_b = u3nt(u3k(n_b), u3k(l_b), u3_nul); - u3_noun new_a = u3qdi_int(l_a, new_l_b); - - u3z(new_l_b); - return u3kdi_uni(new_a, u3qdi_int(a, r_b)); - } - else { - u3_noun new_r_b = u3nt(u3k(n_b), u3_nul, u3k(r_b)); - u3_noun new_a = u3qdi_int(r_a, new_r_b); - - u3z(new_r_b); - return u3kdi_uni(new_a, u3qdi_int(a, l_b)); - } - } -} - -u3_noun -u3wdi_int(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdi_int(a, b); -} diff --git a/pkg/urbit/jets/d/in_put.c b/pkg/urbit/jets/d/in_put.c deleted file mode 100644 index 2f6301035..000000000 --- a/pkg/urbit/jets/d/in_put.c +++ /dev/null @@ -1,86 +0,0 @@ -/* j/4/in_put.c -** -*/ -#include "all.h" - -/* functions -*/ -u3_noun -u3qdi_put(u3_noun a, - u3_noun b) -{ - if ( u3_nul == a ) { - return u3nt(u3k(b), u3_nul, u3_nul); - } - else { - u3_noun n_a, lr_a; - u3x_cell(a, &n_a, &lr_a); - - if ( c3y == u3r_sing(n_a, b) ) { - return u3k(a); - } - else { - u3_noun c, n_c, l_c, r_c; - u3_noun l_a, r_a; - u3x_cell(lr_a, &l_a, &r_a); - - if ( c3y == u3qc_gor(b, n_a) ) { - c = u3qdi_put(l_a, b); - - if ( c3y == u3qc_mor(n_a, u3h(c)) ) { - return u3nt(u3k(n_a), - c, - u3k(r_a)); - } - else { - u3r_trel(c, &n_c, &l_c, &r_c); - { - u3_noun d = u3nt(u3k(n_c), - u3k(l_c), - u3nt(u3k(n_a), u3k(r_c), u3k(r_a))); - - u3z(c); - return d; - } - } - } - else { - c = u3qdi_put(r_a, b); - - if ( c3y == u3qc_mor(n_a, u3h(c)) ) { - return u3nt(u3k(n_a), - u3k(l_a), - c); - } - else { - u3r_trel(c, &n_c, &l_c, &r_c); - { - u3_noun d = u3nt(u3k(n_c), - u3nt(u3k(n_a), u3k(l_a), u3k(l_c)), - u3k(r_c)); - - u3z(c); - return d; - } - } - } - } - } -} - -u3_noun -u3wdi_put(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdi_put(a, b); -} - -u3_noun -u3kdi_put(u3_noun a, - u3_noun b) -{ - u3_noun pro = u3qdi_put(a, b); - u3z(a); u3z(b); - return pro; -} diff --git a/pkg/urbit/jets/d/in_rep.c b/pkg/urbit/jets/d/in_rep.c deleted file mode 100644 index 7af3c5d9e..000000000 --- a/pkg/urbit/jets/d/in_rep.c +++ /dev/null @@ -1,44 +0,0 @@ -/* j/4/in_rep.c -** -*/ -#include "all.h" - -// [a] is RETAINED, [out] is TRANSFERRED -// -static void -_in_rep(u3_noun a, u3j_site* sit_u, u3_noun* out) -{ - if ( u3_nul == a ) { - return; - } - else { - u3_noun n_a, l_a, r_a; - u3x_trel(a, &n_a, &l_a, &r_a); - - *out = u3j_gate_slam(sit_u, u3nc(u3k(n_a), *out)); - - _in_rep(l_a, sit_u, out); - _in_rep(r_a, sit_u, out); - } -} - -u3_noun -u3qdi_rep(u3_noun a, u3_noun b) -{ - u3_noun out = u3k(u3x_at(u3x_sam_3, b)); - u3j_site sit_u; - - u3j_gate_prep(&sit_u, u3k(b)); - _in_rep(a, &sit_u, &out); - u3j_gate_lose(&sit_u); - - return out; -} - -u3_noun -u3wdi_rep(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdi_rep(a, b); -} diff --git a/pkg/urbit/jets/d/in_run.c b/pkg/urbit/jets/d/in_run.c deleted file mode 100644 index 2a9747241..000000000 --- a/pkg/urbit/jets/d/in_run.c +++ /dev/null @@ -1,51 +0,0 @@ -/* j/4/in_run.c -** -*/ -#include "all.h" - -// [a] is RETAINED, [out] is TRANSFERRED -// -static void -_in_run(u3_noun a, u3j_site* sit_u, u3_noun* out) -{ - if ( u3_nul == a ) { - return; - } - else { - u3_noun n_a, l_a, r_a; - u3x_trel(a, &n_a, &l_a, &r_a); - - { - u3_noun new = u3j_gate_slam(sit_u, u3k(n_a)); - u3_noun pro = u3qdi_put(*out, new); - - u3z(new); - u3z(*out); - *out = pro; - } - - _in_run(l_a, sit_u, out); - _in_run(r_a, sit_u, out); - } -} - -u3_noun -u3qdi_run(u3_noun a, u3_noun b) -{ - u3_noun out = u3_nul; - u3j_site sit_u; - - u3j_gate_prep(&sit_u, u3k(b)); - _in_run(a, &sit_u, &out); - u3j_gate_lose(&sit_u); - - return out; -} - -u3_noun -u3wdi_run(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdi_run(a, b); -} diff --git a/pkg/urbit/jets/d/in_tap.c b/pkg/urbit/jets/d/in_tap.c deleted file mode 100644 index 648753091..000000000 --- a/pkg/urbit/jets/d/in_tap.c +++ /dev/null @@ -1,45 +0,0 @@ -/* j/4/in_tap.c -** -*/ -#include "all.h" - -/* functions -*/ -static u3_noun -_tap_in(u3_noun a, - u3_noun b) -{ - if ( u3_nul == a ) { - return b; - } - else { - u3_noun n_a, l_a, r_a; - u3x_trel(a, &n_a, &l_a, &r_a); - - return _tap_in(r_a, - u3nc(u3k(n_a), - _tap_in(l_a, b))); - } -} - -u3_noun -u3qdi_tap(u3_noun a) -{ - return _tap_in(a, u3_nul); -} - -u3_noun -u3wdi_tap(u3_noun cor) -{ - u3_noun a; - u3x_mean(cor, u3x_con_sam, &a, 0); - return u3qdi_tap(a); -} - -u3_noun -u3kdi_tap(u3_noun a) -{ - u3_noun b = u3qdi_tap(a); - u3z(a); - return b; -} diff --git a/pkg/urbit/jets/d/in_uni.c b/pkg/urbit/jets/d/in_uni.c deleted file mode 100644 index cc18ecd37..000000000 --- a/pkg/urbit/jets/d/in_uni.c +++ /dev/null @@ -1,97 +0,0 @@ -/* j/4/in_uni.c -** -*/ -#include "all.h" - -/* internal functions -*/ -static u3_noun -_in_uni(u3_noun a, u3_noun b) -{ - if ( u3_nul == a ) { - return u3k(b); - } - else if ( u3_nul == b ) { - return u3k(a); - } - else { - u3_noun n_a, l_a, r_a, - n_b, l_b, r_b, - neb, sub, naw, pro; - u3x_trel(a, &n_a, &l_a, &r_a); - u3x_trel(b, &n_b, &l_b, &r_b); - - if ( c3n == u3qc_mor(n_a, n_b) ) { - if ( c3y == u3r_sing(n_a, n_b) ) { - return u3nt(u3k(n_b), _in_uni(l_a, l_b), _in_uni(r_a, r_b)); - } - else if ( c3y == u3qc_gor(n_a, n_b) ) { - naw = u3nt(u3k(n_a), u3k(l_a), u3_nul); - sub = _in_uni(naw, l_b); - neb = u3nt(u3k(n_b), sub, u3k(r_b)); - pro = _in_uni(r_a, neb); - u3z(naw); u3z(neb); - return pro; - } - else { - naw = u3nt(u3k(n_a), u3_nul, u3k(r_a)); - sub = _in_uni(naw, r_b); - neb = u3nt(u3k(n_b), u3k(l_b), sub); - pro = _in_uni(l_a, neb); - u3z(naw); u3z(neb); - return pro; - } - } - else if ( c3y == u3r_sing(n_b, n_a) ) { - return u3nt(u3k(n_b), _in_uni(l_a, l_b), _in_uni(r_a, r_b)); - } - else if ( c3y == u3qc_gor(n_b, n_a) ) { - neb = u3nt(u3k(n_b), u3k(l_b), u3_nul); - sub = _in_uni(l_a, neb); - naw = u3nt(u3k(n_a), sub, u3k(r_a)); - pro = _in_uni(naw, r_b); - u3z(neb); u3z(naw); - return pro; - } - else { - neb = u3nt(u3k(n_b), u3_nul, u3k(r_b)); - sub = _in_uni(r_a, neb); - naw = u3nt(u3k(n_a), u3k(l_a), sub); - pro = _in_uni(naw, l_b); - u3z(neb); u3z(naw); - return pro; - } - } -} - -/* functions -*/ -u3_noun -u3kdi_uni(u3_noun a, - u3_noun b) -{ - u3_noun c = u3qdi_uni(a, b); - u3z(a); u3z(b); - return c; -} - -u3_noun -u3qdi_uni(u3_noun a, - u3_noun b) -{ - if ( c3y == u3r_sing(a, b) ) { - return u3k(a); - } - else { - return _in_uni(a, b); - } -} - -u3_noun -u3wdi_uni(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0); - return u3qdi_uni(a, b); -} - diff --git a/pkg/urbit/jets/d/in_wyt.c b/pkg/urbit/jets/d/in_wyt.c deleted file mode 100644 index d28fbac16..000000000 --- a/pkg/urbit/jets/d/in_wyt.c +++ /dev/null @@ -1,33 +0,0 @@ -/* jets/d/in_wyt.c -** -*/ -#include "all.h" - -STATIC_ASSERT( (UINT32_MAX > u3a_cells), - "width precision" ); - -static c3_w -_wyt_in(u3_noun a) -{ - if ( u3_nul == a ) { - return 0; - } - else { - u3_noun l_a, r_a; - u3x_trel(a, 0, &l_a, &r_a); - - return 1 + _wyt_in(l_a) + _wyt_in(r_a); - } -} - -u3_noun -u3qdi_wyt(u3_noun a) -{ - return u3i_word(_wyt_in(a)); -} - -u3_noun -u3wdi_wyt(u3_noun cor) -{ - return u3qdi_wyt(u3x_at(u3x_con_2, cor)); -} diff --git a/pkg/urbit/jets/e/aes_cbc.c b/pkg/urbit/jets/e/aes_cbc.c deleted file mode 100644 index b561efa44..000000000 --- a/pkg/urbit/jets/e/aes_cbc.c +++ /dev/null @@ -1,182 +0,0 @@ -/* j/5/aes_cbc.c -** -*/ -#include "all.h" -#include - -/* All of the CBC hoon truncates its key and prv inputs by passing them to - * the ECB functions, which truncate them, hence the raw u3r_bytes unpacking. - */ - -typedef int (*urcrypt_cbc)(c3_y**, - size_t*, - c3_y*, - c3_y*, - urcrypt_realloc_t); - -/* functions -*/ - static u3_atom - _cqea_cbc_help(c3_y* key_y, u3_atom iv, u3_atom msg, urcrypt_cbc low_f) - { - u3_atom ret; - c3_w met_w; - c3_y iv_y[16]; - c3_y* msg_y = u3r_bytes_all(&met_w, msg); - size_t len = met_w; - - u3r_bytes(0, 16, iv_y, iv); - if ( 0 != (*low_f)(&msg_y, &len, key_y, iv_y, &u3a_realloc) ) { - ret = u3_none; - } - else { - ret = u3i_bytes(len, msg_y); - } - u3a_free(msg_y); - - return ret; - } - - static u3_atom - _cqea_cbca_en(u3_atom key, - u3_atom iv, - u3_atom msg) - { - c3_y key_y[16]; - u3r_bytes(0, 16, key_y, key); - return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbca_en); - } - - u3_noun - u3wea_cbca_en(u3_noun cor) - { - u3_noun a, b, c; - - if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("cbca-en", _cqea_cbca_en(a, b, c)); - } - } - - static u3_atom - _cqea_cbca_de(u3_atom key, - u3_atom iv, - u3_atom msg) - { - c3_y key_y[16]; - u3r_bytes(0, 16, key_y, key); - return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbca_de); - } - - u3_noun - u3wea_cbca_de(u3_noun cor) - { - u3_noun a, b, c; - - if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("cbca-de", _cqea_cbca_de(a, b, c)); - } - } - - static u3_atom - _cqea_cbcb_en(u3_atom key, - u3_atom iv, - u3_atom msg) - { - c3_y key_y[24]; - u3r_bytes(0, 24, key_y, key); - return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbcb_en); - } - - u3_noun - u3wea_cbcb_en(u3_noun cor) - { - u3_noun a, b, c; - - if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("cbcb-en", _cqea_cbcb_en(a, b, c)); - } - } - - static u3_atom - _cqea_cbcb_de(u3_atom key, - u3_atom iv, - u3_atom msg) - { - c3_y key_y[24]; - u3r_bytes(0, 24, key_y, key); - return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbcb_de); - } - - u3_noun - u3wea_cbcb_de(u3_noun cor) - { - u3_noun a, b, c; - - if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("cbcb-de", _cqea_cbcb_de(a, b, c)); - } - } - - static u3_atom - _cqea_cbcc_en(u3_atom key, - u3_atom iv, - u3_atom msg) - { - c3_y key_y[32]; - u3r_bytes(0, 32, key_y, key); - return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbcc_en); - } - - u3_noun - u3wea_cbcc_en(u3_noun cor) - { - u3_noun a, b, c; - - if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("cbcc-en", _cqea_cbcc_en(a, b, c)); - } - } - - static u3_atom - _cqea_cbcc_de(u3_atom key, - u3_atom iv, - u3_atom msg) - { - c3_y key_y[32]; - u3r_bytes(0, 32, key_y, key); - return _cqea_cbc_help(key_y, iv, msg, &urcrypt_aes_cbcc_de); - } - - u3_noun - u3wea_cbcc_de(u3_noun cor) - { - u3_noun a, b, c; - - if ( c3n == u3r_mean(cor, u3x_sam, &c, 60, &a, 61, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("cbcc-de", _cqea_cbcc_de(a, b, c)); - } - } diff --git a/pkg/urbit/jets/e/aes_ecb.c b/pkg/urbit/jets/e/aes_ecb.c deleted file mode 100644 index d350bc808..000000000 --- a/pkg/urbit/jets/e/aes_ecb.c +++ /dev/null @@ -1,166 +0,0 @@ -/* j/5/aes_ecb.c -** -*/ -#include "all.h" -#include - -typedef int (*urcrypt_ecb)(c3_y*, c3_y[16], c3_y[16]); - -/* functions -*/ - - /* All of the ECB hoon truncates its key and blk inputs with +fe, in these - * jets we unpack with an unconditional u3r_bytes */ - - static u3_atom - _cqea_ecb_help(c3_y* key_y, u3_atom blk, urcrypt_ecb low_f) - { - c3_y blk_y[16], out_y[16]; - - u3r_bytes(0, 16, blk_y, blk); - - if ( 0 != (*low_f)(key_y, blk_y, out_y) ) { - return u3_none; - } - else { - return u3i_bytes(16, out_y); - } - } - - static u3_atom - _cqea_ecba_en(u3_atom key, - u3_atom blk) - { - c3_y key_y[16]; - u3r_bytes(0, 16, key_y, key); - return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecba_en); - } - - u3_noun - u3wea_ecba_en(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("ecba-en", _cqea_ecba_en(a, b)); - } - } - - static u3_atom - _cqea_ecba_de(u3_atom key, - u3_atom blk) - { - c3_y key_y[16]; - u3r_bytes(0, 16, key_y, key); - return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecba_de); - } - - u3_noun - u3wea_ecba_de(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("ecba-de", _cqea_ecba_de(a, b)); - } - } - - static u3_atom - _cqea_ecbb_en(u3_atom key, - u3_atom blk) - { - c3_y key_y[24]; - u3r_bytes(0, 24, key_y, key); - return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecbb_en); - } - - u3_noun - u3wea_ecbb_en(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("ecbb-en", _cqea_ecbb_en(a, b)); - } - } - - static u3_atom - _cqea_ecbb_de(u3_atom key, - u3_atom blk) - { - c3_y key_y[24]; - u3r_bytes(0, 24, key_y, key); - return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecbb_de); - } - - u3_noun - u3wea_ecbb_de(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("ecbb-de", _cqea_ecbb_de(a, b)); - } - } - - static u3_atom - _cqea_ecbc_en(u3_atom key, - u3_atom blk) - { - c3_y key_y[32]; - u3r_bytes(0, 32, key_y, key); - return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecbc_en); - } - - u3_noun - u3wea_ecbc_en(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("ecbc-en", _cqea_ecbc_en(a, b)); - } - } - - static u3_atom - _cqea_ecbc_de(u3_atom key, - u3_atom blk) - { - c3_y key_y[32]; - u3r_bytes(0, 32, key_y, key); - return _cqea_ecb_help(key_y, blk, &urcrypt_aes_ecbc_de); - } - - u3_noun - u3wea_ecbc_de(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("ecbc-de", _cqea_ecbc_de(a, b)); - } - } diff --git a/pkg/urbit/jets/e/aes_siv.c b/pkg/urbit/jets/e/aes_siv.c deleted file mode 100644 index 4c1b01583..000000000 --- a/pkg/urbit/jets/e/aes_siv.c +++ /dev/null @@ -1,370 +0,0 @@ -/* j/5/aes_ecb.c -** -*/ -#include "all.h" -#include - -typedef int (*urcrypt_siv)(c3_y*, size_t, - urcrypt_aes_siv_data*, size_t, - c3_y*, c3_y[16], c3_y*); - -/* functions -*/ - -// soc_w = number of items -// mat_w = size in bytes of assoc array -// dat_w = size of allocation (array + atom storage) -static void -_cqea_measure_ads(u3_noun ads, c3_w* soc_w, c3_w *mat_w, c3_w *dat_w) -{ - u3_noun i, t; - c3_w a_w, b_w, tmp_w, met_w; - - for ( a_w = b_w = 0, t = ads; u3_nul != t; ++a_w ) { - u3x_cell(t, &i, &t); - if ( c3n == u3ud(i) ) { - u3m_bail(c3__exit); - return; - } - else { - tmp_w = b_w; - b_w += u3r_met(3, i); - if ( b_w < tmp_w ) { - u3m_bail(c3__fail); - return; - } - } - } - - // check for size overflows - tmp_w = a_w * sizeof(urcrypt_aes_siv_data); - if ( (tmp_w / a_w) != sizeof(urcrypt_aes_siv_data) ) { - u3m_bail(c3__fail); - } - else if ( (*dat_w = tmp_w + b_w) < tmp_w ) { - u3m_bail(c3__fail); - } - else { - *soc_w = a_w; - *mat_w = tmp_w; - } -} - -// assumes ads is a valid (list @) because it's already been measured -static void -_cqea_encode_ads(u3_noun ads, - c3_w mat_w, - urcrypt_aes_siv_data *dat_u) -{ - c3_w met_w; - u3_noun i, t; - urcrypt_aes_siv_data *cur_u; - c3_y *dat_y = ((c3_y*) dat_u) + mat_w; - - for ( cur_u = dat_u, t = ads; u3_nul != t; t = u3t(t), ++cur_u ) { - i = u3h(t); - met_w = u3r_met(3, i); - u3r_bytes(0, met_w, dat_y, i); - cur_u->length = met_w; - cur_u->bytes = dat_y; - dat_y += met_w; - } -} - -static void -_cqea_ads_free(urcrypt_aes_siv_data *dat_u) -{ - if ( NULL != dat_u ) { - u3a_free(dat_u); - } -} - -static urcrypt_aes_siv_data* -_cqea_ads_alloc(u3_noun ads, c3_w *soc_w) -{ - if ( !ads ) { - *soc_w = 0; - return NULL; - } - else { - c3_w mat_w, dat_w; - urcrypt_aes_siv_data *dat_u; - - _cqea_measure_ads(ads, soc_w, &mat_w, &dat_w); - dat_u = u3a_malloc(dat_w); - _cqea_encode_ads(ads, mat_w, dat_u); - return dat_u; - } -} - -static u3_noun -_cqea_siv_en(c3_y* key_y, - c3_w key_w, - u3_noun ads, - u3_atom txt, - urcrypt_siv low_f) -{ - u3_noun ret; - c3_w txt_w, soc_w; - c3_y *txt_y, *out_y, iv_y[16]; - urcrypt_aes_siv_data *dat_u; - - dat_u = _cqea_ads_alloc(ads, &soc_w); - txt_y = u3r_bytes_all(&txt_w, txt); - out_y = u3a_malloc(txt_w); - - ret = ( 0 != (*low_f)(txt_y, txt_w, dat_u, soc_w, key_y, iv_y, out_y) ) - ? u3_none - : u3nt(u3i_bytes(16, iv_y), - u3i_words(1, &txt_w), - u3i_bytes(txt_w, out_y)); - - u3a_free(txt_y); - u3a_free(out_y); - _cqea_ads_free(dat_u); - return ret; -} - -static u3_noun -_cqea_siv_de(c3_y* key_y, - c3_w key_w, - u3_noun ads, - u3_atom iv, - u3_atom len, - u3_atom txt, - urcrypt_siv low_f) -{ - c3_w txt_w; - if ( !u3r_word_fit(&txt_w, len) ) { - return u3m_bail(c3__fail); - } - else { - u3_noun ret; - c3_w soc_w; - c3_y *txt_y, *out_y, iv_y[16]; - urcrypt_aes_siv_data *dat_u; - - u3r_bytes(0, 16, iv_y, iv); - dat_u = _cqea_ads_alloc(ads, &soc_w); - txt_y = u3r_bytes_alloc(0, txt_w, txt); - out_y = u3a_malloc(txt_w); - - if ( 0 != (*low_f)(txt_y, txt_w, dat_u, soc_w, key_y, iv_y, out_y) ) { - return u3m_bail(c3__evil); - } - - ret = u3nc(0, u3i_bytes(txt_w, out_y)); - - u3a_free(txt_y); - u3a_free(out_y); - _cqea_ads_free(dat_u); - - return ret; - } -} - -// the siv* hoon doesn't explicitly check keysizes, but all of these functions -// have fixed maximum keysizes, so we will punt if we get a key that is too -// large. - -static u3_noun -_cqea_siva_en(u3_atom key, - u3_noun ads, - u3_atom txt) -{ - if ( u3r_met(3, key) > 32 ) { - return u3_none; - } - else { - c3_y key_y[32]; - u3r_bytes(0, 32, key_y, key); - return _cqea_siv_en(key_y, 32, ads, txt, &urcrypt_aes_siva_en); - } -} - -u3_noun -u3wea_siva_en(u3_noun cor) -{ - u3_noun key, ads, txt; - - if ( c3n == u3r_mean(cor, u3x_sam, &txt, - u3x_con_sam_2, &key, - u3x_con_sam_3, &ads, 0) || - c3n == u3ud(key) || - c3n == u3ud(txt) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("siva-en", _cqea_siva_en(key, ads, txt)); - } -} - -static u3_noun -_cqea_siva_de(u3_atom key, - u3_noun ads, - u3_atom iv, - u3_atom len, - u3_atom txt) -{ - if ( u3r_met(3, key) > 32 ) { - return u3_none; - } - else { - c3_y key_y[32]; - u3r_bytes(0, 32, key_y, key); - return _cqea_siv_de(key_y, 32, ads, iv, len, txt, &urcrypt_aes_siva_de); - } -} - -u3_noun -u3wea_siva_de(u3_noun cor) -{ - u3_noun key, ads, iv, len, txt; - - if ( c3n == u3r_mean(cor, - u3x_sam_2, &iv, - u3x_sam_6, &len, - u3x_sam_7, &txt, - u3x_con_sam_2, &key, - u3x_con_sam_3, &ads, 0) || - c3n == u3ud(key) || - c3n == u3ud(txt) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("siva-de", _cqea_siva_de(key, ads, iv, len, txt)); - } -} - -static u3_noun -_cqea_sivb_en(u3_atom key, - u3_noun ads, - u3_atom txt) -{ - if ( u3r_met(3, key) > 48 ) { - return u3_none; - } - else { - c3_y key_y[48]; - u3r_bytes(0, 48, key_y, key); - return _cqea_siv_en(key_y, 48, ads, txt, &urcrypt_aes_sivb_en); - } -} - - -u3_noun -u3wea_sivb_en(u3_noun cor) -{ - u3_noun key, ads, txt; - - if ( c3n == u3r_mean(cor, u3x_sam, &txt, - u3x_con_sam_2, &key, - u3x_con_sam_3, &ads, 0) || - c3n == u3ud(key) || - c3n == u3ud(txt) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("sivb-en", _cqea_sivb_en(key, ads, txt)); - } -} - -static u3_noun -_cqea_sivb_de(u3_atom key, - u3_noun ads, - u3_atom iv, - u3_atom len, - u3_atom txt) -{ - if ( u3r_met(3, key) > 48 ) { - return u3_none; - } - else { - c3_y key_y[48]; - u3r_bytes(0, 48, key_y, key); - return _cqea_siv_de(key_y, 48, ads, iv, len, txt, &urcrypt_aes_sivb_de); - } -} - -u3_noun -u3wea_sivb_de(u3_noun cor) -{ - u3_noun key, ads, iv, len, txt; - - if ( c3n == u3r_mean(cor, - u3x_sam_2, &iv, - u3x_sam_6, &len, - u3x_sam_7, &txt, - u3x_con_sam_2, &key, - u3x_con_sam_3, &ads, 0) || - c3n == u3ud(key) || - c3n == u3ud(txt) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("sivb-de", _cqea_sivb_de(key, ads, iv, len, txt)); - } -} - -static u3_noun -_cqea_sivc_en(u3_atom key, - u3_noun ads, - u3_atom txt) -{ - if ( u3r_met(3, key) > 64 ) { - return u3_none; - } - else { - c3_y key_y[64]; - u3r_bytes(0, 64, key_y, key); - return _cqea_siv_en(key_y, 64, ads, txt, &urcrypt_aes_sivc_en); - } -} - -u3_noun -u3wea_sivc_en(u3_noun cor) -{ - u3_noun key, ads, txt; - - if ( c3n == u3r_mean(cor, u3x_sam, &txt, - u3x_con_sam_2, &key, - u3x_con_sam_3, &ads, 0) || - c3n == u3ud(key) || - c3n == u3ud(txt) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("sivc-en", _cqea_sivc_en(key, ads, txt)); - } -} - -static u3_noun -_cqea_sivc_de(u3_atom key, - u3_noun ads, - u3_atom iv, - u3_atom len, - u3_atom txt) -{ - if ( u3r_met(3, key) > 64 ) { - return u3_none; - } - else { - c3_y key_y[64]; - u3r_bytes(0, 64, key_y, key); - return _cqea_siv_de(key_y, 64, ads, iv, len, txt, &urcrypt_aes_sivc_de); - } -} - -u3_noun -u3wea_sivc_de(u3_noun cor) -{ - u3_noun key, ads, iv, len, txt; - - if ( c3n == u3r_mean(cor, - u3x_sam_2, &iv, - u3x_sam_6, &len, - u3x_sam_7, &txt, - u3x_con_sam_2, &key, - u3x_con_sam_3, &ads, 0) || - c3n == u3ud(key) || - c3n == u3ud(txt) ) { - return u3m_bail(c3__exit); - } else { - return u3l_punt("sivc-de", _cqea_sivc_de(key, ads, iv, len, txt)); - } -} diff --git a/pkg/urbit/jets/e/argon2.c b/pkg/urbit/jets/e/argon2.c deleted file mode 100644 index 689cb84e3..000000000 --- a/pkg/urbit/jets/e/argon2.c +++ /dev/null @@ -1,151 +0,0 @@ -/* j/5/argon2.c -** -*/ -#include "all.h" -#include - -/* helpers -*/ - - static int - argon2_alloc(uint8_t** output, size_t bytes) - { - *output = u3a_malloc(bytes); - return 1; - } - - static void - argon2_free(uint8_t* memory, size_t bytes) - { - u3a_free(memory); - } - - static c3_t - _cqear_unpack_type(c3_y* out, u3_atom in) - { - switch ( in ) { - default: - return 0; - case c3__d: - *out = urcrypt_argon2_d; - return 1; - case c3__i: - *out = urcrypt_argon2_i; - return 1; - case c3__id: - *out = urcrypt_argon2_id; - return 1; - case c3__u: - *out = urcrypt_argon2_u; - return 1; - } - } - -/* functions -*/ - - static u3_atom - _cqe_argon2( // configuration params, - u3_atom out, u3_atom type, u3_atom version, - u3_atom threads, u3_atom mem_cost, u3_atom time_cost, - u3_atom wik, u3_atom key, u3_atom wix, u3_atom extra, - // input params - u3_atom wid, u3_atom dat, u3_atom wis, u3_atom sat ) - { - c3_y typ_u; - c3_w out_w, wik_w, wix_w, wid_w, wis_w, ver_w, ted_w, mem_w, tim_w; - - if ( !(u3r_word_fit(&out_w, out) && - u3r_word_fit(&wik_w, wik) && - u3r_word_fit(&wix_w, wix) && - u3r_word_fit(&wid_w, wid) && - u3r_word_fit(&wis_w, wis)) ) { - // too big to allocate - return u3m_bail(c3__fail); - } - else if ( !(_cqear_unpack_type(&typ_u, type) && - u3r_word_fit(&ver_w, version) && - u3r_word_fit(&ted_w, threads) && - u3r_word_fit(&mem_w, mem_cost) && - u3r_word_fit(&tim_w, time_cost)) ) { - return u3_none; - } - else { - u3_atom ret; - c3_y *key_y = u3r_bytes_alloc(0, wik_w, key), - *ex_y = u3r_bytes_alloc(0, wix_w, extra), - *dat_y = u3r_bytes_alloc(0, wid_w, dat), - *sat_y = u3r_bytes_alloc(0, wis_w, sat), - *out_y = u3a_malloc(out_w); - - const c3_c* err_c = urcrypt_argon2( - typ_u, ver_w, ted_w, mem_w, tim_w, - wik_w, key_y, - wix_w, ex_y, - wid_w, dat_y, - wis_w, sat_y, - out_w, out_y, - &argon2_alloc, - &argon2_free); - - u3a_free(key_y); - u3a_free(ex_y); - u3a_free(dat_y); - u3a_free(sat_y); - - if ( NULL == err_c ) { - ret = u3i_bytes(out_w, out_y); - } - else { - ret = u3_none; - u3l_log("argon2-error: %s", err_c); - } - - u3a_free(out_y); - return ret; - } - } - - u3_noun - u3we_argon2(u3_noun cor) - { - u3_noun // configuration params - out, type, version, - threads, mem_cost, time_cost, - wik, key, wix, extra, - // input params - wid, dat, wis, sat, - // for use during unpacking - wmsg, wsat, arg, brg, wkey, wext; - - // the hoon code for argon2 takes configuration parameters, - // and then produces a gate. we jet that inner gate. - // this does mean that the config params have gotten buried - // pretty deep in the subject, hence the +510. - if ( c3n == u3r_mean(cor, u3x_sam_2, &wmsg, - u3x_sam_3, &wsat, - 510, &arg, 0) || - u3r_cell(wmsg, &wid, &dat) || u3ud(wid) || u3ud(dat) || - u3r_cell(wsat, &wis, &sat) || u3ud(wis) || u3ud(sat) || - // - u3r_qual(arg, &out, &type, &version, &brg) || - u3ud(out) || u3ud(type) || u3ud(version) || - // - u3r_qual(brg, &threads, &mem_cost, &time_cost, &arg) || - u3ud(threads) || u3ud(mem_cost) || u3ud(time_cost) || - // - u3r_cell(arg, &wkey, &wext) || - u3r_cell(wkey, &wik, &key) || u3ud(wik) || u3ud(key) || - u3r_cell(wext, &wix, &extra) || u3ud(wix) || u3ud(extra) - ) - { - return u3m_bail(c3__exit); - } - else { - return u3l_punt("argon2", - _cqe_argon2(out, type, version, - threads, mem_cost, time_cost, - wik, key, wix, extra, - wid, dat, wis, sat)); - } - } diff --git a/pkg/urbit/jets/e/base.c b/pkg/urbit/jets/e/base.c deleted file mode 100644 index 021b055cc..000000000 --- a/pkg/urbit/jets/e/base.c +++ /dev/null @@ -1,153 +0,0 @@ -/* j/5/base.c -** -*/ -#include "all.h" - -const c3_y hex_y[16] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - -u3_noun -u3qe_en_base16(u3_atom len, u3_atom dat) -{ - if ( c3n == u3a_is_cat(len) ) { - return u3m_bail(c3__fail); - } - else { - c3_w len_w = (c3_w)len; - u3i_slab sab_u; - - u3i_slab_bare(&sab_u, 4, len_w); - sab_u.buf_w[sab_u.len_w - 1] = 0; - - { - c3_y* buf_y = sab_u.buf_y; - c3_y inp_y; - - while ( len_w-- ) { - inp_y = u3r_byte(len_w, dat); - - *buf_y++ = hex_y[inp_y >> 4]; - *buf_y++ = hex_y[inp_y & 0xf]; - } - } - - return u3i_slab_moot_bytes(&sab_u); - } -} - -static inline c3_o -_of_hex_digit(c3_y inp_y, c3_y* out_y) -{ - if ( inp_y >= '0' && inp_y <= '9' ) { - *out_y = inp_y - '0'; - return c3y; - } - else if ( inp_y >= 'a' && inp_y <= 'f' ) { - *out_y = inp_y - 87; - return c3y; - } - else if ( inp_y >= 'A' && inp_y <= 'F' ) { - *out_y = inp_y - 55; - return c3y; - } - - return c3n; -} - -static inline c3_o -_of_hex_odd(u3_atom inp, c3_w len_w, c3_w byt_w, c3_y* buf_y) -{ - c3_y low_y, hig_y, lit_y, hit_y; - - hig_y = u3r_byte(--byt_w, inp); - - while ( --len_w ) { - low_y = u3r_byte(--byt_w, inp); - - if ( (c3n == _of_hex_digit(low_y, &lit_y)) - || (c3n == _of_hex_digit(hig_y, &hit_y)) ) - { - return c3n; - } - else { - *buf_y++ = (hit_y & 0xf) ^ (lit_y << 4); - } - - hig_y = u3r_byte(--byt_w, inp); - } - - if ( c3n == _of_hex_digit(hig_y, &hit_y) ) { - return c3n; - } - else { - *buf_y = hit_y & 0xf; - } - - return c3y; -} - -static inline c3_o -_of_hex_even(u3_atom inp, c3_w len_w, c3_y* buf_y) -{ - c3_y lit_y, hit_y; - c3_s inp_s; - - while ( len_w-- ) { - inp_s = u3r_short(len_w, inp); - - if ( (c3n == _of_hex_digit(inp_s & 0xff, &lit_y)) - || (c3n == _of_hex_digit(inp_s >> 8, &hit_y)) ) - { - return c3n; - } - else { - *buf_y++ = (hit_y & 0xf) ^ (lit_y << 4); - } - } - - return c3y; -} - -u3_noun -u3qe_de_base16(u3_atom inp) -{ - c3_w len_w = u3r_met(4, inp); - u3i_slab sab_u; - - u3i_slab_bare(&sab_u, 3, len_w); - sab_u.buf_w[sab_u.len_w - 1] = 0; - - // even byte-length input can be parsed in aligned, 16-bit increments, - // but odd byte-length input cannot, and is expressed more simply in bytes. - // - { - c3_w byt_w = u3r_met(3, inp); - c3_o ret_o = ( byt_w & 1 ) - ? _of_hex_odd(inp, len_w, byt_w, sab_u.buf_y) - : _of_hex_even(inp, len_w, sab_u.buf_y); - - if ( c3n == ret_o ) { - u3i_slab_free(&sab_u); - return u3_nul; - } - else { - u3_noun dat = u3i_slab_mint_bytes(&sab_u); - return u3nt(u3_nul, u3i_word(len_w), dat); - } - } -} - -u3_noun -u3we_en_base16(u3_noun cor) -{ - u3_noun a, b; - u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0); - return u3qe_en_base16(u3x_atom(a), u3x_atom(b)); -} - -u3_noun -u3we_de_base16(u3_noun cor) -{ - u3_noun sam = u3x_at(u3x_sam, cor); - return u3qe_de_base16(u3x_atom(sam)); -} diff --git a/pkg/urbit/jets/e/blake.c b/pkg/urbit/jets/e/blake.c deleted file mode 100644 index 1770a3f89..000000000 --- a/pkg/urbit/jets/e/blake.c +++ /dev/null @@ -1,60 +0,0 @@ -/* j/5/blake.c -** -*/ -#include "all.h" -#include - -/* functions -*/ - - static u3_atom - _cqe_blake(u3_atom wid, u3_atom dat, - u3_atom wik, u3_atom dak, - u3_atom out) - { - c3_w wid_w; - if ( !u3r_word_fit(&wid_w, wid) ) { - // impossible to represent an atom this large - return u3m_bail(c3__fail); - } - else { - // the hoon adjusts these widths to its liking - int err; - u3_atom ret; - c3_y out_y[64], dak_y[64]; - c3_w wik_w = c3_min(wik, 64), - out_w = c3_max(1, c3_min(out, 64)); - c3_y *dat_y = u3r_bytes_alloc(0, wid_w, dat); - - u3r_bytes(0, wik_w, dak_y, dak); - err = urcrypt_blake2(wid_w, dat_y, wik_w, dak_y, out_w, out_y); - u3a_free(dat_y); - - if ( 0 == err ) { - return u3i_bytes(out_w, out_y); - } - else { - return u3_none; - } - } - } - - u3_noun - u3we_blake(u3_noun cor) - { - u3_noun msg, key, out, // arguments - wid, dat, // destructured msg - wik, dak; // destructured key - - if ( c3n == u3r_mean(cor, u3x_sam_2, &msg, - u3x_sam_6, &key, - u3x_sam_7, &out, 0) || - u3r_cell(msg, &wid, &dat) || u3ud(wid) || u3ud(dat) || - u3r_cell(key, &wik, &dak) || u3ud(wik) || u3ud(dak) || - u3ud(out) ) - { - return u3m_bail(c3__exit); - } else { - return u3l_punt("blake", _cqe_blake(wid, dat, wik, dak, out)); - } - } diff --git a/pkg/urbit/jets/e/cue.c b/pkg/urbit/jets/e/cue.c deleted file mode 100644 index eab7ac031..000000000 --- a/pkg/urbit/jets/e/cue.c +++ /dev/null @@ -1,24 +0,0 @@ -/* j/5/cue.c -** -*/ -#include "all.h" - -u3_noun -u3qe_cue(u3_atom a) -{ - return u3s_cue_atom(a); -} - -u3_noun -u3we_cue(u3_noun cor) -{ - return u3qe_cue(u3x_at(u3x_sam, cor)); -} - -u3_noun -u3ke_cue(u3_atom a) -{ - u3_noun b = u3qe_cue(a); - u3z(a); - return b; -} diff --git a/pkg/urbit/jets/e/ed_add_double_scalarmult.c b/pkg/urbit/jets/e/ed_add_double_scalarmult.c deleted file mode 100644 index e3f01950d..000000000 --- a/pkg/urbit/jets/e/ed_add_double_scalarmult.c +++ /dev/null @@ -1,47 +0,0 @@ -/* gen164/5/ed_add_double_scalarmult.c -** -*/ -#include "all.h" -#include - -/* functions -*/ - static u3_atom - _cqee_add_double_scalarmult(u3_atom a, - u3_atom b, - u3_atom c, - u3_atom d) - { - c3_y a_y[32], b_y[32], c_y[32], d_y[32], out_y[32]; - - if ( (0 != u3r_bytes_fit(32, a_y, a)) || - (0 != u3r_bytes_fit(32, b_y, b)) || - (0 != u3r_bytes_fit(32, c_y, c)) || - (0 != u3r_bytes_fit(32, d_y, d)) || - (0 != urcrypt_ed_add_double_scalarmult(a_y, b_y, c_y, d_y, out_y)) ) { - return u3_none; - } - else { - return u3i_bytes(32, out_y); - } - } - - u3_noun - u3wee_add_double_scalarmult(u3_noun cor) - { - u3_noun a, b, c, d; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, - u3x_sam_6, &b, - u3x_sam_14, &c, - u3x_sam_15, &d, 0)) || - (c3n == u3ud(a)) || - (c3n == u3ud(b)) || - (c3n == u3ud(c)) ) - { - return u3m_bail(c3__exit); - } else { - return u3l_punt("add-double-scalarmult", - _cqee_add_double_scalarmult(a, b, c, d)); - } - } diff --git a/pkg/urbit/jets/e/ed_add_scalarmult_scalarmult_base.c b/pkg/urbit/jets/e/ed_add_scalarmult_scalarmult_base.c deleted file mode 100644 index 26dd69994..000000000 --- a/pkg/urbit/jets/e/ed_add_scalarmult_scalarmult_base.c +++ /dev/null @@ -1,44 +0,0 @@ -/* gen164/5/ed_double_scalarmult.c -** -*/ -#include "all.h" -#include - -/* functions -*/ - static u3_atom - _cqee_add_scalarmult_scalarmult_base(u3_atom a, - u3_atom b, - u3_atom c) - { - c3_y a_y[32], b_y[32], c_y[32], out_y[32]; - - if ( (0 != u3r_bytes_fit(32, a_y, a)) || - (0 != u3r_bytes_fit(32, b_y, b)) || - (0 != u3r_bytes_fit(32, c_y, c)) || - (0 != urcrypt_ed_add_scalarmult_scalarmult_base(a_y, b_y, c_y, out_y)) ) { - return u3_none; - } - else { - return u3i_bytes(32, out_y); - } - } - - u3_noun - u3wee_add_scalarmult_scalarmult_base(u3_noun cor) - { - u3_noun a, b, c; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, - u3x_sam_6, &b, - u3x_sam_7, &c, 0)) || - (c3n == u3ud(a)) || - (c3n == u3ud(b)) || - (c3n == u3ud(c)) ) - { - return u3m_bail(c3__exit); - } else { - return u3l_punt("add-scalarmult-scalarmult-base", - _cqee_add_scalarmult_scalarmult_base(a, b, c)); - } - } diff --git a/pkg/urbit/jets/e/ed_point_add.c b/pkg/urbit/jets/e/ed_point_add.c deleted file mode 100644 index dfa52502e..000000000 --- a/pkg/urbit/jets/e/ed_point_add.c +++ /dev/null @@ -1,40 +0,0 @@ -/* gen164/5/ed_point_add.c -** -*/ -#include "all.h" -#include - -/* functions -*/ - - static u3_atom - _cqee_point_add(u3_atom a, - u3_atom b) - { - c3_y a_y[32], b_y[32], out_y[32]; - - if ( (0 != u3r_bytes_fit(32, a_y, a)) || - (0 != u3r_bytes_fit(32, b_y, b)) || - (0 != urcrypt_ed_point_add(a_y, b_y, out_y)) ) { - return u3_none; - } - else { - return u3i_bytes(32, out_y); - } - } - - u3_noun - u3wee_point_add(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, - u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) || - (c3n == u3ud(b)) ) - { - return u3m_bail(c3__exit); - } else { - return u3l_punt("point-add", _cqee_point_add(a, b)); - } - } diff --git a/pkg/urbit/jets/e/ed_puck.c b/pkg/urbit/jets/e/ed_puck.c deleted file mode 100644 index 436650e1a..000000000 --- a/pkg/urbit/jets/e/ed_puck.c +++ /dev/null @@ -1,36 +0,0 @@ -/* gen164/5/ed_puck.c -** -*/ -#include "all.h" -#include - -/* functions -*/ - static u3_atom - _cqee_puck(u3_atom sed) - { - c3_y sed_y[32]; - - if ( 0 != u3r_bytes_fit(32, sed_y, sed) ) { - // hoon explicitly crashes on mis-size - return u3m_bail(c3__exit); - } - else { - c3_y pub_y[32]; - urcrypt_ed_puck(sed_y, pub_y); - return u3i_bytes(32, pub_y); - } - } - - u3_noun - u3wee_puck(u3_noun cor) - { - u3_noun a = u3r_at(u3x_sam, cor); - - if ( (u3_none == a) || (c3n == u3ud(a)) ) { - return u3m_bail(c3__exit); - } - else { - return _cqee_puck(a); - } - } diff --git a/pkg/urbit/jets/e/ed_scalarmult.c b/pkg/urbit/jets/e/ed_scalarmult.c deleted file mode 100644 index 136d51af2..000000000 --- a/pkg/urbit/jets/e/ed_scalarmult.c +++ /dev/null @@ -1,40 +0,0 @@ -/* gen164/5/ed_scalarmult.c -** -*/ -#include "all.h" -#include "urcrypt.h" - -/* functions -*/ - static u3_atom - _cqee_scalarmult(u3_atom a, - u3_atom b) - { - c3_y a_y[32], b_y[32], out_y[32]; - - if ( (0 != u3r_bytes_fit(32, a_y, a)) || - (0 != u3r_bytes_fit(32, b_y, b)) || - (0 != urcrypt_ed_scalarmult(a_y, b_y, out_y)) ) { - // hoon does not check size of inputs - return u3_none; - } - else { - return u3i_bytes(32, out_y); - } - } - - u3_noun - u3wee_scalarmult(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, - u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) || - (c3n == u3ud(b)) ) - { - return u3m_bail(c3__exit); - } else { - return u3l_punt("scalarmult", _cqee_scalarmult(a, b)); - } - } diff --git a/pkg/urbit/jets/e/ed_scalarmult_base.c b/pkg/urbit/jets/e/ed_scalarmult_base.c deleted file mode 100644 index 965ba8b22..000000000 --- a/pkg/urbit/jets/e/ed_scalarmult_base.c +++ /dev/null @@ -1,35 +0,0 @@ -/* gen164/5/ed_scalarmult_base.c -** -*/ -#include "all.h" -#include - -/* functions -*/ - static u3_atom - _cqee_scalarmult_base(u3_atom a) - { - c3_y a_y[32]; - - if ( 0 != u3r_bytes_fit(32, a_y, a) ) { - return u3_none; - } - else { - c3_y out_y[32]; - urcrypt_ed_scalarmult_base(a_y, out_y); - return u3i_bytes(32, out_y); - } - } - - u3_noun - u3wee_scalarmult_base(u3_noun cor) - { - u3_noun a = u3r_at(u3x_sam, cor); - - if ( (u3_none == a) || (c3n == u3ud(a)) ) { - return u3m_bail(c3__exit); - } - else { - return u3l_punt("scalarmult-base", _cqee_scalarmult_base(a)); - } - } diff --git a/pkg/urbit/jets/e/ed_shar.c b/pkg/urbit/jets/e/ed_shar.c deleted file mode 100644 index e26b0627c..000000000 --- a/pkg/urbit/jets/e/ed_shar.c +++ /dev/null @@ -1,40 +0,0 @@ -/* j/5/shar.c -** -*/ -#include "all.h" -#include - - static u3_atom - _cqee_shar(u3_atom pub, u3_atom sek) - { - c3_y pub_y[32], sek_y[32]; - - if ( 0 != u3r_bytes_fit(32, pub_y, pub) ) { - // pub is not size checked in the hoon - return u3_none; - } - else if ( 0 != u3r_bytes_fit(32, sek_y, sek) ) { - // sek explicitly bails through suck - return u3m_bail(c3__exit); - } - else { - c3_y shr_y[32]; - urcrypt_ed_shar(pub_y, sek_y, shr_y); - return u3i_bytes(32, shr_y); - } - } - - u3_noun - u3wee_shar(u3_noun cor) - { - u3_noun pub, sek; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &pub, u3x_sam_3, &sek, 0)) || - (c3n == u3ud(pub)) || - (c3n == u3ud(sek)) ) - { - return u3m_bail(c3__exit); - } else { - return u3l_punt("shar", _cqee_shar(pub, sek)); - } - } diff --git a/pkg/urbit/jets/e/ed_sign.c b/pkg/urbit/jets/e/ed_sign.c deleted file mode 100644 index 09fd317d0..000000000 --- a/pkg/urbit/jets/e/ed_sign.c +++ /dev/null @@ -1,41 +0,0 @@ -/* gen164/5/ed_sign.c -** -*/ -#include "all.h" -#include - -/* functions -*/ - static u3_atom - _cqee_sign(u3_noun a, - u3_noun b) - { - c3_y sed_y[32]; - - if ( 0 != u3r_bytes_fit(32, sed_y, b) ) { - // hoon calls suck, which calls puck, which crashes - return u3m_bail(c3__exit); - } - else { - c3_y sig_y[64]; - c3_w met_w; - c3_y* mes_y = u3r_bytes_all(&met_w, a); - - urcrypt_ed_sign(mes_y, met_w, sed_y, sig_y); - u3a_free(mes_y); - - return u3i_bytes(64, sig_y); - } - } - - u3_noun - u3wee_sign(u3_noun cor) - { - u3_noun a, b; - if ( c3n == u3r_mean(cor, - u3x_sam_2, &a, u3x_sam_3, &b, 0) ) { - return u3m_bail(c3__fail); - } else { - return _cqee_sign(a, b); - } - } diff --git a/pkg/urbit/jets/e/ed_veri.c b/pkg/urbit/jets/e/ed_veri.c deleted file mode 100644 index 51ac20c13..000000000 --- a/pkg/urbit/jets/e/ed_veri.c +++ /dev/null @@ -1,42 +0,0 @@ -/* gen164/5/ed_veri.c -** -*/ -#include "all.h" -#include - -/* functions -*/ - static u3_atom - _cqee_veri(u3_noun s, - u3_noun m, - u3_noun pk) - { - c3_y sig_y[64], pub_y[32]; - - if ( (0 != u3r_bytes_fit(64, sig_y, s)) || - (0 != u3r_bytes_fit(32, pub_y, pk)) ) { - // hoon checks sizes, but weirdly and without crashes - return u3_none; - } - else { - c3_w met_w; - c3_y* mes_y = u3r_bytes_all(&met_w, m); - c3_t val_t = urcrypt_ed_veri(mes_y, met_w, pub_y, sig_y); - u3a_free(mes_y); - - return val_t ? c3y : c3n; - } - } - - u3_noun - u3wee_veri(u3_noun cor) - { - u3_noun a, b, c; - if ( c3n == u3r_mean(cor, - u3x_sam_2, &a, u3x_sam_6, &b, - u3x_sam_7, &c, 0) ) { - return u3m_bail(c3__fail); - } else { - return u3l_punt("veri", _cqee_veri(a, b, c)); - } - } diff --git a/pkg/urbit/jets/e/fein_ob.c b/pkg/urbit/jets/e/fein_ob.c deleted file mode 100644 index 80e113512..000000000 --- a/pkg/urbit/jets/e/fein_ob.c +++ /dev/null @@ -1,88 +0,0 @@ -/* j/3/fein.c -** -*/ -#include "all.h" -#include - -// +feis:ob constant parameters to +fe:ob -// -static const c3_w a_w = 0xffff; -static const c3_w b_w = 0x10000; -static const c3_w k_w = 0xffff0000; - -// +raku:ob -// -static const c3_w rak_w[4] = { 0xb76d5eed, 0xee281300, 0x85bcae01, 0x4b387af7 }; - -/* _fe_ob(): +fe:ob, with constant parameters factored out. -** correct over the domain [0x0, 0xfffe.ffff] -*/ -static c3_w -_fe_ob(c3_w m_w) -{ - c3_w l_w = m_w % a_w; - c3_w r_w = m_w / a_w; - c3_w f_w, t_w; - c3_y j_y, k_y[2]; - - for ( j_y = 0; j_y < 4; j_y++ ) { - k_y[0] = r_w & 0xff; - k_y[1] = (r_w >> 8) & 0xff; - - MurmurHash3_x86_32(k_y, 2, rak_w[j_y], &f_w); - - // NB: this addition can overflow a c3_w (before mod) - // - t_w = ((c3_d)f_w + l_w) % (!(j_y & 1) ? a_w : b_w); - l_w = r_w; - r_w = t_w; - } - - // legendary @max19 - // - return ( a_w == r_w ) - ? (r_w * a_w) + l_w - : (l_w * a_w) + r_w; -} - -/* _feis_ob(): +feis:ob, also offsetting by 0x1.000 (as in +fein:ob). -** correct over the domain [0x1.0000, 0xffff.ffff] -*/ -static c3_w -_feis_ob(c3_w m_w) -{ - c3_w c_w = _fe_ob(m_w - b_w); - return b_w + (( c_w < k_w ) ? c_w : _fe_ob(c_w)); -} - -u3_atom -u3qe_fein_ob(u3_atom pyn) -{ - c3_w sor_w = u3r_met(4, pyn); - - if ( (sor_w < 2) || (sor_w > 4) ) { - return u3k(pyn); - } - - if ( 2 == sor_w ) { - return u3i_word(_feis_ob(u3r_word(0, pyn))); - } - else { - c3_w pyn_w[2]; - u3r_words(0, 2, pyn_w, pyn); - - if ( pyn_w[0] < b_w ) { - return u3k(pyn); - } - else { - pyn_w[0] = _feis_ob(pyn_w[0]); - return u3i_words(2, pyn_w); - } - } -} - -u3_noun -u3we_fein_ob(u3_noun cor) -{ - return u3qe_fein_ob(u3x_atom(u3x_at(u3x_sam, cor))); -} diff --git a/pkg/urbit/jets/e/fl.c b/pkg/urbit/jets/e/fl.c deleted file mode 100644 index 5b759dd27..000000000 --- a/pkg/urbit/jets/e/fl.c +++ /dev/null @@ -1,441 +0,0 @@ -/* j/e/fl.c -** -*/ -#include "all.h" - -/* structures -*/ - typedef struct _flOptions { - c3_w precision; - mpz_t minExp; - mpz_t expWidth; - c3_w rMode; - c3_w eMode; - } flOptions; - - typedef struct _ea { - mpz_t e; - mpz_t a; - } ea; - -/* functions -*/ - static void - _satom_to_mp(mpz_t a_mp, - u3_atom b) - { - if ( _(u3a_is_cat(b)) ) { - c3_ws c = (b + 1) >> 1; - if ( (b & 1) ) { - c = -c; - } - mpz_init_set_si(a_mp, c); - } - else { - u3r_mp(a_mp, b); - c3_t x = mpz_odd_p(a_mp); - mpz_add_ui(a_mp, a_mp, 1); - mpz_tdiv_q_2exp(a_mp, a_mp, 1); - if ( x ) { - mpz_neg(a_mp, a_mp); - } - } - } - - static u3_noun - _mp_to_satom(mpz_t a_mp) - { - c3_ws b = mpz_sgn(a_mp); - switch ( b ) { - default: return u3m_bail(c3__fail); - case 0: { - mpz_clear(a_mp); - return 0; - } - case 1: { - mpz_mul_2exp(a_mp, a_mp, 1); - return u3i_mp(a_mp); - } - case -1: { - mpz_abs(a_mp, a_mp); - mpz_mul_2exp(a_mp, a_mp, 1); - mpz_sub_ui(a_mp, a_mp, 1); - return u3i_mp(a_mp); - } - } - } - - static void - _noun_to_flOptions(flOptions* a, - u3_noun b) - { - u3_noun c; - u3_atom d, e, f, g, h; - u3x_trel(b, &c, &d, &e); - u3x_trel(c, &f, &g, &h); - - mpz_t i; - u3r_mp(i, f); - if ( !mpz_fits_uint_p(i) ) { - mpz_clear(i); - u3m_bail(c3__exit); - } - a->precision = mpz_get_ui(i); - mpz_clear(i); - - if ( a->precision < 2 ) u3m_bail(c3__exit); - - _satom_to_mp(a->minExp, g); - u3r_mp(a->expWidth, h); - - if ( !(_(u3a_is_cat(d)) && _(u3a_is_cat(e))) ) { - mpz_clear(a->minExp); - mpz_clear(a->expWidth); - u3m_bail(c3__exit); - } - a->rMode = d; - a->eMode = e; - } - - static void - _noun_to_ea(ea* a, - u3_noun b) - { - u3_atom c, d; - u3x_cell(b, &c, &d); - - if ( !(_(u3a_is_cat(c))) ) { - u3m_bail(c3__exit); - } - - _satom_to_mp(a->e, c); - u3r_mp(a->a, d); - } - - static u3_noun - _ea_to_noun(ea* a) - { - u3_atom b = _mp_to_satom(a->e); - u3_atom c = u3i_mp(a->a); - - return u3nc(b, c); - } - - static void - _xpd(ea* a, - flOptions* b) - { - size_t z = mpz_sizeinbase(a->a, 2); - if ( z >= b->precision ) return; - c3_w c = b->precision - z; - - if ( b->eMode != c3__i ) { - mpz_t i; - mpz_init_set(i, a->e); - mpz_sub(i, i, b->minExp); - if ( mpz_sgn(i) < 0 ) { - c = 0; - } - else if ( mpz_fits_uint_p(i) ) - { - c3_w d = mpz_get_ui(i); - c = c3_min(c, d); - } - mpz_clear(i); - } - - mpz_mul_2exp(a->a, a->a, c); - mpz_sub_ui(a->e, a->e, c); - } - - /* a: floating point number, b: flOptions, i: rounding mode, j: sticky bit */ - u3_noun - u3qef_lug(u3_noun a, - u3_noun b, - u3_atom i, - u3_atom j) - { - mpz_t v, g, h; - ea c; - flOptions d; - _noun_to_ea(&c, a); - _noun_to_flOptions(&d, b); - if ( mpz_sgn(c.a) == 0 ) { - mpz_clear(d.minExp); mpz_clear(d.expWidth); - mpz_clear(c.a); mpz_clear(c.e); - return u3m_bail(c3__exit); - } - size_t m = mpz_sizeinbase(c.a, 2); - if ( !_(j) && (m <= d.precision) ) { - mpz_clear(d.minExp); mpz_clear(d.expWidth); - mpz_clear(c.a); mpz_clear(c.e); - return u3m_bail(c3__exit); - } - c3_w q = 0; - c3_w f = (m > d.precision) ? m - d.precision : 0; - mpz_init(g); - if ( (d.eMode != c3__i) && - (mpz_cmp(c.e, d.minExp) < 0) ) { - mpz_sub(g, d.minExp, c.e); - if ( !mpz_fits_uint_p(g) ) { - mpz_clear(g); - mpz_clear(d.minExp); mpz_clear(d.expWidth); - mpz_clear(c.a); mpz_clear(c.e); - return u3m_bail(c3__exit); - } - q = mpz_get_ui(g); - } - q = c3_max(f, q); - mpz_init(v); - mpz_tdiv_r_2exp(v, c.a, q); - mpz_tdiv_q_2exp(c.a, c.a, q); - mpz_add_ui(c.e, c.e, q); - mpz_init_set_ui(h, 1); - if ( q > 0 ) mpz_mul_2exp(h, h, q - 1); - - if ( mpz_sgn(c.a) == 0 ) { - c3_t y; - switch ( i ) { - default: - mpz_clear(v); mpz_clear(h); mpz_clear(g); - mpz_clear(d.minExp); mpz_clear(d.expWidth); - mpz_clear(c.a); mpz_clear(c.e); - return u3m_bail(c3__exit); - case c3__fl: - case c3__sm: - mpz_set_ui(c.a, 0); - mpz_set_ui(c.e, 0); - mpz_clear(v); mpz_clear(h); mpz_clear(g); - break; - case c3__ce: - case c3__lg: - mpz_set_ui(c.a, 1); - mpz_set(c.e, d.minExp); - mpz_clear(v); mpz_clear(h); mpz_clear(g); - break; - case c3__ne: - case c3__nt: - case c3__na: - if ( (i != c3__na) && _(j) ) { - y = (mpz_cmp(v, h) <= 0); - } else { - y = (mpz_cmp(v, h) < 0); - } - if ( y ) { - mpz_set_ui(c.a, 0); - mpz_set_ui(c.e, 0); - } else { - mpz_set_ui(c.a, 1); - mpz_set(c.e, d.minExp); - } - mpz_clear(v); mpz_clear(h); mpz_clear(g); - break; - } - goto end; - } - _xpd(&c, &d); - switch ( i ) { - c3_ws x; - default: - mpz_clear(v); mpz_clear(h); mpz_clear(g); - mpz_clear(d.minExp); mpz_clear(d.expWidth); - mpz_clear(c.a); mpz_clear(c.e); - return u3m_bail(c3__exit); - case c3__fl: - break; - case c3__lg: - mpz_add_ui(c.a, c.a, 1); - break; - case c3__sm: - if ( (mpz_sgn(v) != 0) || !_(j) ) break; - if ( (mpz_cmp(c.e, d.minExp) == 0) && (d.eMode != c3__i) ) { - mpz_sub_ui(c.a, c.a, 1); - break; - } - mpz_mul_2exp(g, c.a, 1); - mpz_sub_ui(g, g, 1); - if ( mpz_sizeinbase(g, 2) <= d.precision ) { - mpz_sub_ui(c.e, c.e, 1); - mpz_set(c.a, g); - } else { - mpz_sub_ui(c.a, c.a, 1); - } - break; - case c3__ce: - if ( (mpz_sgn(v) != 0) || !_(j) ) { - mpz_add_ui(c.a, c.a, 1); - } - break; - case c3__ne: - if ( mpz_sgn(v) == 0 ) break; - x = mpz_cmp(v, h); - if ( (x == 0) && _(j) ) { - if ( mpz_odd_p(c.a) ) { - mpz_add_ui(c.a, c.a, 1); - } - } - else if ( x >= 0 ) { - mpz_add_ui(c.a, c.a, 1); - } - break; - case c3__na: - case c3__nt: - if ( mpz_sgn(v) == 0 ) break; - x = mpz_cmp(v, h); - if ( (x < 0) ) break; - if ( (i == c3__nt) && (x == 0) ) { - if (!_(j)) mpz_add_ui(c.a, c.a, 1); - } else { - mpz_add_ui(c.a, c.a, 1); - } - break; - } - if ( mpz_sizeinbase(c.a, 2) == (d.precision + 1) ) { - mpz_tdiv_q_2exp(c.a, c.a, 1); - mpz_add_ui(c.e, c.e, 1); - } - if ( mpz_sgn(c.a) == 0 ) { - mpz_set_ui(c.e, 0); - mpz_clear(v); mpz_clear(h); mpz_clear(g); - goto end; - } - mpz_set(g, d.minExp); - mpz_add(g, g, d.expWidth); - if ( (d.eMode != c3__i) && (mpz_cmp(g, c.e) < 0) ) { - mpz_clear(v); mpz_clear(h); mpz_clear(g); - mpz_clear(d.minExp); mpz_clear(d.expWidth); - mpz_clear(c.a); mpz_clear(c.e); - return u3nc(c3__i, c3y); - } - mpz_clear(v); mpz_clear(h); mpz_clear(g); - - // all mpz except in c, d structures cleared; c contains result - end: - if ( d.eMode == c3__f ) { - if ( mpz_sizeinbase(c.a, 2) != d.precision ) { - mpz_set_ui(c.a, 0); - mpz_set_ui(c.e, 0); - } - } - u3_noun ret = u3nq(c3__f, c3y, _mp_to_satom(c.e), u3i_mp(c.a)); - mpz_clear(d.minExp); mpz_clear(d.expWidth); - return ret; - } - - u3_noun - u3wef_lug(u3_noun cor) - { - u3_noun a, b, c, d, e; - a = u3x_at(u3x_sam, cor); - b = u3x_at(30, cor); - u3x_trel(a, &c, &d, &e); - - return u3qef_lug(d, b, c, e); - } - - u3_noun - u3qef_drg(u3_noun a, - u3_noun b) - { - ea c; - flOptions d; - _noun_to_ea(&c, a); - _noun_to_flOptions(&d, b); - if ( mpz_sgn(c.a) == 0 ) { - mpz_clear(d.minExp); mpz_clear(d.expWidth); - mpz_clear(c.a); mpz_clear(c.e); - u3m_bail(c3__exit); - } - _xpd(&c, &d); - if ( !mpz_fits_sint_p(c.e) ) { - mpz_clear(d.minExp); mpz_clear(d.expWidth); - mpz_clear(c.a); mpz_clear(c.e); - u3m_bail(c3__exit); - } - mpz_t r, s, mn, mp, i, j, u, o; - mpz_init_set(r, c.a); - mpz_init_set_ui(s, 1); - mpz_init_set_ui(mn, 1); - mpz_init(i); - mpz_init(j); - c3_w se = mpz_sgn(c.e); - if ( se == 1 ) { - mpz_mul_2exp(r, r, mpz_get_ui(c.e)); - mpz_mul_2exp(mn, mn, mpz_get_ui(c.e)); - } - else if ( se == -1 ) { - mpz_mul_2exp(s, s, mpz_get_ui(c.e)); - } - mpz_init_set(mp, mn); - mpz_set_ui(i, 1); - mpz_mul_2exp(i, i, d.precision - 1); - if ( (mpz_cmp(c.a, i) == 0) && - ((mpz_cmp(c.e, d.minExp) != 0 ) || - (d.eMode == c3__i)) ) { - mpz_mul_2exp(mp, mp, 1); - mpz_mul_2exp(r, r, 1); - mpz_mul_2exp(s, s, 1); - } - mpz_cdiv_q_ui(i, s, 10); - mpz_set_ui(c.e, 0); - while ( mpz_cmp(r, i) < 0 ) { - mpz_sub_ui(c.e, c.e, 1); - mpz_mul_ui(r, r, 10); - mpz_mul_ui(mn, mn, 10); - mpz_mul_ui(mp, mp, 10); - } - while ( 1 ) { - mpz_mul_2exp(i, r, 1); - mpz_add(i, i, mp); - mpz_mul_2exp(j, s, 1); - if ( mpz_cmp(i, j) < 0 ) { - break; - } - mpz_mul_ui(s, s, 10); - mpz_add_ui(c.e, c.e, 1); - } - mpz_init(u); - mpz_init_set_ui(o, 0); - while ( 1 ) { - mpz_sub_ui(c.e, c.e, 1); - mpz_mul_ui(r, r, 10); - mpz_mul_ui(mn, mn, 10); - mpz_mul_ui(mp, mp, 10); - mpz_tdiv_qr(u, r, r, s); - mpz_mul_2exp(i, r, 1); - mpz_mul_2exp(j, s, 1); - c3_t l = mpz_cmp(i, mn) < 0; - c3_t h = mpz_cmp(j, mp) < 0; - if ( !h ) { - mpz_sub(j, j, mp); - h = mpz_cmp(i, j) > 0; - } - if ( l || h ) { - mpz_mul_ui(o, o, 10); - mpz_add(o, o, u); - if ( h && (!l || (mpz_cmp(i, s) > 0)) ) { - mpz_add_ui(o, o, 1); - } - break; - } - mpz_mul_ui(o, o, 10); - mpz_add(o, o, u); - } - mpz_set(c.a, o); - mpz_clear(r); mpz_clear(s); - mpz_clear(mn); mpz_clear(mp); - mpz_clear(i); mpz_clear(j); mpz_clear(u); - mpz_clear(o); mpz_clear(d.minExp); mpz_clear(d.expWidth); - - return _ea_to_noun(&c); - } - - u3_noun - u3wef_drg(u3_noun cor) - { - u3_noun a, b; - a = u3x_at(u3x_sam, cor); - b = u3x_at(30, cor); - - return u3qef_drg(a, b); - } diff --git a/pkg/urbit/jets/e/fynd_ob.c b/pkg/urbit/jets/e/fynd_ob.c deleted file mode 100644 index 203d94f4d..000000000 --- a/pkg/urbit/jets/e/fynd_ob.c +++ /dev/null @@ -1,92 +0,0 @@ -/* j/3/fein.c -** -*/ -#include "all.h" -#include - -// +tail:ob constant parameters to +fe:ob -// -static const c3_w a_w = 0xffff; -static const c3_w b_w = 0x10000; -static const c3_w k_w = 0xffff0000; - -// (flop raku:ob) -// -static const c3_w kar_w[4] = { 0x4b387af7, 0x85bcae01, 0xee281300, 0xb76d5eed }; - -/* _fen_ob(): +fen:ob, with constant parameters factored out. -** correct over the domain [0x0 ... 0xfffe.ffff] -*/ -static c3_w -_fen_ob(c3_w m_w) -{ - c3_w l_w = m_w / a_w; - c3_w r_w = m_w % a_w; - c3_w f_w, t_w; - c3_y j_y, k_y[2]; - - // legendary @max19 - // - if ( a_w == l_w ) { - t_w = l_w; - l_w = r_w; - r_w = t_w; - } - - for ( j_y = 0; j_y < 4; j_y++ ) { - k_y[0] = l_w & 0xff; - k_y[1] = (l_w >> 8) & 0xff; - - MurmurHash3_x86_32(k_y, 2, kar_w[j_y], &f_w); - - t_w = ( j_y & 1 ) - ? ((r_w + a_w) - (f_w % a_w)) % a_w - : ((r_w + b_w) - (f_w % b_w)) % b_w; - r_w = l_w; - l_w = t_w; - } - - return (r_w * a_w) + l_w; -} - -/* _tail_ob(): +feis:ob, also offsetting by 0x1.000 (as in +fynd:ob). -** correct over the domain [0x1.0000, 0xffff.ffff] -*/ -static c3_w -_tail_ob(c3_w m_w) -{ - c3_w c_w = _fen_ob(m_w - b_w); - return b_w + (( c_w < k_w ) ? c_w : _fen_ob(c_w)); -} - -u3_atom -u3qe_fynd_ob(u3_atom pyn) -{ - c3_w sor_w = u3r_met(4, pyn); - - if ( (sor_w < 2) || (sor_w > 4) ) { - return u3k(pyn); - } - - if ( 2 == sor_w ) { - return u3i_word(_tail_ob(u3r_word(0, pyn))); - } - else { - c3_w pyn_w[2]; - u3r_words(0, 2, pyn_w, pyn); - - if ( pyn_w[0] < b_w ) { - return u3k(pyn); - } - else { - pyn_w[0] = _tail_ob(pyn_w[0]); - return u3i_words(2, pyn_w); - } - } -} - -u3_noun -u3we_fynd_ob(u3_noun cor) -{ - return u3qe_fynd_ob(u3x_atom(u3x_at(u3x_sam, cor))); -} diff --git a/pkg/urbit/jets/e/hmac.c b/pkg/urbit/jets/e/hmac.c deleted file mode 100644 index 8585f57d7..000000000 --- a/pkg/urbit/jets/e/hmac.c +++ /dev/null @@ -1,93 +0,0 @@ -/* j/5/hmac.c -** -*/ -#include "all.h" - -/* functions -*/ - - u3_noun - u3qe_hmac(u3_noun haj, - u3_atom boq, - u3_atom out, - u3_atom wik, - u3_atom key, - u3_atom wid, - u3_atom dat) - { - c3_assert(_(u3a_is_cat(boq)) && _(u3a_is_cat(wik)) && _(u3a_is_cat(wid))); - - // prep the hashing gate - u3j_site sit_u; - u3j_gate_prep(&sit_u, u3k(haj)); - - // ensure key and message fit signaled lengths - key = u3qc_end(3, wik, key); - dat = u3qc_end(3, wid, dat); - - // keys longer than block size are shortened by hashing - if (wik > boq) { - key = u3j_gate_slam(&sit_u, u3nc(wik, key)); - wik = out; - } - - // keys shorter than block size are right-padded - if (wik < boq) { - key = u3kc_lsh(3, (boq - wik), key); - } - - // pad key, inner and outer - c3_y trail = (boq % 4); - c3_y padwords = (boq / 4) + (trail == 0 ? 0 : 1); - c3_w innpad[padwords], outpad[padwords]; - memset(innpad, 0x36, padwords * 4); - memset(outpad, 0x5c, padwords * 4); - if ( trail > 0 ) { - innpad[padwords-1] = 0x36363636 >> (8 * (4 - trail)); - outpad[padwords-1] = 0x5c5c5c5c >> (8 * (4 - trail)); - } - u3_atom innkey = u3kc_mix(u3k(key), u3i_words(padwords, innpad)); - u3_atom outkey = u3kc_mix( key , u3i_words(padwords, outpad)); - - // append inner padding to message, then hash - u3_atom innmsg = u3ka_add(u3kc_lsh(3, wid, innkey), dat); - u3_atom innhaj = u3j_gate_slam(&sit_u, u3nc((wid + boq), innmsg)); - - // prepend outer padding to result, hash again - u3_atom outmsg = u3ka_add(u3kc_lsh(3, out, outkey), innhaj); - u3_atom outhaj = u3j_gate_slam(&sit_u, u3nc((out + boq), outmsg)); - - u3j_gate_lose(&sit_u); - return outhaj; - } - - u3_noun - u3we_hmac(u3_noun cor) - { - u3_noun haj, boq, out, wik, key, wid, dat; - - // sample is [[haj boq out] [wik key] [wid dat]] - if ( (c3n == u3r_mean(cor, u3x_sam_4, &haj, - 50, &boq, // +<->- - 51, &out, // +<->+ - u3x_sam_12, &wik, - u3x_sam_13, &key, - u3x_sam_14, &wid, - u3x_sam_15, &dat, 0)) || - (c3n == u3ud(boq)) || - (c3n == u3a_is_cat(boq)) || - (c3n == u3ud(out)) || - (c3n == u3a_is_cat(out)) || - (c3n == u3ud(wik)) || - (c3n == u3a_is_cat(wik)) || - (c3n == u3ud(key)) || - (c3n == u3ud(wid)) || - (c3n == u3a_is_cat(wid)) || - (c3n == u3ud(dat)) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qe_hmac(haj, boq, out, wik, key, wid, dat); - } - } diff --git a/pkg/urbit/jets/e/jam.c b/pkg/urbit/jets/e/jam.c deleted file mode 100644 index 4848cc4ae..000000000 --- a/pkg/urbit/jets/e/jam.c +++ /dev/null @@ -1,57 +0,0 @@ -/* j/5/jam.c -** -*/ -#include "all.h" - -u3_noun -u3qe_jam(u3_atom a) -{ -#if 0 - if (c3y == u3du(a) && 1337 == u3h(a)) { - c3_w siz_w, tot_w = 0; - u3_noun som; - for ( som = u3t(a); c3y == u3du(som); som = u3t(som) ) { - siz_w = u3a_count_noun(u3h(som)); - tot_w += siz_w; - if ( 0 == siz_w ) { - u3l_log("item: B/0"); - } - else { - u3a_print_memory(stderr, "item", siz_w); - } - } - if ( u3_blip != som ) { - u3l_log("forgot to terminate list!"); - } - c3_w mem_w = u3h_count(u3R->cax.har_p); - - for ( som = u3t(a); c3y == u3du(som); som = u3t(som) ) u3a_discount_noun(u3h(som)); - u3h_discount(u3R->cax.har_p); - - u3a_print_memory(stderr, "total", tot_w); - u3a_print_memory(stderr, "memoization cache", mem_w); - u3h_root* har_u = u3to(u3h_root, u3R->cax.har_p); - u3l_log("memoization entries: %d", har_u->use_w); - u3a_print_memory(stderr, "unused free", u3a_open(u3R)); - return tot_w; - } -#endif - - u3i_slab sab_u; - u3s_jam_fib(&sab_u, a); - return u3i_slab_mint(&sab_u); -} - -u3_noun -u3we_jam(u3_noun cor) -{ - return u3qe_jam(u3x_at(u3x_sam, cor)); -} - -u3_atom -u3ke_jam(u3_noun a) -{ - u3_atom b = u3qe_jam(a); - u3z(a); - return b; -} diff --git a/pkg/urbit/jets/e/keccak.c b/pkg/urbit/jets/e/keccak.c deleted file mode 100644 index 236780593..000000000 --- a/pkg/urbit/jets/e/keccak.c +++ /dev/null @@ -1,39 +0,0 @@ -/* jets/e/keccak.c -*/ -#include "all.h" -#include - -#define defw(bits,byts) \ - u3_atom \ - _kecc_##bits(c3_w len_w, u3_atom a) \ - { \ - c3_y out[byts]; \ - c3_y* buf_y = u3r_bytes_alloc(0, len_w, a); \ - if ( 0 != urcrypt_keccak_##bits(buf_y, len_w, out) ) { \ - /* urcrypt_keccac_##bits always succeeds when called correctly */ \ - return u3m_bail(c3__oops); \ - } \ - else { \ - u3_atom pro = u3i_bytes(byts, out); \ - u3a_free(buf_y); \ - return pro; \ - } \ - } \ - \ - u3_weak \ - u3we_kecc##bits(u3_noun cor) \ - { \ - c3_w len_w; \ - u3_noun len, tom; \ - u3x_mean(cor, u3x_sam_2, &len, u3x_sam_3, &tom, 0); \ - return ( (c3n == u3ud(len)) || (c3n == u3ud(tom)) ) \ - ? u3m_bail(c3__exit) \ - : (!u3r_word_fit(&len_w, len)) \ - ? u3m_bail(c3__fail) \ - : _kecc_##bits(len_w, tom); \ - } - -defw(224, 28) -defw(256, 32) -defw(384, 48) -defw(512, 64) diff --git a/pkg/urbit/jets/e/leer.c b/pkg/urbit/jets/e/leer.c deleted file mode 100644 index a880f69be..000000000 --- a/pkg/urbit/jets/e/leer.c +++ /dev/null @@ -1,128 +0,0 @@ -/* j/5/leer.c -** -*/ -#include "all.h" - -static u3_atom -_leer_cut(c3_w pos_w, c3_w len_w, u3_atom src) -{ - if ( 0 == len_w ) { - return 0; - } - else { - u3i_slab sab_u; - u3i_slab_bare(&sab_u, 3, len_w); - sab_u.buf_w[sab_u.len_w - 1] = 0; - - u3r_bytes(pos_w, len_w, sab_u.buf_y, src); - - return u3i_slab_mint_bytes(&sab_u); - } -} - -// Leaving the lore jet in place for backwards compatibility. -// TODO: remove u3[qw]e_lore (also from jet tree) - -u3_noun -u3qe_lore(u3_atom lub) -{ - c3_w len_w = u3r_met(3, lub); - c3_w pos_w = 0; - u3_noun tez = u3_nul; - - while ( 1 ) { - c3_w meg_w = 0; - c3_y end_y; - - c3_y byt_y; - while ( 1 ) { - if ( pos_w >= len_w ) { - byt_y = 0; - end_y = c3y; - break; - } - byt_y = u3r_byte(pos_w + meg_w, lub); - - if ( (10 == byt_y) || (0 == byt_y) ) { - end_y = __(byt_y == 0); - break; - } else meg_w++; - } - - if ((byt_y == 0) && ((pos_w + meg_w + 1) < len_w)) { - return u3m_bail(c3__exit); - } - - if ( !_(end_y) && pos_w >= len_w ) { - return u3kb_flop(tez); - } - else { - tez = u3nc(_leer_cut(pos_w, meg_w, lub), tez); - if ( _(end_y) ) { - return u3kb_flop(tez); - } - pos_w += (meg_w + 1); - } - } -} - -u3_noun -u3we_lore(u3_noun cor) -{ - u3_noun lub; - - if ( (u3_none == (lub = u3r_at(u3x_sam, cor))) || - (c3n == u3ud(lub)) ) - { - return u3m_bail(c3__fail); - } else { - return u3qe_lore(lub); - } -} - -u3_noun -u3qe_leer(u3_atom txt) -{ - u3_noun pro; - u3_noun* lit = &pro; - - { - c3_w pos_w, i_w = 0, len_w = u3r_met(3, txt); - u3_noun* hed; - u3_noun* tel; - - while ( i_w < len_w ) { - // scan till end or newline - // - for ( pos_w = i_w; i_w < len_w; ++i_w ) { - if ( 10 == u3r_byte(i_w, txt) ) { - break; - } - } - - // append to list - // - *lit = u3i_defcons(&hed, &tel); - *hed = _leer_cut(pos_w, i_w - pos_w, txt); - lit = tel; - - i_w++; - } - } - - *lit = u3_nul; - - return pro; -} - -u3_noun -u3we_leer(u3_noun cor) -{ - u3_noun txt = u3x_at(u3x_sam, cor); - - if ( c3n == u3ud(txt) ) { - return u3m_bail(c3__fail); - } - - return u3qe_leer(txt); -} diff --git a/pkg/urbit/jets/e/loss.c b/pkg/urbit/jets/e/loss.c deleted file mode 100644 index 6f581c0ae..000000000 --- a/pkg/urbit/jets/e/loss.c +++ /dev/null @@ -1,296 +0,0 @@ -/* j/5/loss.c -** -*/ -#include "all.h" - - -/* functions -*/ - typedef struct _u3_loss { // loss problem - u3_noun hel; // a as a list - c3_w lel_w; // length of a - c3_w lev_w; // length of b - u3_noun* hev; // b as an array - u3_noun sev; // b as a set of lists - c3_w kct_w; // candidate count - u3_noun* kad; // candidate array - } u3_loss; - - // free loss object - // - static void - _flem(u3_loss* loc_u) - { - u3z(loc_u->sev); - { - c3_w i_w; - - for ( i_w = 0; i_w < loc_u->kct_w; i_w++ ) { - u3z(loc_u->kad[i_w]); - } - } - u3a_free(loc_u->hev); - u3a_free(loc_u->kad); - } - - // extract lcs - XX don't use the stack like this - // - static u3_noun - _lext(u3_loss* loc_u, - u3_noun kad) - { - if ( u3_nul == kad ) { - return u3_nul; - } else { - return u3nc(u3k(loc_u->hev[u3r_word(0, u3h(kad))]), - _lext(loc_u, u3t(kad))); - } - } - - // extract lcs - // - static u3_noun - _lexs(u3_loss* loc_u) - { - if ( 0 == loc_u->kct_w ) { - return u3_nul; - } else return u3kb_flop(_lext(loc_u, loc_u->kad[loc_u->kct_w - 1])); - } - - // initialize loss object - // - static void - _lemp(u3_loss* loc_u, - u3_noun hel, - u3_noun hev) - { - loc_u->hel = hel; - loc_u->lel_w = u3kb_lent(u3k(hel)); - - // Read hev into array. - { - c3_w i_w; - - loc_u->hev = u3a_malloc(u3kb_lent(u3k(hev)) * sizeof(u3_noun)); - - for ( i_w = 0; u3_nul != hev; i_w++ ) { - loc_u->hev[i_w] = u3h(hev); - hev = u3t(hev); - } - loc_u->lev_w = i_w; - } - loc_u->kct_w = 0; - loc_u->kad = u3a_malloc((1 + c3_min(loc_u->lev_w, loc_u->lel_w)) * - sizeof(u3_noun)); - - // Compute equivalence classes. - // - loc_u->sev = u3_nul; - { - c3_w i_w; - - for ( i_w = 0; i_w < loc_u->lev_w; i_w++ ) { - u3_noun how = loc_u->hev[i_w]; - u3_noun hav; - u3_noun teg; - - hav = u3kdb_get(u3k(loc_u->sev), u3k(how)); - teg = u3nc(u3i_words(1, &i_w), - (hav == u3_none) ? u3_nul : hav); - loc_u->sev = u3kdb_put(loc_u->sev, u3k(how), teg); - } - } - } - - // apply - // - static void - _lune(u3_loss* loc_u, - c3_w inx_w, - c3_w goy_w) - { - u3_noun kad; - - kad = u3nc(u3i_words(1, &goy_w), - (inx_w == 0) ? u3_nul - : u3k(loc_u->kad[inx_w - 1])); - if ( loc_u->kct_w == inx_w ) { - c3_assert(loc_u->kct_w < (1 << 31)); - loc_u->kct_w++; - } else { - u3z(loc_u->kad[inx_w]); - } - loc_u->kad[inx_w] = kad; - } - - // extend fits top - // - static u3_noun - _hink(u3_loss* loc_u, - c3_w inx_w, - c3_w goy_w) - { - return __ - ( (loc_u->kct_w == inx_w) || - (u3r_word(0, u3h(loc_u->kad[inx_w])) > goy_w) ); - } - - // extend fits bottom - // - static u3_noun - _lonk(u3_loss* loc_u, - c3_w inx_w, - c3_w goy_w) - { - return __ - ( (0 == inx_w) || - (u3r_word(0, u3h(loc_u->kad[inx_w - 1])) < goy_w) ); - } - -#if 0 - // search for first index >= inx_w and <= max_w that fits - // the hink and lonk criteria. - // - static u3_noun - _binka(u3_loss* loc_u, - c3_w* inx_w, - c3_w max_w, - c3_w goy_w) - { - while ( *inx_w <= max_w ) { - if ( c3n == _lonk(loc_u, *inx_w, goy_w) ) { - return c3n; - } - if ( c3y == _hink(loc_u, *inx_w, goy_w) ) { - return c3y; - } - else ++*inx_w; - } - return c3n; - } -#endif - - // search for lowest index >= inx_w and <= max_w for which - // both hink(inx_w) and lonk(inx_w) are true. lonk is false - // if inx_w is too high, hink is false if it is too low. - // - static u3_noun - _bink(u3_loss* loc_u, - c3_w* inx_w, - c3_w max_w, - c3_w goy_w) - { - c3_assert(max_w >= *inx_w); - - if ( max_w == *inx_w ) { - if ( c3n == _lonk(loc_u, *inx_w, goy_w) ) { - return c3n; - } - if ( c3y == _hink(loc_u, *inx_w, goy_w) ) { - return c3y; - } - else { - ++*inx_w; - return c3n; - } - } - else { - c3_w mid_w = *inx_w + ((max_w - *inx_w) / 2); - - if ( (c3n == _lonk(loc_u, mid_w, goy_w)) || - (c3y == _hink(loc_u, mid_w, goy_w)) ) - { - return _bink(loc_u, inx_w, mid_w, goy_w); - } else { - *inx_w = mid_w + 1; - return _bink(loc_u, inx_w, max_w, goy_w); - } - } - } - - - static void - _merg(u3_loss* loc_u, - c3_w inx_w, - u3_noun gay) - { - if ( (u3_nul == gay) || (inx_w > loc_u->kct_w) ) { - return; - } - else { - u3_noun i_gay = u3h(gay); - c3_w goy_w = u3r_word(0, i_gay); - u3_noun bik; - - bik = _bink(loc_u, &inx_w, loc_u->kct_w, goy_w); - - if ( c3y == bik ) { - _merg(loc_u, inx_w + 1, u3t(gay)); - _lune(loc_u, inx_w, goy_w); - } - else { - _merg(loc_u, inx_w, u3t(gay)); - } - } - } - - // compute lcs - // - static void - _loss(u3_loss* loc_u) - { - while ( u3_nul != loc_u->hel ) { - u3_noun i_hel = u3h(loc_u->hel); - u3_noun guy = u3kdb_get(u3k(loc_u->sev), u3k(i_hel)); - - if ( u3_none != guy ) { - u3_noun gay = u3kb_flop(guy); - - _merg(loc_u, 0, gay); - u3z(gay); - } - - loc_u->hel = u3t(loc_u->hel); - } - } - - u3_noun - u3qe_loss(u3_noun hel, - u3_noun hev) - { - u3_loss loc_u; - u3_noun lcs; - - _lemp(&loc_u, hel, hev); - _loss(&loc_u); - lcs = _lexs(&loc_u); - - _flem(&loc_u); - return lcs; - } - - static u3_noun - _listp(u3_noun lix) - { - while ( 1 ) { - if ( u3_nul == lix ) return c3y; - if ( c3n == u3du(lix) ) return c3n; - lix = u3t(lix); - } - } - - u3_noun - u3we_loss(u3_noun cor) - { - u3_noun hel, hev; - - if ( (u3_none == (hel = u3r_at(u3x_sam_2, cor))) || - (u3_none == (hev = u3r_at(u3x_sam_3, cor))) || - (c3n == _listp(hel)) || - (c3n == _listp(hev)) ) - { - return u3m_bail(c3__fail); - } else { - return u3qe_loss(hel, hev); - } - } diff --git a/pkg/urbit/jets/e/lune.c b/pkg/urbit/jets/e/lune.c deleted file mode 100644 index 7d173d47a..000000000 --- a/pkg/urbit/jets/e/lune.c +++ /dev/null @@ -1,55 +0,0 @@ -/* j/5/lune.c -** -*/ -#include "all.h" - - - u3_noun - u3qe_lune(u3_atom lub) - { - if (lub == 0) { - return u3_nul; - } - - { - c3_w end_w = u3r_met(3, lub) - 1; - c3_w pos_w = end_w; - u3_noun lin = u3_nul; - - if (u3r_byte(pos_w, lub) != 10) { - return u3m_error("noeol"); - } - - if (pos_w == 0) { - return u3nc(u3_nul, lin); - } - - while (--pos_w) { - if (u3r_byte(pos_w, lub) == 10) { - lin = u3nc(u3qc_cut(3, (pos_w + 1), (end_w - pos_w - 1), lub), lin); - end_w = pos_w; - } - } - - if (u3r_byte(pos_w, lub) == 10) { - return u3nc(u3_nul, - u3nc(u3qc_cut(3, (pos_w + 1), (end_w - pos_w - 1), lub), lin)); - } - - return u3nc(u3qc_cut(3, pos_w, (end_w - pos_w), lub), lin); - } - } - - u3_noun - u3we_lune(u3_noun cor) - { - u3_noun lub; - - if ( (u3_none == (lub = u3r_at(u3x_sam, cor))) || - (c3n == u3ud(lub)) ) - { - return u3m_bail(c3__fail); - } else { - return u3qe_lune(lub); - } - } diff --git a/pkg/urbit/jets/e/mat.c b/pkg/urbit/jets/e/mat.c deleted file mode 100644 index 7a9232602..000000000 --- a/pkg/urbit/jets/e/mat.c +++ /dev/null @@ -1,50 +0,0 @@ -/* j/3/mat.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qe_mat(u3_atom a) - { - if ( 0 == a ) { - return u3nc(1, 1); - } else { - u3_atom b = u3qc_met(0, a); - u3_atom c = u3qc_met(0, b); - u3_atom u, v, w, x, y, z; - u3_atom p, q; - - u = u3qa_dec(c); - v = u3qa_add(c, c); - w = u3qc_bex(c); - x = u3qc_end(0, u, b); - y = u3qc_lsh(0, u, a); - z = u3qc_mix(x, y); - - p = u3qa_add(v, b); - q = u3qc_cat(0, w, z); - - u3z(u); - u3z(v); - u3z(w); - u3z(x); - u3z(y); - u3z(z); - - return u3nc(p, q); - } - } - u3_noun - u3we_mat(u3_noun cor) - { - u3_noun a; - - if ( (u3_none == (a = u3r_at(u3x_sam, cor))) ) { - return u3m_bail(c3__fail); - } else { - return u3qe_mat(a); - } - } diff --git a/pkg/urbit/jets/e/mink.c b/pkg/urbit/jets/e/mink.c deleted file mode 100644 index c17a02427..000000000 --- a/pkg/urbit/jets/e/mink.c +++ /dev/null @@ -1,25 +0,0 @@ -/* j/5/mink.c -** -*/ -#include "all.h" - - u3_noun - u3we_mink(u3_noun cor) - { - u3_noun bus, fol, gul; - - if ( c3n == u3r_mean(cor, u3x_sam_4, &bus, - u3x_sam_5, &fol, - u3x_sam_3, &gul, - 0) ) - { - return u3m_bail(c3__exit); - } - else { - u3_noun som; - - som = u3n_nock_et(u3k(gul), u3k(bus), u3k(fol)); - - return som; - } - } diff --git a/pkg/urbit/jets/e/mole.c b/pkg/urbit/jets/e/mole.c deleted file mode 100644 index ee32472ec..000000000 --- a/pkg/urbit/jets/e/mole.c +++ /dev/null @@ -1,16 +0,0 @@ -/* j/5/mule.c -** -*/ -#include "all.h" - -u3_noun -u3we_mole(u3_noun cor) -{ - u3_noun hok = u3j_cook("u3we_mole-mure", u3k(cor), "mure"); - - // just like +mule and +mute, this takes advantage of the fact that - // +mure's result is identical to that of +mole, and safely produces - // a statically-typed value while only evaluating the trap once. - // - return u3n_slam_on(hok, u3k(u3x_at(u3x_sam, cor))); -} diff --git a/pkg/urbit/jets/e/mule.c b/pkg/urbit/jets/e/mule.c deleted file mode 100644 index f27b294fa..000000000 --- a/pkg/urbit/jets/e/mule.c +++ /dev/null @@ -1,17 +0,0 @@ -/* j/5/mule.c -** -*/ -#include "all.h" - -u3_noun -u3we_mule(u3_noun cor) -{ - u3_noun hok = u3j_cook("u3we_mule-mute", u3k(cor), "mute"); - - - // this takes advantage of the fact that +mute's result is - // identical to that of +mule, and safely produces a statically-typed - // value while only evaluating the trap once. - // - return u3n_slam_on(hok, u3k(u3x_at(u3x_sam, cor))); -} diff --git a/pkg/urbit/jets/e/parse.c b/pkg/urbit/jets/e/parse.c deleted file mode 100644 index 4d50439e2..000000000 --- a/pkg/urbit/jets/e/parse.c +++ /dev/null @@ -1,1014 +0,0 @@ -/* j/5/parse.c -** -*/ -#include "all.h" - - - static u3_noun - _slip(u3_noun weq, - u3_noun naz) - { - u3_noun p_naz, q_naz; - - u3x_cell(naz, &p_naz, &q_naz); - if ( 10 == weq ) { - return u3nc(u3x_good(u3i_vint(u3k(p_naz))), - 1); - } else { - return u3nc(u3k(p_naz), - u3x_good(u3i_vint(u3k(q_naz)))); - } - } - - static u3_noun - _fail(u3_noun tub) - { - u3_noun p_tub, q_tub; - - u3x_cell(tub, &p_tub, &q_tub); - return u3nc(u3k(p_tub), u3_nul); - } - - static u3_noun - _last(u3_noun zyc, - u3_noun naz) - { - u3_noun p_zyc, q_zyc, p_naz, q_naz; - - u3x_cell(zyc, &p_zyc, &q_zyc); - u3x_cell(naz, &p_naz, &q_naz); - - if ( !_(u3a_is_cat(p_zyc)) || !_(u3a_is_cat(q_zyc)) || - !_(u3a_is_cat(p_naz)) || !_(u3a_is_cat(q_naz)) ) - { - return u3m_bail(c3__fail); - } else { - if ( p_zyc == p_naz ) { - return (q_zyc > q_naz) ? u3k(zyc) : u3k(naz); - } - else { - return (p_zyc > p_naz) ? u3k(zyc) : u3k(naz); - } - } - } - - static u3_noun - _last_k(u3_noun zyc, u3_noun naz) - { - u3_noun pro = _last(zyc, naz); - u3z(zyc); u3z(naz); - return pro; - } - - static u3_noun - _next(u3_noun tub) - { - u3_noun p_tub, q_tub; - u3_noun zac; - - u3x_cell(tub, &p_tub, &q_tub); - if ( c3n == u3du(q_tub) ) { - return _fail(tub); - } - else { - u3_noun iq_tub = u3h(q_tub); - u3_noun tq_tub = u3t(q_tub); - - zac = _slip(iq_tub, p_tub); - - return u3nc(zac, - u3nq(u3_nul, - u3k(iq_tub), - u3k(zac), - u3k(tq_tub))); - } - } - -/* bend -*/ - static u3_noun - _cqe_bend_fun(u3_noun raq, - u3_noun vex, - u3_noun sab) - { - u3_noun p_vex, q_vex; - - u3x_cell(vex, &p_vex, &q_vex); - if ( c3n == u3du(q_vex) ) { - return u3k(vex); - } else { - u3_noun uq_vex = u3t(q_vex); - u3_noun puq_vex, quq_vex; - u3_noun yit, yur; - u3_noun p_yit, q_yit; - u3_noun ret; - - u3x_cell(uq_vex, &puq_vex, &quq_vex); - yit = u3x_good(u3n_slam_on(u3k(sab), u3k(quq_vex))); - - u3x_cell(yit, &p_yit, &q_yit); - yur = _last(p_vex, p_yit); - - if ( c3n == u3du(q_yit) ) { - ret = u3nc(yur, u3k(q_vex)); - } - else { - u3_noun uq_yit = u3t(q_yit); - u3_noun puq_yit, quq_yit; - u3_noun vux; - - u3x_cell(uq_yit, &puq_yit, &quq_yit); - - vux = u3x_good(u3n_slam_on(u3k(raq), - u3nc(u3k(puq_vex), - u3k(puq_yit)))); - if ( u3_nul == vux ) { - ret = u3nc(yur, u3k(q_vex)); - } - else { - ret = u3nq(yur, - u3_nul, - u3k(u3t(vux)), - u3k(quq_yit)); - u3z(vux); - } - } - u3z(yit); - return ret; - } - } - - u3_noun - u3we_bend_fun(u3_noun cor) - { - u3_noun van, raq, vex, sab; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, - u3x_sam_3, &sab, - u3x_con, &van, 0)) || - (u3_none == (raq = u3r_at(u3x_sam, van))) ) - { - return u3m_bail(c3__fail); - } else { - return _cqe_bend_fun(raq, vex, sab); - } - } - -/* cold -*/ - static u3_noun - _cqe_cold_fun(u3_noun cus, - u3_noun sef, - u3_noun tub) - { - u3_noun vex = u3x_good(u3n_slam_on(u3k(sef), u3k(tub))); - u3_noun p_vex, q_vex; - - u3x_cell(vex, &p_vex, &q_vex); - - if ( c3n == u3du(q_vex) ) { - return vex; - } - else { - u3_noun uq_vex = u3t(q_vex); - u3_noun quq_vex; - u3_noun ret; - - u3x_cell(uq_vex, 0, &quq_vex); - ret = u3nq(u3k(p_vex), - u3_nul, - u3k(cus), - u3k(quq_vex)); - - u3z(vex); - return ret; - } - } - - u3_noun - u3we_cold_fun(u3_noun cor) - { - u3_noun van, cus, sef, tub; - - if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || - (c3n == u3r_mean(van, u3x_sam_2, &cus, u3x_sam_3, &sef, 0)) ) - { - return u3m_bail(c3__fail); - } else { - return _cqe_cold_fun(cus, sef, tub); - } - } - -/* cook -*/ - static u3_noun - _cqe_cook_fun(u3_noun poq, - u3_noun sef, - u3_noun tub) - { - u3_noun vex = u3x_good(u3n_slam_on(u3k(sef), u3k(tub))); - u3_noun p_vex, q_vex; - - u3x_cell(vex, &p_vex, &q_vex); - - if ( c3n == u3du(q_vex) ) { - return vex; - } - else { - u3_noun uq_vex = u3t(q_vex); - u3_noun puq_vex, quq_vex; - u3_noun wag; - u3_noun ret; - - u3x_cell(uq_vex, &puq_vex, &quq_vex); - wag = u3x_good(u3n_slam_on(u3k(poq), u3k(puq_vex))); - ret = u3nq(u3k(p_vex), - u3_nul, - wag, - u3k(quq_vex)); - - u3z(vex); - return ret; - } - } - - u3_noun - u3we_cook_fun(u3_noun cor) - { - u3_noun van, poq, sef, tub; - - if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || - (c3n == u3r_mean(van, u3x_sam_2, &poq, u3x_sam_3, &sef, 0)) ) - { - return u3m_bail(c3__fail); - } else { - return _cqe_cook_fun(poq, sef, tub); - } - } - -/* comp -*/ - static u3_noun - _cqe_comp_fun(u3_noun raq, - u3_noun vex, - u3_noun sab) - { - u3_noun p_vex, q_vex; - - u3x_cell(vex, &p_vex, &q_vex); - if ( c3n == u3du(q_vex) ) { - return u3k(vex); - } else { - u3_noun uq_vex = u3t(q_vex); - u3_noun puq_vex, quq_vex; - u3_noun yit, yur; - u3_noun p_yit, q_yit; - u3_noun ret; - - u3x_cell(uq_vex, &puq_vex, &quq_vex); - yit = u3x_good(u3n_slam_on(u3k(sab), u3k(quq_vex))); - - u3x_cell(yit, &p_yit, &q_yit); - yur = _last(p_vex, p_yit); - - if ( c3n == u3du(q_yit) ) { - ret = u3nc(yur, u3k(q_yit)); - } - else { - u3_noun uq_yit = u3t(q_yit); - u3_noun puq_yit, quq_yit; - - u3x_cell(uq_yit, &puq_yit, &quq_yit); - ret = u3nq(yur, - u3_nul, - u3x_good(u3n_slam_on(u3k(raq), - u3nc(u3k(puq_vex), - u3k(puq_yit)))), - u3k(quq_yit)); - } - u3z(yit); - return ret; - } - } - - u3_noun - u3we_comp_fun(u3_noun cor) - { - u3_noun van, raq, vex, sab; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, - u3x_sam_3, &sab, - u3x_con, &van, 0)) || - (u3_none == (raq = u3r_at(u3x_sam, van))) ) - { - return u3m_bail(c3__fail); - } else { - return _cqe_comp_fun(raq, vex, sab); - } - } - -/* easy -*/ - static u3_noun - _cqe_easy_fun(u3_noun huf, - u3_noun tub) - { - u3_noun p_tub, q_tub; - - u3x_cell(tub, &p_tub, &q_tub); - return u3nq(u3k(p_tub), - u3_nul, - u3k(huf), - u3k(tub)); - } - - u3_noun - u3we_easy_fun(u3_noun cor) - { - u3_noun van, huf, tub; - - if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || - (u3_none == (huf = u3r_at(u3x_sam, van))) ) - { - return u3m_bail(c3__fail); - } else { - return _cqe_easy_fun(huf, tub); - } - } - -/* glue -*/ - static u3_noun - _cqe_glue_fun(u3_noun bus, - u3_noun vex, - u3_noun sab) - { - u3_noun p_vex, q_vex; - - u3x_cell(vex, &p_vex, &q_vex); - if ( c3n == u3du(q_vex) ) { - return u3k(vex); - } - else { - u3_noun uq_vex = u3t(q_vex); - u3_noun puq_vex, quq_vex; - u3_noun yit, yur; - u3_noun p_yit, q_yit; - u3_noun ret; - - u3x_cell(uq_vex, &puq_vex, &quq_vex); - yit = u3x_good(u3n_slam_on(u3k(bus), u3k(quq_vex))); - - u3x_cell(yit, &p_yit, &q_yit); - yur = _last(p_vex, p_yit); - - if ( c3n == u3du(q_yit) ) { - ret = u3nc(yur, u3_nul); - } - else { - u3_noun uq_yit = u3t(q_yit); - u3_noun puq_yit, quq_yit; - u3_noun wam, p_wam, q_wam, goy; - - u3x_cell(uq_yit, &puq_yit, &quq_yit); - wam = u3x_good(u3n_slam_on(u3k(sab), u3k(quq_yit))); - - u3x_cell(wam, &p_wam, &q_wam); - goy = _last(yur, p_wam); - u3z(yur); - - if ( c3n == u3du(q_wam) ) { - ret = u3nc(goy, u3_nul); - } else { - u3_noun uq_wam = u3t(q_wam); - u3_noun puq_wam, quq_wam; - - u3x_cell(uq_wam, &puq_wam, &quq_wam); - ret = u3nq(goy, - u3_nul, - u3nc(u3k(puq_vex), - u3k(puq_wam)), - u3k(quq_wam)); - } - u3z(wam); - } - u3z(yit); - return ret; - } - } - - u3_noun - u3we_glue_fun(u3_noun cor) - { - u3_noun van, bus, vex, sab; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, - u3x_sam_3, &sab, - u3x_con, &van, 0)) || - (u3_none == (bus = u3r_at(u3x_sam, van))) ) - { - return u3m_bail(c3__fail); - } else { - return _cqe_glue_fun(bus, vex, sab); - } - } - -/* here -*/ - static u3_noun - _cqe_here_fun(u3_noun hez, - u3_noun sef, - u3_noun tub) - { - u3_noun vex = u3x_good(u3n_slam_on(u3k(sef), u3k(tub))); - u3_noun p_vex, q_vex; - - u3x_cell(vex, &p_vex, &q_vex); - - if ( c3n == u3du(q_vex) ) { - return vex; - } - else { - u3_noun uq_vex = u3t(q_vex); - u3_noun p_tub, q_tub; - u3_noun puq_vex, quq_vex, pquq_vex; - u3_noun gud, wag; - u3_noun ret; - - u3x_cell(tub, &p_tub, &q_tub); - u3x_cell(uq_vex, &puq_vex, &quq_vex); - u3x_cell(quq_vex, &pquq_vex, 0); - gud = u3nc( - u3nc(u3k(p_tub), - u3k(pquq_vex)), - u3k(puq_vex)); - - wag = u3x_good(u3n_slam_on(u3k(hez), gud)); - ret = u3nq(u3k(p_vex), - u3_nul, - wag, - u3k(quq_vex)); - - u3z(vex); - return ret; - } - } - - u3_noun - u3we_here_fun(u3_noun cor) - { - u3_noun van, hez, sef, tub; - - if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || - (c3n == u3r_mean(van, u3x_sam_2, &hez, u3x_sam_3, &sef, 0)) ) - { - return u3m_bail(c3__fail); - } - else { - return _cqe_here_fun(hez, sef, tub); - } - } - -/* just -*/ - static u3_noun - _cqe_just_fun(u3_noun daf, - u3_noun tub) - { - u3_noun p_tub, q_tub; - - u3x_cell(tub, &p_tub, &q_tub); - - if ( c3n == u3du(q_tub) ) { - return _fail(tub); - } - else { - u3_noun iq_tub = u3h(q_tub); - - if ( c3y == u3r_sing(daf, iq_tub) ) { - return _next(tub); - } - else return _fail(tub); - } - } - u3_noun - u3we_just_fun(u3_noun cor) - { - u3_noun van, daf, tub; - - if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || - (u3_none == (daf = u3r_at(u3x_sam, van))) ) - { - return u3m_bail(c3__fail); - } else { - return _cqe_just_fun(daf, tub); - } - } - -/* mask -*/ - static u3_noun - _cqe_mask_fun(u3_noun bud, - u3_noun tub) - { - u3_noun p_tub, q_tub; - - u3x_cell(tub, &p_tub, &q_tub); - - if ( c3n == u3du(q_tub) ) { - return _fail(tub); - } - else { - u3_noun iq_tub = u3h(q_tub); - - while ( c3y == u3du(bud) ) { - if ( c3y == u3r_sing(u3h(bud), iq_tub) ) { - return _next(tub); - } - bud = u3t(bud); - } - return _fail(tub); - } - } - u3_noun - u3we_mask_fun(u3_noun cor) - { - u3_noun van, bud, tub; - - if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || - (u3_none == (bud = u3r_at(u3x_sam, van))) ) - { - return u3m_bail(c3__fail); - } else { - return _cqe_mask_fun(bud, tub); - } - } -/* pfix -*/ - static u3_noun - _cqe_pfix(u3_noun vex, - u3_noun sab) - { - u3_noun p_vex, q_vex; - - u3x_cell(vex, &p_vex, &q_vex); - if ( c3n == u3du(q_vex) ) { - return u3k(vex); - } - else { - u3_noun uq_vex = u3t(q_vex); - u3_noun puq_vex, quq_vex; - u3_noun yit, p_yit, q_yit; - u3_noun ret; - - u3x_cell(uq_vex, &puq_vex, &quq_vex); - yit = u3x_good(u3n_slam_on(u3k(sab), u3k(quq_vex))); - - u3x_cell(yit, &p_yit, &q_yit); - ret = u3nc(_last(p_vex, p_yit), - u3k(q_yit)); - - u3z(yit); - return ret; - } - } - u3_noun - u3we_pfix(u3_noun cor) - { - u3_noun vex, sab; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, u3x_sam_3, &sab, 0)) ) { - return u3m_bail(c3__exit); - } else { - return _cqe_pfix(vex, sab); - } - } - -/* plug -*/ - static u3_noun - _cqe_plug(u3_noun vex, - u3_noun sab) - { - u3_noun p_vex, q_vex; - - u3x_cell(vex, &p_vex, &q_vex); - if ( c3n == u3du(q_vex) ) { - return u3k(vex); - } - else { - u3_noun uq_vex = u3t(q_vex); - u3_noun puq_vex, quq_vex; - u3_noun yit, yur; - u3_noun p_yit, q_yit; - u3_noun ret; - - u3x_cell(uq_vex, &puq_vex, &quq_vex); - yit = u3x_good(u3n_slam_on(u3k(sab), u3k(quq_vex))); - - u3x_cell(yit, &p_yit, &q_yit); - yur = _last(p_vex, p_yit); - - if ( c3n == u3du(q_yit) ) { - ret = u3nc(yur, u3k(q_yit)); - } - else { - u3_noun uq_yit = u3t(q_yit); - u3_noun puq_yit, quq_yit; - - u3x_cell(uq_yit, &puq_yit, &quq_yit); - ret = u3nq(yur, - u3_nul, - u3nc(u3k(puq_vex), - u3k(puq_yit)), - u3k(quq_yit)); - } - u3z(yit); - return ret; - } - } - u3_noun - u3we_plug(u3_noun cor) - { - u3_noun vex, sab; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, u3x_sam_3, &sab, 0)) ) { - return u3m_bail(c3__exit); - } else { - return _cqe_plug(vex, sab); - } - } - -/* pose -*/ - u3_noun - u3qe_pose(u3_noun vex, - u3_noun sab) - { - u3_noun p_vex, q_vex; - - u3x_cell(vex, &p_vex, &q_vex); - if ( c3y == u3du(q_vex) ) { - return u3k(vex); - } else { - u3_noun roq = u3x_good(u3n_kick_on(u3k(sab))); - u3_noun p_roq, q_roq; - u3_noun ret; - - u3x_cell(roq, &p_roq, &q_roq); - ret = u3nc(_last(p_vex, p_roq), - u3k(q_roq)); - - u3z(roq); - return ret; - } - } - u3_noun - u3we_pose(u3_noun cor) - { - u3_noun vex, sab; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, u3x_sam_3, &sab, 0)) ) { - return u3m_bail(c3__exit); - } else { - return u3qe_pose(vex, sab); - } - } - -/* sfix -*/ - static u3_noun - _cqe_sfix(u3_noun vex, - u3_noun sab) - { - u3_noun p_vex, q_vex; - - u3x_cell(vex, &p_vex, &q_vex); - if ( c3n == u3du(q_vex) ) { - return u3k(vex); - } - else { - u3_noun uq_vex = u3t(q_vex); - u3_noun puq_vex, quq_vex; - u3_noun yit, p_yit, q_yit, yur; - u3_noun ret; - - u3x_cell(uq_vex, &puq_vex, &quq_vex); - yit = u3x_good(u3n_slam_on(u3k(sab), u3k(quq_vex))); - - u3x_cell(yit, &p_yit, &q_yit); - yur = _last(p_vex, p_yit); - - if ( c3n == u3du(q_yit) ) { - ret = u3nc(yur, u3_nul); - } - else { - u3_noun uq_yit = u3t(q_yit); - u3_noun puq_yit, quq_yit; - - u3x_cell(uq_yit, &puq_yit, &quq_yit); - - ret = u3nq(yur, - u3_nul, - u3k(puq_vex), - u3k(quq_yit)); - } - u3z(yit); - return ret; - } - } - u3_noun - u3we_sfix(u3_noun cor) - { - u3_noun vex, sab; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &vex, u3x_sam_3, &sab, 0)) ) { - return u3m_bail(c3__exit); - } else { - return _cqe_sfix(vex, sab); - } - } - -/* shim -*/ - static u3_noun - _cqe_shim_fun(u3_noun zep, - u3_noun tub) - { - u3_noun p_tub, q_tub; - - u3x_cell(tub, &p_tub, &q_tub); - - if ( c3n == u3du(q_tub) ) { - return _fail(tub); - } - else { - u3_noun p_zep, q_zep; - u3_noun iq_tub = u3h(q_tub); - - u3x_cell(zep, &p_zep, &q_zep); - if ( _(u3a_is_cat(p_zep)) && - _(u3a_is_cat(q_zep)) && - _(u3a_is_cat(iq_tub)) ) - { - if ( (iq_tub >= p_zep) && (iq_tub <= q_zep) ) { - return _next(tub); - } - else return _fail(tub); - } - else { - return u3m_bail(c3__fail); - } - } - } - u3_noun - u3we_shim_fun(u3_noun cor) - { - u3_noun van, zep, tub; - - if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || - (u3_none == (zep = u3r_at(u3x_sam, van))) ) - { - return u3m_bail(c3__fail); - } else { - return _cqe_shim_fun(zep, tub); - } - } - -/* stag -*/ - static u3_noun - _cqe_stag_fun(u3_noun gob, - u3_noun sef, - u3_noun tub) - { - u3_noun vex = u3x_good(u3n_slam_on(u3k(sef), u3k(tub))); - u3_noun p_vex, q_vex; - - u3x_cell(vex, &p_vex, &q_vex); - - if ( c3n == u3du(q_vex) ) { - return vex; - } - else { - u3_noun uq_vex = u3t(q_vex); - u3_noun puq_vex, quq_vex; - u3_noun wag; - u3_noun ret; - - u3x_cell(uq_vex, &puq_vex, &quq_vex); - wag = u3nc(u3k(gob), u3k(puq_vex)); - ret = u3nq(u3k(p_vex), - u3_nul, - wag, - u3k(quq_vex)); - - u3z(vex); - return ret; - } - } - - u3_noun - u3we_stag_fun(u3_noun cor) - { - u3_noun van, gob, sef, tub; - - if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || - (c3n == u3r_mean(van, u3x_sam_2, &gob, u3x_sam_3, &sef, 0)) ) - { - return u3m_bail(c3__fail); - } else { - return _cqe_stag_fun(gob, sef, tub); - } - } - -/* stew -*/ - static u3_noun - _stew_wor(u3_noun ort, - u3_noun wan) - { - if ( !_(u3a_is_cat(ort)) ) { - return u3m_bail(c3__fail); - } - else { - if ( c3n == u3du(wan) ) { - if ( !_(u3a_is_cat(wan)) ) { - return u3m_bail(c3__fail); - } - else return (ort < wan) ? c3y : c3n; - } - else { - u3_noun h_wan = u3h(wan); - - if ( !_(u3a_is_cat(h_wan)) ) { - return u3m_bail(c3__fail); - } - else return (ort < h_wan) ? c3y : c3n; - } - } - } - - static u3_noun - _cqe_stew_fun(u3_noun hel, - u3_noun tub) - { - u3_noun p_tub, q_tub; - - u3x_cell(tub, &p_tub, &q_tub); - if ( c3n == u3du(q_tub) ) { - return _fail(tub); - } - else { - u3_noun iq_tub = u3h(q_tub); - - if ( !_(u3a_is_cat(iq_tub)) ) { - return u3m_bail(c3__fail); - } - else while ( 1 ) { - if ( c3n == u3du(hel) ) { - return _fail(tub); - } - else { - u3_noun n_hel, l_hel, r_hel; - u3_noun pn_hel, qn_hel; - c3_o bit_o; - - u3x_trel(hel, &n_hel, &l_hel, &r_hel); - u3x_cell(n_hel, &pn_hel, &qn_hel); - - if ( (c3n == u3du(pn_hel)) ) { - bit_o = __((iq_tub == pn_hel)); - } - else { - u3_noun hpn_hel = u3h(pn_hel); - u3_noun tpn_hel = u3t(pn_hel); - - if ( !_(u3a_is_cat(hpn_hel)) || - !_(u3a_is_cat(tpn_hel)) ) { - return _fail(tub); - } - else bit_o = __((iq_tub >= hpn_hel) && (iq_tub <= tpn_hel)); - } - - if ( c3y == bit_o ) { - return u3x_good - (u3n_slam_on(u3k(qn_hel), u3k(tub))); - } else { - if ( c3y == _stew_wor(iq_tub, pn_hel) ) { - hel = l_hel; - } - else hel = r_hel; - } - } - } - } - } - u3_noun - u3we_stew_fun(u3_noun cor) - { - u3_noun con, hel, tub; - - if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &con, 0)) || - (u3_none == (hel = u3r_at(2, con))) ) - { - return u3m_bail(c3__fail); - } else { - return _cqe_stew_fun(hel, tub); - } - } - -/* _stir_pair(): stack frame recording intermediate parse results -*/ - typedef struct { - u3_noun har; // hair, p_vex - u3_noun res; // parse-result, puq_vex - } _stir_pair; - -/* stir -*/ - static u3_noun - _cqe_stir_fun(u3_noun rud, - u3_noun raq, - u3_noun fel, - u3_noun tub) - { - // pil_u: stack control structure - // par_u: frame pointer - // wag: initial accumulator (deconstructed) - // - u3a_pile pil_u; - _stir_pair* par_u; - u3_noun p_wag, puq_wag, quq_wag; - - u3a_pile_prep(&pil_u, sizeof(*par_u)); - - // push incremental, successful [fel] parse results onto road stack - // - { - u3_noun vex, p_vex, q_vex, puq_vex, quq_vex; - u3j_site fel_u; - u3j_gate_prep(&fel_u, u3k(fel)); - - vex = u3j_gate_slam(&fel_u, u3k(tub)); - u3x_cell(vex, &p_vex, &q_vex); - - u3k(tub); - - while ( u3_nul != q_vex ) { - u3x_trel(q_vex, 0, &puq_vex, &quq_vex); - - par_u = u3a_push(&pil_u); - par_u->har = u3k(p_vex); - par_u->res = u3k(puq_vex); - - u3z(tub); - tub = u3k(quq_vex); - - u3z(vex); - vex = u3j_gate_slam(&fel_u, u3k(tub)); - u3x_cell(vex, &p_vex, &q_vex); - } - - p_wag = u3k(p_vex); - puq_wag = u3k(rud); - quq_wag = tub; - - u3z(vex); - u3j_gate_lose(&fel_u); - } - - // unwind the stack, folding parse results into [wag] by way of [raq] - // - if ( c3n == u3a_pile_done(&pil_u) ) { - u3j_site raq_u; - u3j_gate_prep(&raq_u, u3k(raq)); - - while ( c3n == u3a_pile_done(&pil_u) ) { - p_wag = _last_k(par_u->har, p_wag); - puq_wag = u3j_gate_slam(&raq_u, u3nc(par_u->res, puq_wag)); - par_u = u3a_pop(&pil_u); - } - - u3j_gate_lose(&raq_u); - } - - return u3nq(p_wag, u3_nul, puq_wag, quq_wag); - } - - u3_noun - u3we_stir_fun(u3_noun cor) - { - u3_noun van, rud, raq, fel, tub; - - if ( (c3n == u3r_mean(cor, u3x_sam, &tub, u3x_con, &van, 0)) || - (c3n == u3r_mean(van, u3x_sam_2, &rud, - u3x_sam_6, &raq, - u3x_sam_7, &fel, - 0)) ) - { - return u3m_bail(c3__fail); - } else { - return _cqe_stir_fun(rud, raq, fel, tub); - } - } diff --git a/pkg/urbit/jets/e/rd.c b/pkg/urbit/jets/e/rd.c deleted file mode 100644 index d4b44f778..000000000 --- a/pkg/urbit/jets/e/rd.c +++ /dev/null @@ -1,390 +0,0 @@ -/* j/e/rd.c -** -*/ -#include "all.h" -#include - -#define DOUBNAN 0x7ff8000000000000 - - union doub { - float64_t d; - c3_d c; - }; - -/* functions -*/ - static inline c3_t - _nan_test(float64_t a) - { - return !f64_eq(a, a); - } - - static inline float64_t - _nan_unify(float64_t a) - { - if ( _nan_test(a) ) - { - *(c3_d*)(&a) = DOUBNAN; - } - return a; - } - - static inline void - _set_rounding(c3_w a) - { - switch ( a ) - { - default: - u3m_bail(c3__fail); - break; - case c3__n: - softfloat_roundingMode = softfloat_round_near_even; - break; - case c3__z: - softfloat_roundingMode = softfloat_round_minMag; - break; - case c3__u: - softfloat_roundingMode = softfloat_round_max; - break; - case c3__d: - softfloat_roundingMode = softfloat_round_min; - break; - } - } - -/* add -*/ - u3_noun - u3qer_add(u3_atom a, - u3_atom b, - u3_atom r) - { - union doub c, d, e; - _set_rounding(r); - c.c = u3r_chub(0, a); - d.c = u3r_chub(0, b); - e.d = _nan_unify(f64_add(c.d, d.d)); - - return u3i_chubs(1, &e.c); - } - - u3_noun - u3wer_add(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qer_add(a, b, u3x_at(30, cor)); - } - } - -/* sub -*/ - u3_noun - u3qer_sub(u3_atom a, - u3_atom b, - u3_atom r) - { - union doub c, d, e; - _set_rounding(r); - c.c = u3r_chub(0, a); - d.c = u3r_chub(0, b); - e.d = _nan_unify(f64_sub(c.d, d.d)); - - return u3i_chubs(1, &e.c); - } - - u3_noun - u3wer_sub(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qer_sub(a, b, u3x_at(30, cor)); - } - } - -/* mul -*/ - u3_noun - u3qer_mul(u3_atom a, - u3_atom b, - u3_atom r) - { - union doub c, d, e; - _set_rounding(r); - c.c = u3r_chub(0, a); - d.c = u3r_chub(0, b); - e.d = _nan_unify(f64_mul(c.d, d.d)); - - return u3i_chubs(1, &e.c); - } - - u3_noun - u3wer_mul(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qer_mul(a, b, u3x_at(30, cor)); - } - } - -/* div -*/ - u3_noun - u3qer_div(u3_atom a, - u3_atom b, - u3_atom r) - { - union doub c, d, e; - _set_rounding(r); - c.c = u3r_chub(0, a); - d.c = u3r_chub(0, b); - e.d = _nan_unify(f64_div(c.d, d.d)); - - return u3i_chubs(1, &e.c); - } - - u3_noun - u3wer_div(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qer_div(a, b, u3x_at(30, cor)); - } - } - -/* sqt -*/ - u3_noun - u3qer_sqt(u3_atom a, - u3_atom r) - { - union doub c, d; - _set_rounding(r); - c.c = u3r_chub(0, a); - d.d = _nan_unify(f64_sqrt(c.d)); - - return u3i_chubs(1, &d.c); - } - - u3_noun - u3wer_sqt(u3_noun cor) - { - u3_noun a; - - if ( c3n == (a = u3r_at(u3x_sam, cor)) || - c3n == u3ud(a) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qer_sqt(a, u3x_at(30, cor)); - } - } - -/* fma -*/ - u3_noun - u3qer_fma(u3_atom a, - u3_atom b, - u3_atom c, - u3_atom r) - { - union doub d, e, f, g; - _set_rounding(r); - d.c = u3r_chub(0, a); - e.c = u3r_chub(0, b); - f.c = u3r_chub(0, c); - g.d = _nan_unify(f64_mulAdd(d.d, e.d, f.d)); - - return u3i_chubs(1, &g.c); - } - - u3_noun - u3wer_fma(u3_noun cor) - { - u3_noun a, b, c; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_6, &b, u3x_sam_7, &c, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) || - c3n == u3ud(c) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qer_fma(a, b, c, u3x_at(30, cor)); - } - } - -/* lth -*/ - u3_noun - u3qer_lth(u3_atom a, - u3_atom b) - { - union doub c, d; - c.c = u3r_chub(0, a); - d.c = u3r_chub(0, b); - - return __(f64_lt(c.d, d.d)); - } - - u3_noun - u3wer_lth(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qer_lth(a, b); - } - } - -/* lte -*/ - u3_noun - u3qer_lte(u3_atom a, - u3_atom b) - { - union doub c, d; - c.c = u3r_chub(0, a); - d.c = u3r_chub(0, b); - - return __(f64_le(c.d, d.d)); - } - - u3_noun - u3wer_lte(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qer_lte(a, b); - } - } - -/* equ -*/ - u3_noun - u3qer_equ(u3_atom a, - u3_atom b) - { - union doub c, d; - c.c = u3r_chub(0, a); - d.c = u3r_chub(0, b); - - return __(f64_eq(c.d, d.d)); - } - - u3_noun - u3wer_equ(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qer_equ(a, b); - } - } - -/* gte -*/ - u3_noun - u3qer_gte(u3_atom a, - u3_atom b) - { - union doub c, d; - c.c = u3r_chub(0, a); - d.c = u3r_chub(0, b); - - return __(f64_le(d.d, c.d)); - } - - u3_noun - u3wer_gte(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qer_gte(a, b); - } - } - -/* gth -*/ - u3_noun - u3qer_gth(u3_atom a, - u3_atom b) - { - union doub c, d; - c.c = u3r_chub(0, a); - d.c = u3r_chub(0, b); - - return __(f64_lt(d.d, c.d)); - } - - u3_noun - u3wer_gth(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qer_gth(a, b); - } - } diff --git a/pkg/urbit/jets/e/rh.c b/pkg/urbit/jets/e/rh.c deleted file mode 100644 index 472de374a..000000000 --- a/pkg/urbit/jets/e/rh.c +++ /dev/null @@ -1,390 +0,0 @@ -/* j/e/rh.c -** -*/ -#include "all.h" -#include - -#define HALFNAN 0x7e00 - - union half { - float16_t h; - c3_s c; - }; - -/* functions -*/ - static inline c3_t - _nan_test(float16_t a) - { - return !f16_eq(a, a); - } - - static inline float16_t - _nan_unify(float16_t a) - { - if ( _nan_test(a) ) - { - *(c3_s*)(&a) = HALFNAN; - } - return a; - } - - static inline void - _set_rounding(c3_w a) - { - switch ( a ) - { - default: - u3m_bail(c3__fail); - break; - case c3__n: - softfloat_roundingMode = softfloat_round_near_even; - break; - case c3__z: - softfloat_roundingMode = softfloat_round_minMag; - break; - case c3__u: - softfloat_roundingMode = softfloat_round_max; - break; - case c3__d: - softfloat_roundingMode = softfloat_round_min; - break; - } - } - -/* add -*/ - u3_noun - u3qes_add(u3_atom a, - u3_atom b, - u3_atom r) - { - union half c, d, e; - _set_rounding(r); - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - e.h = _nan_unify(f16_add(c.h, d.h)); - - return e.c; - } - - u3_noun - u3wes_add(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qes_add(a, b, u3x_at(30, cor)); - } - } - -/* sub -*/ - u3_noun - u3qes_sub(u3_atom a, - u3_atom b, - u3_atom r) - { - union half c, d, e; - _set_rounding(r); - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - e.h = _nan_unify(f16_sub(c.h, d.h)); - - return e.c; - } - - u3_noun - u3wes_sub(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qes_sub(a, b, u3x_at(30, cor)); - } - } - -/* mul -*/ - u3_noun - u3qes_mul(u3_atom a, - u3_atom b, - u3_atom r) - { - union half c, d, e; - _set_rounding(r); - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - e.h = _nan_unify(f16_mul(c.h, d.h)); - - return e.c; - } - - u3_noun - u3wes_mul(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qes_mul(a, b, u3x_at(30, cor)); - } - } - -/* div -*/ - u3_noun - u3qes_div(u3_atom a, - u3_atom b, - u3_atom r) - { - union half c, d, e; - _set_rounding(r); - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - e.h = _nan_unify(f16_div(c.h, d.h)); - - return e.c; - } - - u3_noun - u3wes_div(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qes_div(a, b, u3x_at(30, cor)); - } - } - -/* sqt -*/ - u3_noun - u3qes_sqt(u3_atom a, - u3_atom r) - { - union half c, d; - _set_rounding(r); - c.c = u3r_word(0, a); - d.h = _nan_unify(f16_sqrt(c.h)); - - return d.c; - } - - u3_noun - u3wes_sqt(u3_noun cor) - { - u3_noun a; - - if ( c3n == (a = u3r_at(u3x_sam, cor)) || - c3n == u3ud(a) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qes_sqt(a, u3x_at(30, cor)); - } - } - -/* fma -*/ - u3_noun - u3qes_fma(u3_atom a, - u3_atom b, - u3_atom c, - u3_atom r) - { - union half d, e, f, g; - _set_rounding(r); - d.c = u3r_word(0, a); - e.c = u3r_word(0, b); - f.c = u3r_word(0, c); - g.h = _nan_unify(f16_mulAdd(d.h, e.h, f.h)); - - return g.c; - } - - u3_noun - u3wes_fma(u3_noun cor) - { - u3_noun a, b, c; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_6, &b, u3x_sam_7, &c, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) || - c3n == u3ud(c) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qes_fma(a, b, c, u3x_at(30, cor)); - } - } - -/* lth -*/ - u3_noun - u3qes_lth(u3_atom a, - u3_atom b) - { - union half c, d; - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - - return __(f16_lt(c.h, d.h)); - } - - u3_noun - u3wes_lth(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qes_lth(a, b); - } - } - -/* lte -*/ - u3_noun - u3qes_lte(u3_atom a, - u3_atom b) - { - union half c, d; - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - - return __(f16_le(c.h, d.h)); - } - - u3_noun - u3wes_lte(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qes_lte(a, b); - } - } - -/* equ -*/ - u3_noun - u3qes_equ(u3_atom a, - u3_atom b) - { - union half c, d; - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - - return __(f16_eq(c.h, d.h)); - } - - u3_noun - u3wes_equ(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qes_equ(a, b); - } - } - -/* gte -*/ - u3_noun - u3qes_gte(u3_atom a, - u3_atom b) - { - union half c, d; - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - - return __(f16_le(d.h, c.h)); - } - - u3_noun - u3wes_gte(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qes_gte(a, b); - } - } - -/* gth -*/ - u3_noun - u3qes_gth(u3_atom a, - u3_atom b) - { - union half c, d; - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - - return __(f16_lt(d.h, c.h)); - } - - u3_noun - u3wes_gth(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qes_gth(a, b); - } - } diff --git a/pkg/urbit/jets/e/ripe.c b/pkg/urbit/jets/e/ripe.c deleted file mode 100644 index 457068d47..000000000 --- a/pkg/urbit/jets/e/ripe.c +++ /dev/null @@ -1,45 +0,0 @@ -/* j/5/ripe.c -** -*/ -#include "all.h" -#include - -/* functions -*/ - static u3_atom - _cqe_ripe(u3_atom wid, u3_atom dat) - { - c3_w len_w; - if ( !u3r_word_fit(&len_w, wid) ) { - return u3m_bail(c3__fail); - } - else { - u3_atom ret; - c3_y out_y[20]; - c3_y *dat_y = u3r_bytes_alloc(0, len_w, dat); - - ret = ( 0 == urcrypt_ripemd160(dat_y, len_w, out_y) ) - ? u3i_bytes(20, out_y) - : u3_none; - - u3a_free(dat_y); - return ret; - } - } - - u3_noun - u3we_ripe(u3_noun cor) - { - u3_noun wid, dat; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &wid, - u3x_sam_3, &dat, 0) || - u3ud(wid) || u3ud(dat)) - ) - { - return u3m_bail(c3__exit); - } - else { - return u3l_punt("ripe", _cqe_ripe(wid, dat)); - } - } diff --git a/pkg/urbit/jets/e/rq.c b/pkg/urbit/jets/e/rq.c deleted file mode 100644 index 19af6acc6..000000000 --- a/pkg/urbit/jets/e/rq.c +++ /dev/null @@ -1,446 +0,0 @@ -/* j/e/rq.c -** -*/ -#include "all.h" -#include - -#define QUADNAN 0x7fff800000000000 - - union quad { - float128_t* q; - c3_w* c; - }; - -/* functions -*/ - static inline c3_t - _nan_test(float128_t* a) - { - return !f128M_eq(a, a); - } - - static inline void - _nan_unify(float128_t* a) - { - if ( _nan_test(a) ) - { - *( (c3_d*)a) = 0; - *(((c3_d*)a)+1) = QUADNAN; - } - } - - static inline void - _set_rounding(c3_w a) - { - switch ( a ) - { - default: - u3m_bail(c3__fail); - break; - case c3__n: - softfloat_roundingMode = softfloat_round_near_even; - break; - case c3__z: - softfloat_roundingMode = softfloat_round_minMag; - break; - case c3__u: - softfloat_roundingMode = softfloat_round_max; - break; - case c3__d: - softfloat_roundingMode = softfloat_round_min; - break; - } - } - -/* add -*/ - u3_noun - u3qeq_add(u3_atom a, - u3_atom b, - u3_atom r) - { - union quad c, d, e; - _set_rounding(r); - c.c = alloca(16); - d.c = alloca(16); - e.c = alloca(16); - - u3r_words(0, 4, c.c, a); - u3r_words(0, 4, d.c, b); - f128M_add(c.q, d.q, e.q); - _nan_unify(e.q); - - u3_atom f = u3i_words(4, e.c); - return f; - } - - u3_noun - u3weq_add(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qeq_add(a, b, u3x_at(30, cor)); - } - } - -/* sub -*/ - u3_noun - u3qeq_sub(u3_atom a, - u3_atom b, - u3_atom r) - { - union quad c, d, e; - _set_rounding(r); - c.c = alloca(16); - d.c = alloca(16); - e.c = alloca(16); - - u3r_words(0, 4, c.c, a); - u3r_words(0, 4, d.c, b); - f128M_sub(c.q, d.q, e.q); - _nan_unify(e.q); - - u3_atom f = u3i_words(4, e.c); - return f; - } - - u3_noun - u3weq_sub(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qeq_sub(a, b, u3x_at(30, cor)); - } - } - -/* mul -*/ - u3_noun - u3qeq_mul(u3_atom a, - u3_atom b, - u3_atom r) - { - union quad c, d, e; - _set_rounding(r); - c.c = alloca(16); - d.c = alloca(16); - e.c = alloca(16); - - u3r_words(0, 4, c.c, a); - u3r_words(0, 4, d.c, b); - f128M_mul(c.q, d.q, e.q); - _nan_unify(e.q); - - u3_atom f = u3i_words(4, e.c); - return f; - } - - u3_noun - u3weq_mul(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qeq_mul(a, b, u3x_at(30, cor)); - } - } - -/* div -*/ - u3_noun - u3qeq_div(u3_atom a, - u3_atom b, - u3_atom r) - { - union quad c, d, e; - _set_rounding(r); - c.c = alloca(16); - d.c = alloca(16); - e.c = alloca(16); - - u3r_words(0, 4, c.c, a); - u3r_words(0, 4, d.c, b); - f128M_div(c.q, d.q, e.q); - _nan_unify(e.q); - - u3_atom f = u3i_words(4, e.c); - return f; - } - - u3_noun - u3weq_div(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qeq_div(a, b, u3x_at(30, cor)); - } - } - -/* sqt -*/ - u3_noun - u3qeq_sqt(u3_atom a, - u3_atom r) - { - union quad c, d; - _set_rounding(r); - c.c = alloca(16); - d.c = alloca(16); - - u3r_words(0, 4, c.c, a); - f128M_sqrt(c.q, d.q); - _nan_unify(d.q); - - u3_atom e = u3i_words(4, d.c); - return e; - } - - u3_noun - u3weq_sqt(u3_noun cor) - { - u3_noun a; - - if ( c3n == (a = u3r_at(u3x_sam, cor)) || - c3n == u3ud(a) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qeq_sqt(a, u3x_at(30, cor)); - } - } - -/* fma -*/ - u3_noun - u3qeq_fma(u3_atom a, - u3_atom b, - u3_atom c, - u3_atom r) - { - union quad d, e, f, g; - _set_rounding(r); - d.c = alloca(16); - e.c = alloca(16); - f.c = alloca(16); - g.c = alloca(16); - - u3r_words(0, 4, d.c, a); - u3r_words(0, 4, e.c, b); - u3r_words(0, 4, f.c, c); - f128M_mulAdd(d.q, e.q, f.q, g.q); - _nan_unify(g.q); - - u3_atom h = u3i_words(4, g.c); - return h; - } - - u3_noun - u3weq_fma(u3_noun cor) - { - u3_noun a, b, c; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_6, &b, u3x_sam_7, &c, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) || - c3n == u3ud(c) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qeq_fma(a, b, c, u3x_at(30, cor)); - } - } - -/* lth -*/ - u3_noun - u3qeq_lth(u3_atom a, - u3_atom b) - { - union quad c, d; - c.c = alloca(16); - d.c = alloca(16); - - u3r_words(0, 4, c.c, a); - u3r_words(0, 4, d.c, b); - c3_o e = __(f128M_lt(c.q, d.q)); - - return e; - } - - u3_noun - u3weq_lth(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qeq_lth(a, b); - } - } - -/* lte -*/ - u3_noun - u3qeq_lte(u3_atom a, - u3_atom b) - { - union quad c, d; - c.c = alloca(16); - d.c = alloca(16); - - u3r_words(0, 4, c.c, a); - u3r_words(0, 4, d.c, b); - c3_o e = __(f128M_le(c.q, d.q)); - - return e; - } - - u3_noun - u3weq_lte(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qeq_lte(a, b); - } - } - -/* equ -*/ - u3_noun - u3qeq_equ(u3_atom a, - u3_atom b) - { - union quad c, d; - c.c = alloca(16); - d.c = alloca(16); - - u3r_words(0, 4, c.c, a); - u3r_words(0, 4, d.c, b); - c3_o e = __(f128M_eq(c.q, d.q)); - - return e; - } - - u3_noun - u3weq_equ(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qeq_equ(a, b); - } - } - -/* gte -*/ - u3_noun - u3qeq_gte(u3_atom a, - u3_atom b) - { - union quad c, d; - c.c = alloca(16); - d.c = alloca(16); - - u3r_words(0, 4, c.c, a); - u3r_words(0, 4, d.c, b); - c3_o e = __(f128M_le(d.q, c.q)); - - return e; - } - - u3_noun - u3weq_gte(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qeq_gte(a, b); - } - } - -/* gth -*/ - u3_noun - u3qeq_gth(u3_atom a, - u3_atom b) - { - union quad c, d; - c.c = alloca(16); - d.c = alloca(16); - - u3r_words(0, 4, c.c, a); - u3r_words(0, 4, d.c, b); - c3_o e = __(f128M_lt(d.q, c.q)); - - return e; - } - - u3_noun - u3weq_gth(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qeq_gth(a, b); - } - } diff --git a/pkg/urbit/jets/e/rs.c b/pkg/urbit/jets/e/rs.c deleted file mode 100644 index b0f2a4574..000000000 --- a/pkg/urbit/jets/e/rs.c +++ /dev/null @@ -1,390 +0,0 @@ -/* j/e/rs.c -** -*/ -#include "all.h" -#include - -#define SINGNAN 0x7fc00000 - - union sing { - float32_t s; - c3_w c; - }; - -/* functions -*/ - static inline c3_t - _nan_test(float32_t a) - { - return !f32_eq(a, a); - } - - static inline float32_t - _nan_unify(float32_t a) - { - if ( _nan_test(a) ) - { - *(c3_w*)(&a) = SINGNAN; - } - return a; - } - - static inline void - _set_rounding(c3_w a) - { - switch ( a ) - { - default: - u3m_bail(c3__fail); - break; - case c3__n: - softfloat_roundingMode = softfloat_round_near_even; - break; - case c3__z: - softfloat_roundingMode = softfloat_round_minMag; - break; - case c3__u: - softfloat_roundingMode = softfloat_round_max; - break; - case c3__d: - softfloat_roundingMode = softfloat_round_min; - break; - } - } - -/* add -*/ - u3_noun - u3qet_add(u3_atom a, - u3_atom b, - u3_atom r) - { - union sing c, d, e; - _set_rounding(r); - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - e.s = _nan_unify(f32_add(c.s, d.s)); - - return u3i_words(1, &e.c); - } - - u3_noun - u3wet_add(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qet_add(a, b, u3x_at(30, cor)); - } - } - -/* sub -*/ - u3_noun - u3qet_sub(u3_atom a, - u3_atom b, - u3_atom r) - { - union sing c, d, e; - _set_rounding(r); - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - e.s = _nan_unify(f32_sub(c.s, d.s)); - - return u3i_words(1, &e.c); - } - - u3_noun - u3wet_sub(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qet_sub(a, b, u3x_at(30, cor)); - } - } - -/* mul -*/ - u3_noun - u3qet_mul(u3_atom a, - u3_atom b, - u3_atom r) - { - union sing c, d, e; - _set_rounding(r); - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - e.s = _nan_unify(f32_mul(c.s, d.s)); - - return u3i_words(1, &e.c); - } - - u3_noun - u3wet_mul(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qet_mul(a, b, u3x_at(30, cor)); - } - } - -/* div -*/ - u3_noun - u3qet_div(u3_atom a, - u3_atom b, - u3_atom r) - { - union sing c, d, e; - _set_rounding(r); - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - e.s = _nan_unify(f32_div(c.s, d.s)); - - return u3i_words(1, &e.c); - } - - u3_noun - u3wet_div(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qet_div(a, b, u3x_at(30, cor)); - } - } - -/* sqt -*/ - u3_noun - u3qet_sqt(u3_atom a, - u3_atom r) - { - union sing c, d; - _set_rounding(r); - c.c = u3r_word(0, a); - d.s = _nan_unify(f32_sqrt(c.s)); - - return u3i_words(1, &d.c); - } - - u3_noun - u3wet_sqt(u3_noun cor) - { - u3_noun a; - - if ( c3n == (a = u3r_at(u3x_sam, cor)) || - c3n == u3ud(a) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qet_sqt(a, u3x_at(30, cor)); - } - } - -/* fma -*/ - u3_noun - u3qet_fma(u3_atom a, - u3_atom b, - u3_atom c, - u3_atom r) - { - union sing d, e, f, g; - _set_rounding(r); - d.c = u3r_word(0, a); - e.c = u3r_word(0, b); - f.c = u3r_word(0, c); - g.s = _nan_unify(f32_mulAdd(d.s, e.s, f.s)); - - return u3i_words(1, &g.c); - } - - u3_noun - u3wet_fma(u3_noun cor) - { - u3_noun a, b, c; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_6, &b, u3x_sam_7, &c, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) || - c3n == u3ud(c) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qet_fma(a, b, c, u3x_at(30, cor)); - } - } - -/* lth -*/ - u3_noun - u3qet_lth(u3_atom a, - u3_atom b) - { - union sing c, d; - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - - return __(f32_lt(c.s, d.s)); - } - - u3_noun - u3wet_lth(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qet_lth(a, b); - } - } - -/* lte -*/ - u3_noun - u3qet_lte(u3_atom a, - u3_atom b) - { - union sing c, d; - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - - return __(f32_le(c.s, d.s)); - } - - u3_noun - u3wet_lte(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qet_lte(a, b); - } - } - -/* equ -*/ - u3_noun - u3qet_equ(u3_atom a, - u3_atom b) - { - union sing c, d; - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - - return __(f32_eq(c.s, d.s)); - } - - u3_noun - u3wet_equ(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qet_equ(a, b); - } - } - -/* gte -*/ - u3_noun - u3qet_gte(u3_atom a, - u3_atom b) - { - union sing c, d; - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - - return __(f32_le(d.s, c.s)); - } - - u3_noun - u3wet_gte(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qet_gte(a, b); - } - } - -/* gth -*/ - u3_noun - u3qet_gth(u3_atom a, - u3_atom b) - { - union sing c, d; - c.c = u3r_word(0, a); - d.c = u3r_word(0, b); - - return __(f32_lt(d.s, c.s)); - } - - u3_noun - u3wet_gth(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0) || - c3n == u3ud(a) || - c3n == u3ud(b) ) - { - return u3m_bail(c3__exit); - } - else { - return u3qet_gth(a, b); - } - } diff --git a/pkg/urbit/jets/e/rub.c b/pkg/urbit/jets/e/rub.c deleted file mode 100644 index 48a1116b3..000000000 --- a/pkg/urbit/jets/e/rub.c +++ /dev/null @@ -1,85 +0,0 @@ -/* j/3/rub.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qe_rub(u3_atom a, - u3_atom b) - { - u3_atom c, d, e; - u3_atom w, x, y, z; - u3_atom p, q; - - u3_atom m; - { - c3_w bit_w = u3r_met(0, b); - u3_noun bit = u3i_words(1, &bit_w); - m = u3qa_add(a, bit); - u3z(bit); - } - - // Compute c and d. - { - x = u3k(a); - - while ( 0 == u3qc_cut(0, x, 1, b) ) { - u3_atom y = u3qa_inc(x); - - // Sanity check: crash if decoding more bits than available - if ( c3y == u3qa_gth(x, m)) { - // u3l_log("[%%rub-hard %d %d %d]", a, x, m); - return u3m_bail(c3__exit); - } - - u3z(x); - x = y; - } - if ( c3y == u3r_sing(x, a) ) { - u3z(x); - return u3nc(1, 0); - } - c = u3qa_sub(x, a); - d = u3qa_inc(x); - - u3z(x); - } - - // Compute e, p, q. - { - x = u3qa_dec(c); - y = u3qc_bex(x); - z = u3qc_cut(0, d, x, b); - - e = u3qa_add(y, z); - u3z(y); u3z(z); - - w = u3qa_add(c, c); - y = u3qa_add(w, e); - z = u3qa_add(d, x); - - p = u3qa_add(w, e); - q = u3qc_cut(0, z, e, b); - - u3z(w); u3z(x); u3z(y); u3z(z); - - return u3nc(p, q); - } - } - u3_noun - u3we_rub(u3_noun cor) - { - u3_noun a, b; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) || - (c3n == u3ud(a)) || - (c3n == u3ud(b)) ) - { - return u3m_bail(c3__fail); - } else { - return u3qe_rub(a, b); - } - } diff --git a/pkg/urbit/jets/e/scow.c b/pkg/urbit/jets/e/scow.c deleted file mode 100644 index 2d4150292..000000000 --- a/pkg/urbit/jets/e/scow.c +++ /dev/null @@ -1,389 +0,0 @@ -/* j/3/scow.c -** -*/ -#include "all.h" - -#include - -static -c3_y to_digit(c3_y tig) -{ - if (tig >= 10) { - return 87 + tig; - } else { - return '0' + tig; - } -} - -static -c3_y to_w_digit(c3_y tig) -{ - if (tig == 63) { - return '~'; - } else if (tig == 62) { - return '-'; - } else if (tig >= 36) { - return 29 + tig; - } else if (tig >= 10) { - return 87 + tig; - } else { - return '0' + tig; - } -} - -// gives the characters for a four 'digit' small hex atom. -static -void -_x_co_four(c3_w src, c3_y* a, c3_y* b, c3_y* c, c3_y* d) -{ - *d = to_digit(src & 0xF); - src >>= 4; - *c = to_digit(src & 0xF); - src >>= 4; - *b = to_digit(src & 0xF); - src >>= 4; - *a = to_digit(src & 0xF); -} - -// The parser always prints two digits on 0 in y-co. -static -void -_y_co_two(c3_w src, c3_y* a, c3_y* b) -{ - *b = to_digit(src % 10); - *a = to_digit(src / 10); -} - -// -static -u3_noun -_add_year(c3_w year, u3_noun out) -{ - while (year > 0) { - out = u3nc(to_digit(year % 10), out); - year = year / 10; - } - - return out; -} - -static -u3_noun -_print_da(u3_noun cor, u3_atom raw_da) -{ - u3_noun hok = u3j_cook("u3we_scow_print_da", u3k(cor), "yore"); - u3_noun yod = u3n_slam_on(hok, u3k(raw_da)); - - u3_noun out = 0; - - u3_atom age, year, month, day, hour, min, sec, f; - if (c3n == u3r_mean(yod, 4, &age, - 5, &year, - 6, &month, - 14, &day, - 30, &hour, - 62, &min, - 126, &sec, - 127, &f, - 0)) { - return u3m_bail(c3__exit); - } - - if (f != 0) { - u3_noun f_list = u3qb_flop(f); - - for (u3_noun cur = f_list; - _(u3a_is_cell(cur)); - cur = u3t(cur)) { - if (_(u3a_is_cat(u3h(cur)))) { - c3_y a, b, c, d; - _x_co_four(u3h(cur), &a, &b, &c, &d); - out = u3nq('.', a, b, u3nt(c, d, out)); - } else { - // No way to deal with big atoms. fall back. - u3z(yod); - u3z(out); - u3z(f_list); - return u3_none; - } - } - - u3z(f_list); - out = u3nc('.', out); - } - - // if there isn't a hex list and the h/m/s are all 0, skip printing hours. - if (f != 0 || hour != 0 || min != 0 || sec != 0) { - if (!_(u3a_is_cat(hour)) || - !_(u3a_is_cat(min)) || - !_(u3a_is_cat(sec))) { - // Input is weird, fallback to nock. - u3z(yod); - u3z(out); - return u3_none; - } - - c3_y sa, sb, ma, mb, ha, hb; - _y_co_two(sec, &sa, &sb); - out = u3nq('.', sa, sb, out); - - _y_co_two(min, &ma, &mb); - out = u3nq('.', ma, mb, out); - - _y_co_two(hour, &ha, &hb); - out = u3nq('.', ha, hb, out); - - out = u3nc('.', out); - } - - // We always print the Y.M.D. Unlike others, these numbers are unconstrained - // by length, but in practice, the month number and day number can only be up - // to two digits because of +yore. We still need to remove 0 prefixes, - // though. - if (!_(u3a_is_cat(day)) || day > 99 || - !_(u3a_is_cat(month)) || month > 99 || - !_(u3a_is_cat(year))) { - // Input is weird, fallback to nock. - u3z(yod); - u3z(out); - return u3_none; - } - - c3_y da, db; - _y_co_two(day, &da, &db); - out = u3nc(db, out); - if (da != '0') { - out = u3nc(da, out); - } - out = u3nc('.', out); - - c3_y ma, mb; - _y_co_two(month, &ma, &mb); - out = u3nc(mb, out); - if (ma != '0') { - out = u3nc(ma, out); - } - out = u3nc('.', out); - - // suffix the year with a '-' for BC dates - if (age == c3n) { - out = u3nc('-', out); - } - - // The year part is the only place where we have to explicitly loop over the - // input because it can be arbitrarily large or small. - out = _add_year(year, out); - - out = u3nc('~', out); - - u3z(yod); - return out; -} - -static -u3_noun -_print_p(u3_atom cor, u3_atom p) -{ - // Scramble the raw number to the concealed version. - u3_noun ob = u3j_cook("u3we_scow_ob_p", u3k(cor), "ob"); - u3_noun hok = u3j_cook("u3we_scow_fein_p", ob, "fein"); - u3_atom sxz = u3n_slam_on(hok, u3k(p)); - - // Simple galaxy case - if (c3y == u3qa_lth(sxz, 256)) { - c3_y a, b, c; - u3_po_to_suffix(sxz, &a, &b, &c); - u3z(sxz); - return u3nq('~', a, b, u3nc(c, 0)); - } - - u3_atom dyy = u3qc_met(4, sxz); - if (!_(u3a_is_cat(dyy))) { - u3z(sxz); - u3z(dyy); - return u3_none; - } - - u3_noun list = 0; - for (c3_w imp = 0; imp != dyy; ++imp) { - c3_w log = u3qc_end(4, 1, sxz); - c3_w prefix = u3qc_rsh(3, 1, log); - c3_w suffix = u3qc_end(3, 1, log); - - c3_y a, b, c, d, e, f; - u3_po_to_prefix(prefix, &a, &b, &c); - u3_po_to_suffix(suffix, &d, &e, &f); - - if (imp % 4 == 0) { - if (imp != 0) { - list = u3nt('-', '-', list); - } - } else { - list = u3nc('-', list); - } - - list = u3nq(a, b, c, u3nq(d, e, f, list)); - - sxz = u3qc_rsh(4, 1, sxz); - } - - u3z(sxz); - return u3nc('~', list); -} - -static -u3_noun -_print_ud(u3_atom ud) -{ - // number of characters printed "between" periods. - c3_i between = 0; - u3_noun list = 0; - - // increase input refcount to be consumed in u3ka_div(), which will free each - // intermediary state. - u3k(ud); - - do { - if (between == 3) { - list = u3nc('.', list); - between = 0; - } - - list = u3nc(u3ka_add(u3qa_mod(ud, 10), '0'), list); - between++; - ud = u3ka_div(ud, 10); - } while (ud != 0); - - return list; -} - -static -u3_noun -_print_uv(u3_atom uv) -{ - // number of characters printed "between" periods. - c3_i between = 0; - u3_noun list = 0; - - // increase input refcount to be consumed in u3ka_div(), which will free each - // intermediary state. - u3k(uv); - - do { - if (between == 5) { - list = u3nc('.', list); - between = 0; - } - - c3_y tig = u3qa_mod(uv, 32); - list = u3nc(to_digit(tig), list); - between++; - uv = u3ka_div(uv, 32); - } while (uv != 0); - - return u3nt('0', 'v', list); -} - -static -u3_noun -_print_uw(u3_atom uw) -{ - // number of characters printed "between" periods. - c3_i between = 0; - u3_noun list = 0; - - // increase input refcount to be consumed in u3ka_div(), which will free each - // intermediary state. - u3k(uw); - - do { - if (between == 5) { - list = u3nc('.', list); - between = 0; - } - - c3_y tig = u3qa_mod(uw, 64); - list = u3nc(to_w_digit(tig), list); - between++; - uw = u3ka_div(uw, 64); - } while (uw != 0); - - return u3nt('0', 'w', list); -} - -u3_noun -u3we_scow(u3_noun cor) -{ - u3_atom mod; - u3_atom atom; - - if (c3n == u3r_mean(cor, u3x_sam_2, &mod, - u3x_sam_3, &atom, 0)) { - return u3m_bail(c3__exit); - } - - switch (mod) { - case c3__da: - return _print_da(cor, atom); - - case 'p': - return _print_p(cor, atom); - - case c3__ud: - return _print_ud(atom); - - case c3__uv: - return _print_uv(atom); - - case c3__uw: - return _print_uw(atom); - - default: - return u3_none; - } -} - -u3_noun -u3we_scot(u3_noun cor) -{ - u3_atom mod; - u3_atom atom; - - if (c3n == u3r_mean(cor, u3x_sam_2, &mod, - u3x_sam_3, &atom, 0)) { - return u3m_bail(c3__exit); - } - - u3_noun tape; - switch (mod) { - case c3__da: - tape = _print_da(cor, atom); - break; - - case 'p': - tape = _print_p(cor, atom); - break; - - case c3__ud: - tape = _print_ud(atom); - break; - - case c3__uv: - tape = _print_uv(atom); - break; - - case c3__uw: - tape = _print_uw(atom); - break; - - default: - return u3_none; - } - - if (tape == u3_none) { - return tape; - } - u3_noun ret = u3qc_rap(3, tape); - u3z(tape); - return ret; -} diff --git a/pkg/urbit/jets/e/scr.c b/pkg/urbit/jets/e/scr.c deleted file mode 100644 index 0a04925de..000000000 --- a/pkg/urbit/jets/e/scr.c +++ /dev/null @@ -1,227 +0,0 @@ -/* j/5/scr.c -** -*/ -#include "all.h" -#include - -/* functions -*/ - static u3_weak - _cqes_hs(u3_atom p, c3_w pwd_w, - u3_atom s, c3_w sal_w, - u3_atom n, - u3_atom r, - u3_atom z, - u3_atom d) - { - u3_noun chk; - c3_w out_w; - - if ( !u3r_word_fit(&out_w, d) ) { - return u3m_bail(c3__fail); - } - if ( 0 == r || 0 == z ) { - return u3m_bail(c3__exit); - } - chk = u3qc_bex(31); - if ( (c3n == u3qa_lth(pwd_w, chk)) || - (c3n == u3qa_lth(sal_w, chk)) ) { - return u3m_bail(c3__exit); - } - u3z(chk); - chk = u3kc_bex(u3ka_dec(u3qc_xeb(n))); - if ( c3n == u3r_sing(n, chk) ) { - return u3m_bail(c3__exit); - } - u3z(chk); - if ( c3n == u3ka_lte( - u3ka_mul(u3qa_mul(128, r), u3ka_dec(u3qa_add(n, z))), - u3qc_bex(30)) ) { - return u3m_bail(c3__exit); - } - - if ( (u3r_met(6, n) > 1) || - (u3r_met(5, r) > 1) || - (u3r_met(5, z) > 1) ) { - return u3_none; - } - else { - u3_noun pro; - c3_d n_d = u3r_chub(0, n); - c3_w r_w = u3r_word(0, r), - z_w = u3r_word(0, z); - c3_y *pwd_y = u3a_malloc(pwd_w), - *sal_y = u3a_malloc(sal_w), - *out_y = u3a_malloc(d); - u3r_bytes(0, pwd_w, pwd_y, p); - u3r_bytes(0, sal_w, sal_y, s); - pro = ( 0 == urcrypt_scrypt(pwd_y, pwd_w, - sal_y, sal_w, - n_d, r_w, z_w, - out_w, out_y) ) - ? u3i_bytes(out_w, out_y) - : u3_none; - u3a_free(pwd_y); - u3a_free(sal_y); - u3a_free(out_y); - return pro; - } - } - - static u3_weak - _cqes_hsl(u3_atom p, u3_atom pl, - u3_atom s, u3_atom sl, - u3_atom n, - u3_atom r, - u3_atom z, - u3_atom d) - { - c3_w pwd_w, sal_w; - if ( !(u3r_word_fit(&pwd_w, pl) && - u3r_word_fit(&sal_w, sl)) ) { - return u3m_bail(c3__fail); - } - else { - return _cqes_hs(p, pwd_w, s, sal_w, n, r, z, d); - } - } - - u3_noun - u3wes_hsl(u3_noun cor) - { - u3_noun p, pl, s, sl, n, r, z, d; - u3_noun q; - - u3x_quil(u3x_at(u3x_sam, cor), &p, &pl, &s, &sl, &q); - u3x_qual(q, &n, &r, &z, &d); - - if ( !(_(u3a_is_atom(p)) && _(u3a_is_atom(pl)) && - _(u3a_is_atom(s)) && _(u3a_is_atom(sl)) && - _(u3a_is_atom(n)) && _(u3a_is_atom(r)) && - _(u3a_is_atom(z)) && _(u3a_is_atom(d))) ) { - return u3m_bail(c3__exit); - } - else { - return u3l_punt("scr-hsl", _cqes_hsl(p, pl, s, sl, n, r, z, d)); - } - } - - static u3_weak - _cqes_hsh(u3_atom p, - u3_atom s, - u3_atom n, - u3_atom r, - u3_atom z, - u3_atom d) - { - return _cqes_hs(p, u3r_met(3, p), - s, u3r_met(3, s), - n, r, z, d); - } - - u3_noun - u3wes_hsh(u3_noun cor) - { - u3_noun p, s, n, r, z, d; - u3_noun q; - - u3x_quil(u3x_at(u3x_sam, cor), &p, &s, &n, &r, &q); - u3x_cell(q, &z, &d); - - if ( !(_(u3a_is_atom(p)) && _(u3a_is_atom(s)) && - _(u3a_is_atom(n)) && _(u3a_is_atom(r)) && - _(u3a_is_atom(z)) && _(u3a_is_atom(d))) ) { - return u3m_bail(c3__exit); - } - else { - return u3l_punt("scr-hsh", _cqes_hsh(p, s, n, r, z, d)); - } - } - - static u3_atom - _cqes_pb(u3_atom p, c3_w pwd_w, - u3_atom s, c3_w sal_w, - u3_atom c, - u3_atom d) - { - if ( (c > (1 << 28)) || - (d > (1 << 30)) ) { - // max key length 1gb - // max iterations 2^28 - return u3m_bail(c3__exit); - } - else { - u3_noun pro; - c3_w out_w; - c3_y *pwd_y = u3a_malloc(pwd_w), - *sal_y = u3a_malloc(sal_w), - *out_y = u3a_malloc(d); - u3r_bytes(0, pwd_w, pwd_y, p); - u3r_bytes(0, sal_w, sal_y, s); - urcrypt_scrypt_pbkdf_sha256(pwd_y, pwd_w, sal_y, sal_w, c, d, out_y); - pro = u3i_bytes(d, out_y); - u3a_free(pwd_y); - u3a_free(sal_y); - u3a_free(out_y); - return pro; - } - } - - static u3_noun - _cqes_pbl(u3_atom p, u3_atom pl, - u3_atom s, u3_atom sl, - u3_atom c, - u3_atom d) - { - c3_w pwd_w, sal_w; - if ( !(u3r_word_fit(&pwd_w, pl) && - u3r_word_fit(&sal_w, sl)) ) { - return u3m_bail(c3__fail); - } - else { - return _cqes_pb(p, pwd_w, s, sal_w, c, d); - } - } - - u3_noun - u3wes_pbl(u3_noun cor) - { - u3_noun p, pl, s, sl, c, d; - u3_noun q; - - u3x_quil(u3x_at(u3x_sam, cor), &p, &pl, &s, &sl, &q); - u3x_cell(q, &c, &d); - - if ( !(_(u3a_is_atom(p)) && _(u3a_is_atom(s)) && - _(u3a_is_atom(pl)) && _(u3a_is_atom(sl)) && - _(u3a_is_atom(c)) && _(u3a_is_atom(d))) ) { - return u3m_bail(c3__exit); - } - else { - return _cqes_pbl(p, pl, s, sl, c, d); - } - } - - static u3_atom - _cqes_pbk(u3_atom p, u3_atom s, u3_atom c, u3_atom d) - { - return _cqes_pb(p, u3r_met(3, p), - s, u3r_met(3, s), - c, d); - } - - u3_noun - u3wes_pbk(u3_noun cor) - { - u3_noun p, s, c, d; - - u3x_qual(u3x_at(u3x_sam, cor), &p, &s, &c, &d); - - if ( !(_(u3a_is_atom(p)) && _(u3a_is_atom(s)) && - _(u3a_is_atom(c)) && _(u3a_is_atom(d))) ) { - return u3m_bail(c3__exit); - } - else { - return _cqes_pbk(p, s, c, d); - } - } diff --git a/pkg/urbit/jets/e/secp.c b/pkg/urbit/jets/e/secp.c deleted file mode 100644 index 21c6f7daa..000000000 --- a/pkg/urbit/jets/e/secp.c +++ /dev/null @@ -1,297 +0,0 @@ - /* j/5/secp.c -** -*/ -#include "all.h" -#include "urcrypt.h" -#include - -static urcrypt_secp_context* sec_u; - -/* call at process start */ -void -u3je_secp_init() -{ - c3_y ent_y[32]; - ent_getentropy(ent_y, 32); - sec_u = malloc(urcrypt_secp_prealloc_size()); - - if ( 0 != urcrypt_secp_init(sec_u, ent_y) ) { - u3l_log("u3e_secp_init failed"); - abort(); - } -} - -/* call at process end */ -void -u3je_secp_stop() -{ - urcrypt_secp_destroy(sec_u); - free(sec_u); - sec_u = NULL; -} - -/* util funcs - */ -static c3_t -_cqes_in_order(u3_atom a) -{ - // this is the "n" parameter of the secp256k1 curve - static const c3_w now_w[8] = { - 0xd0364141, 0xbfd25e8c, 0xaf48a03b, 0xbaaedce6, - 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff - }; - - if ( 0 == a ) { - return 0; - } - else if ( c3y == u3a_is_cat(a) ) { - return 1; - } - else { - u3a_atom* a_u = u3a_to_ptr(a); - c3_w len_w = a_u->len_w; - - if ( len_w < 8 ) { - return 1; - } - else if ( len_w > 8 ) { - return 0; - } - else { - c3_y i_y; - c3_w *buf_w = a_u->buf_w; - // loop from most to least significant words - for ( i_y = 8; i_y > 0; ) { - c3_w b_w = buf_w[i_y], - o_w = now_w[--i_y]; - if ( b_w < o_w ) { - return 1; - } - else if ( b_w > o_w ) { - return 0; - } - } - return 1; - } - } -} - -static void -_cqes_unpack_fe(u3_atom k, c3_y out_y[32]) -{ - if ( _cqes_in_order(k) ) { - u3r_bytes(0, 32, out_y, k); - } - else { - u3m_bail(c3__exit); - } -} - -/* sign hash with priv key - */ -static u3_noun -_cqes_sign(u3_atom has, - u3_atom prv) -{ - c3_y has_y[32]; - - if ( 0 != u3r_bytes_fit(32, has_y, has) ) { - return u3m_bail(c3__exit); - } - else { - c3_y prv_y[32], v_y, r_y[32], s_y[32]; - _cqes_unpack_fe(prv, prv_y); - - return( 0 == urcrypt_secp_sign(sec_u, has_y, prv_y, &v_y, r_y, s_y) ) - ? u3nt(v_y, u3i_bytes(32, r_y), u3i_bytes(32, s_y)) - : u3_none; - } -} - -u3_noun -u3we_sign(u3_noun cor) -{ - - u3_noun has, prv; - - if ( (c3n == u3r_mean(cor, - u3x_sam_2, &has, - u3x_sam_3, &prv, - 0)) || - (c3n == u3ud(has)) || - (c3n == u3ud(prv))) { - return u3m_bail(c3__exit); - } - else { - return u3l_punt("secp-sign", _cqes_sign(has, prv)); - } -} - -/* recover pubkey from signature (which is how we verify signatures) -*/ -static u3_noun -_cqes_reco(u3_atom has, - u3_atom siv, /* signature: v */ - u3_atom sir, /* signature: r */ - u3_atom sis) /* signature: s */ -{ - c3_y has_y[32]; - if ( !((siv < 4) && (0 == u3r_bytes_fit(32, has_y, has)) ) ) { - return u3m_bail(c3__exit); - } - else { - c3_y sir_y[32], sis_y[32], x_y[32], y_y[32]; - c3_y siv_y = (c3_y) siv; - _cqes_unpack_fe(sir, sir_y); - _cqes_unpack_fe(sis, sis_y); - return - ( 0 == urcrypt_secp_reco(sec_u, has_y, siv, sir_y, sis_y, x_y, y_y) ) - ? u3nc(u3i_bytes(32, x_y), u3i_bytes(32, y_y)) - : u3_none; - } -} - -u3_noun -u3we_reco(u3_noun cor) -{ - u3_noun has, /* hash */ - siv, sir, sis; /* signature: v, r, s */ - - if ( (c3n == u3r_mean(cor, - u3x_sam_2, &has, - u3x_sam_6, &siv, - u3x_sam_14, &sir, - u3x_sam_15, &sis, - 0)) || - (c3n == u3ud(has)) || - (c3n == u3ud(siv)) || - (c3n == u3ud(sir)) || - (c3n == u3ud(sis)) ) { - return u3m_bail(c3__exit); - } - else { - return u3l_punt("secp-reco", _cqes_reco(has, siv, sir, sis)); - } -} - -static u3_atom -_cqes_make(u3_atom has, - u3_atom prv) -{ - c3_y has_y[32]; - - if ( 0 != u3r_bytes_fit(32, has_y, has) ) { - return u3m_bail(c3__exit); - } - else { - c3_y prv_y[32], out_y[32]; - _cqes_unpack_fe(prv, prv_y); - return ( 0 == urcrypt_secp_make(has_y, prv_y, out_y) ) - ? u3i_bytes(32, out_y) - : u3_none; - } -} - -u3_noun -u3we_make(u3_noun cor) -{ - u3_noun has, prv; - if ( (c3n == u3r_mean(cor, - u3x_sam_2, &has, - u3x_sam_3, &prv, - 0)) || - (c3n == u3ud(has)) || - (c3n == u3ud(prv)) ) { - return u3m_bail(c3__exit); - } - else { - return u3l_punt("secp-make", _cqes_make(has, prv)); - } -} - -/* create a schnorr signature -*/ -static u3_weak -_cqes_sosi(u3_atom sk, u3_atom m, u3_atom a) -{ - c3_y key_y[32]; - c3_y mes_y[32]; - c3_y aux_y[32]; - - if ( (0 != u3r_bytes_fit(32, key_y, sk)) || - (0 != u3r_bytes_fit(32, mes_y, m)) || - (0 != u3r_bytes_fit(32, aux_y, a)) ) - { - return u3m_bail(c3__exit); - } - else { - c3_y sig_y[64]; - - return - ( 0 == urcrypt_secp_schnorr_sign(sec_u, key_y, mes_y, aux_y, sig_y) ) - ? u3i_bytes(64, sig_y) - : u3_none; - } -} - -u3_noun -u3we_sosi(u3_noun cor) -{ - u3_noun key, mes, aux; - - if ( (c3n == u3r_mean(cor, - u3x_sam_2, &key, - u3x_sam_6, &mes, - u3x_sam_7, &aux, - 0)) || - (c3n == u3ud(key)) || - (c3n == u3ud(mes)) || - (c3n == u3ud(aux)) ) - { - return u3m_bail(c3__exit); - } - else { - return u3l_punt("secp-sosi", _cqes_sosi(key, mes, aux)); - } -} - -/* verify a schnorr signature -*/ -static u3_atom -_cqes_sove(u3_atom pk, u3_atom m, u3_atom sig) -{ - c3_y pub_y[32]; - c3_y mes_y[32]; - c3_y sig_y[64]; - - if ( (0 != u3r_bytes_fit(32, pub_y, pk)) || - (0 != u3r_bytes_fit(32, mes_y, m)) || - (0 != u3r_bytes_fit(64, sig_y, sig)) ) - { - return u3m_bail(c3__exit); - } - else { - return __(urcrypt_secp_schnorr_veri(sec_u, sig_y, mes_y, pub_y)); - } -} - -u3_noun -u3we_sove(u3_noun cor) -{ - u3_noun pub, mes, sig; - - if ( (c3n == u3r_mean(cor, - u3x_sam_2, &pub, - u3x_sam_6, &mes, - u3x_sam_7, &sig, - 0)) || - (c3n == u3ud(pub)) || - (c3n == u3ud(mes)) || - (c3n == u3ud(sig)) ) - { - return u3m_bail(c3__exit); - } - else { - return _cqes_sove(pub, mes, sig); - } -} diff --git a/pkg/urbit/jets/e/sha1.c b/pkg/urbit/jets/e/sha1.c deleted file mode 100644 index 1423e5299..000000000 --- a/pkg/urbit/jets/e/sha1.c +++ /dev/null @@ -1,40 +0,0 @@ -/* j/5/sha1.c -** -*/ -#include "all.h" -#include - -/* functions -*/ - static u3_noun - _cqe_sha1(u3_atom wid, u3_atom dat) - { - c3_w len_w; - if ( !u3r_word_fit(&len_w, wid) ) { - return u3m_bail(c3__fail); - } - else { - c3_y out_y[20]; - c3_y *dat_y = u3r_bytes_alloc(0, len_w, dat); - - urcrypt_sha1(dat_y, len_w, out_y); - u3a_free(dat_y); - return u3i_bytes(20, out_y); - } - } - - u3_noun - u3we_sha1(u3_noun cor) - { - u3_noun wid, dat; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &wid, u3x_sam_3, &dat, 0)) || - (c3n == u3ud(wid)) || - (c3n == u3ud(dat)) ) - { - return u3m_bail(c3__exit); - } - else { - return _cqe_sha1(wid, dat); - } - } diff --git a/pkg/urbit/jets/e/shax.c b/pkg/urbit/jets/e/shax.c deleted file mode 100644 index 29945ee82..000000000 --- a/pkg/urbit/jets/e/shax.c +++ /dev/null @@ -1,193 +0,0 @@ -/* j/5/shax.c -** -*/ -#include "all.h" -#include - -/* functions -*/ - - static u3_atom - _cqe_shay(u3_atom wid, - u3_atom dat) - { - c3_w len_w; - if ( !u3r_word_fit(&len_w, wid) ) { - return u3m_bail(c3__fail); - } - else { - c3_y out_y[32]; - c3_y* dat_y = u3r_bytes_alloc(0, len_w, dat); - urcrypt_shay(dat_y, len_w, out_y); - u3a_free(dat_y); - return u3i_bytes(32, out_y); - } - } - - static u3_atom - _cqe_shax(u3_atom a) - { - c3_w len_w; - c3_y out_y[32]; - c3_y* dat_y = u3r_bytes_all(&len_w, a); - urcrypt_shay(dat_y, len_w, out_y); - u3a_free(dat_y); - return u3i_bytes(32, out_y); - } - - static u3_atom - _cqe_shal(u3_atom wid, - u3_atom dat) - { - c3_w len_w; - if ( !u3r_word_fit(&len_w, wid) ) { - return u3m_bail(c3__fail); - } - else { - c3_y out_y[64]; - c3_y* dat_y = u3r_bytes_alloc(0, len_w, dat); - urcrypt_shal(dat_y, len_w, out_y); - u3a_free(dat_y); - return u3i_bytes(64, out_y); - } - } - - static u3_atom - _cqe_shas(u3_atom sal, - u3_atom ruz) - { - c3_w sal_w, ruz_w; - c3_y *sal_y, *ruz_y, out_y[32]; - - sal_y = u3r_bytes_all(&sal_w, sal); - ruz_y = u3r_bytes_all(&ruz_w, ruz); - urcrypt_shas(sal_y, sal_w, ruz_y, ruz_w, out_y); - u3a_free(sal_y); - u3a_free(ruz_y); - return u3i_bytes(32, out_y); - } - - u3_noun - u3we_shax(u3_noun cor) - { - u3_noun a; - - if ( (u3_none == (a = u3r_at(u3x_sam, cor))) || - (c3n == u3ud(a)) ) - { - return u3m_bail(c3__exit); - } else { - return _cqe_shax(a); - } - } - - u3_noun - u3we_shay(u3_noun cor) - { - u3_noun a, b; - - if ( (u3_none == (a = u3r_at(u3x_sam_2, cor))) || - (u3_none == (b = u3r_at(u3x_sam_3, cor))) || - (c3n == u3ud(a)) || - (c3n == u3ud(b)) ) - { - return u3m_bail(c3__exit); - } else { - return _cqe_shay(a, b); - } - } - - u3_noun - u3we_shal(u3_noun cor) - { - u3_noun a, b; - - if ( (u3_none == (a = u3r_at(u3x_sam_2, cor))) || - (u3_none == (b = u3r_at(u3x_sam_3, cor))) || - (c3n == u3ud(a)) || - (c3n == u3ud(b)) ) - { - return u3m_bail(c3__exit); - } else { - return _cqe_shal(a, b); - } - } - - u3_noun - u3we_shas(u3_noun cor) - { - u3_noun sal, ruz; - - if ( (u3_none == (sal = u3r_at(u3x_sam_2, cor))) || - (u3_none == (ruz = u3r_at(u3x_sam_3, cor))) || - (c3n == u3ud(sal)) || - (c3n == u3ud(ruz)) ) - { - return u3m_bail(c3__exit); - } else { - return _cqe_shas(sal, ruz); - } - } - - static u3_noun - _og_list(u3_noun a, - u3_noun b, - u3_noun c) - { - u3_noun l = u3_nul; - - if ( !_(u3a_is_cat(b)) ) { - return u3m_bail(c3__fail); - } - while ( 0 != b ) { - u3_noun x = u3qc_mix(a, c); - u3_noun y = u3qc_mix(b, x); - u3_noun d = _cqe_shas(c3_s4('o','g','-','b'), y); - u3_noun m; - - u3z(x); u3z(y); - - if ( b < 256 ) { - u3_noun e = u3qc_end(0, b, d); - - u3z(d); - m = u3nc(b, e); - b = 0; - } else { - m = u3nc(256, d); - c = d; - - b -= 256; - } - l = u3nc(m, l); - } - return u3kb_flop(l); - } - - u3_noun - u3qeo_raw(u3_atom a, - u3_atom b) - { - u3_noun x = u3qc_mix(b, a); - u3_noun c = _cqe_shas(c3_s4('o','g','-','a'), x); - u3_noun l = _og_list(a, b, c); - u3_noun r = u3qc_can(0, l); - - u3z(l); - u3z(c); - u3z(x); - - return r; - } - - u3_noun - u3weo_raw(u3_noun cor) - { - u3_noun a, b; - - if ( c3n == u3r_mean(cor, u3x_sam, &b, u3x_con_sam, &a, 0) ) { - return u3m_bail(c3__exit); - } else { - return u3qeo_raw(a, b); - } - } diff --git a/pkg/urbit/jets/e/slaw.c b/pkg/urbit/jets/e/slaw.c deleted file mode 100644 index 09c470043..000000000 --- a/pkg/urbit/jets/e/slaw.c +++ /dev/null @@ -1,474 +0,0 @@ -/* j/3/slaw.c -** -*/ -#include "all.h" - -#include - -static inline u3_noun -_parse_ud(u3_noun a) -{ - u3_weak pro; - - if ( u3_none == (pro = u3s_sift_ud(u3x_atom(a))) ) { - return u3_nul; - } - - return u3nc(u3_nul, pro); -} - -static -u3_noun get_syllable(c3_c** cur_ptr, c3_c* one, c3_c* two, c3_c* three) { - if (islower((*cur_ptr)[0]) && islower((*cur_ptr)[1]) && - islower((*cur_ptr)[2])) { - *one = (*cur_ptr)[0]; - *two = (*cur_ptr)[1]; - *three = (*cur_ptr)[2]; - (*cur_ptr) += 3; - return c3y; - } else { - return c3n; - } -} - -static u3_noun -combine(u3_noun p, u3_noun q) -{ - if ( (c3y == u3a_is_atom(p)) || (c3y == u3a_is_atom(q)) ) { - return 0; - } - - u3_noun lef = u3qa_mul(256, u3t(q)); - u3_noun ret = u3nc(0, u3qa_add(u3t(p), lef)); - u3z(lef); - u3z(p); u3z(q); - - return ret; -} - -#define ENSURE_NOT_END() do { \ - if (*cur == 0) { \ - u3a_free(c); \ - return u3_none; \ - } \ - } while (0) - -#define CONSUME(x) do { \ - if (*cur != x) { \ - u3a_free(c); \ - return u3_none; \ - } \ - cur++; \ - } while (0) - -#define TRY_GET_SYLLABLE(prefix) \ - c3_c prefix##_one, prefix##_two, prefix##_three; \ - if (c3n == get_syllable(&cur, & prefix##_one, & prefix##_two, & prefix##_three)) { \ - u3a_free(c); \ - return u3_none; \ - } - -u3_noun -_parse_p(u3_noun cor, u3_noun txt) { - c3_c* c = u3a_string(txt); - - c3_c* cur = c; - CONSUME('~'); - - // We at least have a sig prefix. We're now going to parse tuples of three - // lowercase letters. Our naming pattern for the pieces we read is [a b c d - // ...] as we read them. - TRY_GET_SYLLABLE(a); - - // There was only one syllable. If it's a valid suffix syllable, then - // it's a galaxy. We don't even have to run this through the scrambler or - // check for validity since its already a (unit @). - if (*cur == 0) { - u3a_free(c); - return u3_po_find_suffix(a_one, a_two, a_three); - } - - TRY_GET_SYLLABLE(b); - - // There were only two syllables. If they are a valid prefix and suffix, then - // it's a star. - if (*cur == 0) { - u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three); - u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three); - u3_atom combined = combine(b_part, a_part); - u3a_free(c); - return combined; - } - - // There must now be a - or it is invalid - CONSUME('-'); - - TRY_GET_SYLLABLE(c); - - ENSURE_NOT_END(); - - TRY_GET_SYLLABLE(d); - - if (*cur == 0) { - u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three); - u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three); - u3_noun c_part = u3_po_find_prefix(c_one, c_two, c_three); - u3_noun d_part = u3_po_find_suffix(d_one, d_two, d_three); - - u3_noun m = combine(d_part, combine(c_part, combine(b_part, a_part))); - u3a_free(c); - - if (_(u3a_is_atom(m))) { - return 0; - } - - u3_atom raw = u3k(u3t(m)); - u3z(m); - - u3_noun ob = u3j_cook("u3we_slaw_ob_p", u3k(cor), "ob"); - u3_noun hok = u3j_cook("u3we_slaw_fynd_p", ob, "fynd"); - return u3nc(0, u3n_slam_on(hok, raw)); - } - - // There must now be a - or it is invalid. - CONSUME('-'); - - // The next possible case is a "short" moon. (~ab-cd-ef) - TRY_GET_SYLLABLE(e); - - ENSURE_NOT_END(); - - TRY_GET_SYLLABLE(f); - - if (*cur == 0) { - u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three); - u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three); - u3_noun c_part = u3_po_find_prefix(c_one, c_two, c_three); - u3_noun d_part = u3_po_find_suffix(d_one, d_two, d_three); - u3_noun e_part = u3_po_find_prefix(e_one, e_two, e_three); - u3_noun f_part = u3_po_find_suffix(f_one, f_two, f_three); - - u3_noun m = combine(f_part, combine(e_part, combine(d_part, - combine(c_part, combine(b_part, a_part))))); - u3a_free(c); - - if (_(u3a_is_atom(m))) { - return 0; - } - - u3_atom raw = u3k(u3t(m)); - u3z(m); - u3_noun ob = u3j_cook("u3we_slaw_ob_p", u3k(cor), "ob"); - u3_noun hok = u3j_cook("u3we_slaw_fynd_p", ob, "fynd"); - return u3nc(0, u3n_slam_on(hok, raw)); - } - - // There must now be a - or it is invalid. - CONSUME('-'); - - // The next possible case is a "long" moon. (~ab-cd-ef-gh) - TRY_GET_SYLLABLE(g); - - ENSURE_NOT_END(); - - TRY_GET_SYLLABLE(h); - - if (*cur == 0) { - u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three); - u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three); - u3_noun c_part = u3_po_find_prefix(c_one, c_two, c_three); - u3_noun d_part = u3_po_find_suffix(d_one, d_two, d_three); - u3_noun e_part = u3_po_find_prefix(e_one, e_two, e_three); - u3_noun f_part = u3_po_find_suffix(f_one, f_two, f_three); - u3_noun g_part = u3_po_find_prefix(g_one, g_two, g_three); - u3_noun h_part = u3_po_find_suffix(h_one, h_two, h_three); - - u3_noun m = combine(h_part, combine(g_part, combine(f_part, - combine(e_part, combine(d_part, combine(c_part, - combine(b_part, a_part))))))); - u3a_free(c); - - if (_(u3a_is_atom(m))) { - return 0; - } - - u3_atom raw = u3k(u3t(m)); - u3z(m); - u3_noun ob = u3j_cook("u3we_slaw_ob_p", u3k(cor), "ob"); - u3_noun hok = u3j_cook("u3we_slaw_fynd_p", ob, "fynd"); - return u3nc(0, u3n_slam_on(hok, raw)); - } - - // At this point, the only thing it could be is a long comet, of the form - // ~ab-cd-ef-gh--ij-kl-mn-op - - CONSUME('-'); - CONSUME('-'); - - TRY_GET_SYLLABLE(i); - ENSURE_NOT_END(); - TRY_GET_SYLLABLE(j); - CONSUME('-'); - TRY_GET_SYLLABLE(k); - ENSURE_NOT_END(); - TRY_GET_SYLLABLE(l); - CONSUME('-'); - TRY_GET_SYLLABLE(m); - ENSURE_NOT_END(); - TRY_GET_SYLLABLE(n); - CONSUME('-'); - TRY_GET_SYLLABLE(o); - ENSURE_NOT_END(); - TRY_GET_SYLLABLE(p); - - if (*cur != 0) { - // We've parsed all of a comet shape, and there's still more in the - // string. Bail back to the interpreter. - u3a_free(c); - return u3_none; - } - - // We have a long comet. Time to jam it all together. We rely on combine() - // for the error checking and we don't have to scramble comet names. - u3_noun a_part = u3_po_find_prefix(a_one, a_two, a_three); - u3_noun b_part = u3_po_find_suffix(b_one, b_two, b_three); - u3_noun c_part = u3_po_find_prefix(c_one, c_two, c_three); - u3_noun d_part = u3_po_find_suffix(d_one, d_two, d_three); - u3_noun e_part = u3_po_find_prefix(e_one, e_two, e_three); - u3_noun f_part = u3_po_find_suffix(f_one, f_two, f_three); - u3_noun g_part = u3_po_find_prefix(g_one, g_two, g_three); - u3_noun h_part = u3_po_find_suffix(h_one, h_two, h_three); - u3_noun i_part = u3_po_find_prefix(i_one, i_two, i_three); - u3_noun j_part = u3_po_find_suffix(j_one, j_two, j_three); - u3_noun k_part = u3_po_find_prefix(k_one, k_two, k_three); - u3_noun l_part = u3_po_find_suffix(l_one, l_two, l_three); - u3_noun m_part = u3_po_find_prefix(m_one, m_two, m_three); - u3_noun n_part = u3_po_find_suffix(n_one, n_two, n_three); - u3_noun o_part = u3_po_find_prefix(o_one, o_two, o_three); - u3_noun p_part = u3_po_find_suffix(p_one, p_two, p_three); - - u3a_free(c); - - return combine(p_part, combine(o_part, combine(n_part, combine(m_part, - combine(l_part, combine(k_part, combine(j_part, combine(i_part, - combine(h_part, combine(g_part, combine(f_part, combine(e_part, - combine(d_part, combine(c_part, combine(b_part, a_part))))))))))))))); -} - -#define PARSE_NONZERO_NUMBER(numname) \ - c3_w numname = 0; \ - do { \ - if (cur[0] > '9' || cur[0] < '1') { \ - u3a_free(c); \ - return u3_none; \ - } \ - numname = cur[0] - '0'; \ - cur++; \ - while (isdigit(cur[0])) { \ - numname = u3ka_mul(numname, 10); \ - numname = u3ka_add(numname, cur[0] - '0'); \ - cur++; \ - } \ - } while (0) - -#define PARSE_INCLUDING_ZERO_NUMBER(numname) \ - c3_w numname = 0; \ - do { \ - if (cur[0] > '9' || cur[0] < '0') { \ - u3a_free(c); \ - return u3_none; \ - } \ - numname = cur[0] - '0'; \ - cur++; \ - while (isdigit(cur[0])) { \ - numname = u3ka_mul(numname, 10); \ - numname = u3ka_add(numname, cur[0] - '0'); \ - cur++; \ - } \ - } while (0) - -#define PARSE_HEX_DIGIT(out) \ - do { \ - if (cur[0] >= '0' && cur[0] <= '9') { \ - out = cur[0] - '0'; \ - } else if (cur[0] >= 'a' && cur[0] <= 'f') { \ - out = 10 + cur[0] - 'a'; \ - } else { \ - u3a_free(c); \ - return u3_none; \ - } \ - cur++; \ - } while(0) - - -u3_noun -_parse_da(u3_noun cor, u3_noun txt) { - c3_c* c = u3a_string(txt); - - c3_c* cur = c; - CONSUME('~'); - - // Parse out an arbitrary year number. Starts with a nonzero digit followed - // by a series of any digits. - PARSE_NONZERO_NUMBER(year); - - // Parse the optional negative sign for BC dates. - u3_noun bc = c3y; - if (cur[0] == '-') { - bc = c3n; - cur++; - } - - CONSUME('.'); - - // Parse out a two digit month (mot:ag). Either a single digit 1-9 or 1[012]. - c3_y month; - if (cur[0] == '1') { - if (cur[1] <= '2' && cur[1] >= '0') { - // This is a two number month. - month = 10 + cur[1] - '0'; - cur += 2; - } else { - // This is January. - month = 1; - cur++; - } - } else if (cur[0] <= '9' && cur[0] >= '2') { - month = cur[0] - '0'; - cur++; - } else { - u3a_free(c); - return u3_none; - } - - CONSUME('.'); - - // Parse out a two digit day (dip:ag). This number can be really big, so we - // can track number of days since September 1993. - PARSE_NONZERO_NUMBER(day); - - if (cur[0] == 0) { - u3a_free(c); - u3_noun hok = u3j_cook("u3we_slaw_parse_da", u3k(cor), "year"); - u3_noun res = u3n_slam_on(hok, - u3nt(u3nc(bc, year), month, - u3nc(day, u3nq(0, 0, 0, 0)))); - return u3nc(0, res); - } - - CONSUME('.'); - CONSUME('.'); - - PARSE_INCLUDING_ZERO_NUMBER(hour); - CONSUME('.'); - PARSE_INCLUDING_ZERO_NUMBER(minute); - CONSUME('.'); - PARSE_INCLUDING_ZERO_NUMBER(second); - - if (cur[0] == 0) { - u3a_free(c); - u3_noun hok = u3j_cook("u3we_slaw_parse_da", u3k(cor), "year"); - u3_noun res = u3n_slam_on(hok, - u3nt(u3nc(bc, year), month, - u3nc(day, u3nq(hour, minute, second, 0)))); - return u3nc(0, res); - } - - CONSUME('.'); - CONSUME('.'); - - // Now we have to parse a list of hexidecimal numbers 0-f of length 4 only - // (zero padded otherwise) separated by dots. - u3_noun list = 0; - while (1) { - // Parse 4 hex digits - c3_y one, two, three, four; - PARSE_HEX_DIGIT(one); - PARSE_HEX_DIGIT(two); - PARSE_HEX_DIGIT(three); - PARSE_HEX_DIGIT(four); - - c3_w current = (one << 12) + (two << 8) + (three << 4) + four; - list = u3nc(u3i_words(1, ¤t), list); - - if (cur[0] == 0) { - u3a_free(c); - - u3_noun flopped = u3qb_flop(list); - u3z(list); - - u3_noun hok = u3j_cook("u3we_slaw_parse_da", u3k(cor), "year"); - u3_noun res = u3n_slam_on(hok, - u3nt(u3nc(bc, year), month, - u3nc(day, - u3nq(hour, minute, second, flopped)))); - return u3nc(0, res); - } - - CONSUME('.'); - } -} - -#undef ENSURE_NOT_END -#undef CONSUME -#undef TRY_GET_SYLLABLE -#undef PARSE_NONZERO_NUMBER -#undef PARSE_HEX_DIGIT - -u3_noun -_parse_tas(u3_noun txt) { - // For any symbol which matches, txt will return itself as a - // value. Therefore, this is mostly checking validity. - c3_c* c = u3a_string(txt); - - // First character must represent a lowercase letter - c3_c* cur = c; - if (!islower(cur[0])) { - u3a_free(c); - return 0; - } - cur++; - - while (cur[0] != 0) { - if (!(islower(cur[0]) || isdigit(cur[0]) || cur[0] == '-')) { - u3a_free(c); - return 0; - } - - cur++; - } - - u3a_free(c); - return u3nc(0, u3k(txt)); -} - -u3_noun -u3we_slaw(u3_noun cor) -{ - u3_noun mod; - u3_noun txt; - - if (c3n == u3r_mean(cor, u3x_sam_2, &mod, - u3x_sam_3, &txt, 0)) { - return u3m_bail(c3__exit); - } - - switch (mod) { - case c3__da: - return _parse_da(cor, txt); - - case 'p': - return _parse_p(cor, txt); - - case c3__ud: - return _parse_ud(txt); - - // %ta is used once in link.hoon. don't bother. - - case c3__tas: - return _parse_tas(txt); - - default: - return u3_none; - } -} diff --git a/pkg/urbit/jets/e/tape.c b/pkg/urbit/jets/e/tape.c deleted file mode 100644 index 022b09d92..000000000 --- a/pkg/urbit/jets/e/tape.c +++ /dev/null @@ -1,53 +0,0 @@ -/* j/3/tape.c -** -*/ -#include "all.h" - - -/* functions -*/ - static u3_noun - _norm(u3_noun a) - { - if ( c3n == u3du(a) ) { - return u3_nul; - } else { - return u3nc(((c3y == u3du(u3h(a))) ? u3_nul : u3k(u3h(a))), - _norm(u3t(a))); - } - } - - static u3_noun - _good(u3_noun a) - { - while ( 1 ) { - if ( u3_nul == a ) { - return c3y; - } - if ( c3n == u3ud(u3h(a)) ) { - return c3n; - } - a = u3t(a); - } - } - - u3_noun - u3qe_tape(u3_noun a) - { - if ( c3y == _good(a) ) { - return u3k(a); - } else { - return _norm(a); - } - } - u3_noun - u3we_tape(u3_noun cor) - { - u3_noun a; - - if ( (u3_none == (a = u3r_at(u3x_sam, cor))) ) { - return u3m_bail(c3__fail); - } else { - return u3qe_tape(a); - } - } diff --git a/pkg/urbit/jets/e/trip.c b/pkg/urbit/jets/e/trip.c deleted file mode 100644 index 6f986cb7c..000000000 --- a/pkg/urbit/jets/e/trip.c +++ /dev/null @@ -1,30 +0,0 @@ -/* j/5/trip.c -** -*/ -#include "all.h" - -u3_noun -u3qe_trip(u3_atom a) -{ - return u3qc_rip(3, 1, a); -} - -u3_noun -u3we_trip(u3_noun cor) -{ - u3_noun a = u3x_at(u3x_sam, cor); - - if ( c3n == u3ud(a) ) { - return u3m_bail(c3__exit); - } - - return u3qe_trip(a); -} - -u3_atom -u3ke_trip(u3_noun a) -{ - u3_atom pro = u3qe_trip(a); - u3z(a); - return pro; -} diff --git a/pkg/urbit/jets/f/ap.c b/pkg/urbit/jets/f/ap.c deleted file mode 100644 index ac6554803..000000000 --- a/pkg/urbit/jets/f/ap.c +++ /dev/null @@ -1,1081 +0,0 @@ -/* j/6/ap.c -** -*/ -#include "all.h" - - -/** forward declares -**/ - u3_noun u3wfp_rake(u3_noun); - u3_noun u3wfp_open(u3_noun); - u3_noun u3wfp_hack(u3_noun); - - static u3_noun - _ap_open_l(u3_noun, u3_noun, u3_noun); - - // make sure these match the array below! - // -# define _ap_jet_open 0 -# define _ap_jet_rake 1 -# define _ap_jet_hack 2 - -#if 0 - static u3_noun - _open_in(u3_noun ter, u3_noun gen); - /* ~(. al gen) - */ - static u3_noun - _al_bore(u3_noun ter, - u3_noun gen) - { - u3_noun gat = u3j_hook(u3k(ter), "al"); - - return u3i_molt(gat, u3x_sam, u3nc(c3__herb, u3k(gen)), 0); - } - /* ~(. al gen) - */ - static u3_noun - _al_core(u3_noun ter, - u3_noun gen) - { - u3_noun gat = u3j_hook(u3k(ter), "al"); - - return u3i_molt(gat, u3x_sam, u3k(gen), 0); - } - - /* van is transferred, gen is retained - */ - static u3_noun - _ap_bunt(u3_noun van, - u3_noun gen) - { - u3_noun pro = u3qfl_bunt(van, gen); - - u3z(van); - return pro; - } - -/** open cases -**/ - -#define _open_do_p(stem) \ - static u3_noun _open_in_##stem \ - ( u3_noun ter, u3_noun p_gen) - -#define _open_do_pq(stem) \ - static u3_noun _open_in_##stem \ - ( u3_noun ter, u3_noun p_gen, u3_noun q_gen) - -#define _open_do_pqr(stem) \ - static u3_noun _open_in_##stem \ - ( u3_noun ter, u3_noun p_gen, u3_noun q_gen, u3_noun r_gen) - -#define _open_do_pqrs(stem) \ - static u3_noun _open_in_##stem \ - ( u3_noun ter, u3_noun p_gen, u3_noun q_gen, u3_noun r_gen, \ - u3_noun s_gen) - -/*** -**** -***/ - _open_do_pq(tsbr) // =: - { - return u3nt(c3__tsls, - _ap_bunt(_al_core(ter, p_gen), p_gen), - u3k(q_gen)); - } - _open_do_pq(tscl) // =: - { - return u3nt(c3__tsgr, - u3nt(c3__cncb, - u3nc(u3nc(u3_nul, 1), - u3_nul), - u3k(p_gen)), - u3k(q_gen)); - } - _open_do_pqr(tsdt) // =. - { - return u3nt(c3__tsgr, - u3nt(c3__cncb, - u3nc(u3nc(u3_nul, 1), - u3_nul), - u3nc(u3nc(u3k(p_gen), - u3k(q_gen)), - u3_nul)), - u3k(r_gen)); - } - _open_do_pq(tsgl) // =< - { - return u3nt(c3__tsgr, - u3k(q_gen), - u3k(p_gen)); - } - _open_do_pq(tshp) // =- - { - return u3nt(c3__tsls, - u3k(q_gen), - u3k(p_gen)); - } - _open_do_pq(tsls) // =+ - { - return u3nt(c3__tsgr, - u3nc(u3k(p_gen), - u3nc(u3_nul, 1)), - u3k(q_gen)); - } - _open_do_p(tssg) // =~ - { - if ( !_(u3du(p_gen)) ) { - return u3nc(0, 1); - } else { - u3_noun tp_gen = u3t(p_gen); - u3_noun ip_gen = u3h(p_gen); - - if ( (u3_nul == p_gen) ) { - return u3nc(u3_blip, 1); - } - else if ( (u3_nul == tp_gen) ) { - return u3k(ip_gen); - } - else { - return u3nt(c3__tsgr, - u3k(ip_gen), - _open_in_tssg(ter, tp_gen)); - } - } - } -/*** -**** -***/ - _open_do_p(bccb) // $_ - { - return _ap_bunt(_al_core(ter, p_gen), p_gen); - } - _open_do_p(bctr) // $* - { - return - u3nc(c3__ktsg, - _ap_bunt(_al_core(ter, p_gen), - p_gen)); - } - _open_do_p(bczp) // $! - { - return u3nt(c3__bccb, - c3__axil, - u3k(p_gen)); - } -/*** -**** -***/ - _open_do_p(brhp) // |- - { - return u3nt(c3__tsgl, - u3nc(c3__cnzy, u3_blip), - u3nc(c3__brdt, u3k(p_gen))); - } - _open_do_p(brdt) // |. - { - return u3nc(c3__brcn, - u3nt(u3nt(u3_blip, c3__ash, u3k(p_gen)), - u3_nul, - u3_nul)); - } - -/*** -**** -***/ - _open_do_p(wtbr) // ?| - { - if ( (u3_nul == p_gen) ) { - return u3nt(c3__dtzz, 'f', c3n); - } - else { - u3_noun ip_gen = u3h(p_gen); - u3_noun tp_gen = u3t(p_gen); - - return u3nq(c3__wtcl, - u3k(ip_gen), - u3nt(c3__dtzz, 'f', c3y), - _open_in_wtbr(ter, tp_gen)); - } - } - _open_do_pqr(wtkt) // ?^ - { - return u3nq(c3__wtcl, - u3nt(c3__wtts, - u3nt(c3__axil, c3__atom, u3_blip), - u3k(p_gen)), - u3k(r_gen), - u3k(q_gen)); - } - _open_do_pq(wtgl) // ?< - { - return u3nq(c3__wtcl, - u3k(p_gen), - u3nc(c3__zpzp, u3_nul), - u3k(q_gen)); - } - _open_do_pqr(wtdt) // ?. - { - return u3nq(c3__wtcl, - u3k(p_gen), - u3k(r_gen), - u3k(q_gen)); - } - _open_do_pq(wtgr) // ?> - { - return u3nq(c3__wtcl, - u3k(p_gen), - u3k(q_gen), - u3nc(c3__zpzp, u3_nul)); - } - _open_do_pq(wthp) // ?- - { - if ( (u3_nul == q_gen) ) { - return u3nc(c3__zpfs, - u3nc(c3__cnzz, - u3k(p_gen))); - } - else { - u3_noun iq_gen = u3h(q_gen); - u3_noun tq_gen = u3t(q_gen); - u3_noun piq_gen = u3h(iq_gen); - u3_noun qiq_gen = u3t(iq_gen); - - return u3nq(c3__wtcl, - u3nt(c3__wtts, - u3k(piq_gen), - u3k(p_gen)), - u3k(qiq_gen), - _open_in_wthp(ter, p_gen, tq_gen)); - } - } - _open_do_p(wtpm) // ?& - { - if ( (u3_nul == p_gen) ) { - return u3nt(c3__dtzz, 'f', c3y); - } - else { - u3_noun ip_gen = u3h(p_gen); - u3_noun tp_gen = u3t(p_gen); - - return u3nq(c3__wtcl, - u3k(ip_gen), - _open_in_wtpm(ter, tp_gen), - u3nt(c3__dtzz, 'f', c3n)); - } - } - _open_do_pqr(wtls) // ?+ - { u3_noun tul = u3nc(u3nc(u3nc(c3__axil, c3__noun), - u3k(q_gen)), - u3_nul); - u3_noun zal = u3qb_weld(r_gen, tul); - u3_noun ret = u3nt(c3__wthp, u3k(p_gen), zal); - - u3z(tul); - return ret; - - } - _open_do_pqr(wtpt) // ?@ - { - return u3nq(c3__wtcl, - u3nt(c3__wtts, - u3nt(c3__axil, - c3__atom, - u3_blip), - u3k(p_gen)), - u3k(q_gen), - u3k(r_gen)); - } - _open_do_pqr(wtsg) // ?~ - { - return u3nq(c3__wtcl, - u3nt(c3__wtts, - u3nc(c3__axil, c3__null), - u3k(p_gen)), - u3k(q_gen), - u3k(r_gen)); - } - _open_do_p(wtzp) // ?! - { - return u3nq(c3__wtcl, - u3k(p_gen), - u3nt(c3__dtzz, 'f', c3n), - u3nt(c3__dtzz, 'f', c3y)); - } -/*** -**** -***/ - _open_do_pq(zpcb) // !_ - { - return u3k(q_gen); - } - _open_do_p(zpgr) // !> - { - return u3nq(c3__cnhp, - u3nc(c3__cnzy, c3__onan), - u3nt(c3__zpsm, - u3nc(c3__bctr, - u3nc(c3__herb, - u3nc(c3__cnzy, - c3__abel))), - u3k(p_gen)), - u3_nul); - } -/*** -**** -***/ - _open_do_pq(clhp) // :- - { - return u3nc(u3k(p_gen), - u3k(q_gen)); - } - _open_do_pq(clcb) // :_ - { - return u3nc(u3k(q_gen), - u3k(p_gen)); - } - _open_do_p(clcn) // :% - { - return u3nc(u3nc(c3__clsg, - u3k(p_gen)), - u3nc(c3__bczp, c3__null)); - } - _open_do_pqrs(clkt) // :^ - { - return u3nq(u3k(p_gen), - u3k(q_gen), - u3k(r_gen), - u3k(s_gen)); - } - _open_do_pqr(clls) // :+ - { - return u3nt(u3k(p_gen), - u3k(q_gen), - u3k(r_gen)); - } - _open_do_p(clsg) // :~ - { - if ( (u3_nul == p_gen) ) { - return u3nt(c3__dtzz, 'n', u3_nul); - } - else { - u3_noun ip_gen = u3h(p_gen); - u3_noun tp_gen = u3t(p_gen); - - return u3nc(u3k(ip_gen), - _open_in_clsg(ter, tp_gen)); - } - } - _open_do_p(cltr) // :* - { - if ( (u3_nul == p_gen) ) { - return u3nc(c3__zpzp, u3_nul); - } - else { - u3_noun ip_gen = u3h(p_gen); - u3_noun tp_gen = u3t(p_gen); - - if ( (u3_nul == tp_gen) ) { - return u3k(ip_gen); - } else { - return u3nc(u3k(ip_gen), - _open_in_cltr(ter, tp_gen)); - } - } - } -/*** -**** -***/ - _open_do_pq(cncb) // %_ - { - return u3nc(c3__ktls, - u3nq(u3nc(c3__cnzz, u3k(p_gen)), - c3__cnts, - u3k(p_gen), - u3k(q_gen))); - } -#if 0 - _open_do_pq(cncl) // %: - { - return u3nq - (c3__cnsg, - u3nc(u3_blip, u3_nul), - u3k(p_gen), - u3k(q_gen)); - } -#endif - _open_do_pq(cndt) // %. - { - return u3nt(c3__cnhp, - u3k(q_gen), - u3nc(u3k(p_gen), u3_nul)); - } - _open_do_pqrs(cnkt) // %^ - { - return u3nq(c3__cnhp, - u3k(p_gen), - u3k(q_gen), - u3nt(u3k(r_gen), - u3k(s_gen), - u3_nul)); - } - _open_do_pq(cnhp) // %- - { - if ( (u3_nul == q_gen) ) { - return u3nt(c3__tsgr, - u3k(p_gen), - u3nc(c3__cnzy, u3_blip)); - } else { - return u3nq(c3__cncl, - u3k(p_gen), - c3__cltr, - u3k(q_gen)); - } - } - _open_do_pqr(cnls) // %+ - { - return u3nc(c3__cnhp, - u3nq(u3k(p_gen), - u3k(q_gen), - u3k(r_gen), - u3_nul)); - } - _open_do_pqr(cnsg) // %~ - { - return u3nq(c3__cntr, - u3k(p_gen), - u3k(q_gen), - u3nc(u3nc(u3nc(u3nc(u3_nul, 6), 0), u3k(r_gen)), 0)); - } - _open_do_p(cnzy) // %cnzy - { - return u3nt(c3__cnts, - u3nc(u3k(p_gen), u3_nul), - u3_nul); - } - _open_do_p(cnzz) // %cnzz - { - return u3nt(c3__cnts, u3k(p_gen), u3_nul); - } -/*** -**** -***/ - _open_do_p(hxgl) // #< - { - return u3nq(c3__cnhp, - u3nc(c3__cnzy, c3__noah), - u3nc(c3__zpgr, - u3nc(c3__cltr, u3k(p_gen))), - u3_nul); - } - _open_do_p(hxgr) // #> - { - return u3nq(c3__cnhp, - u3nc(c3__cnzy, c3__cain), - u3nc(c3__zpgr, - u3nc(c3__cltr, u3k(p_gen))), - u3_nul); - } -/*** -**** -***/ - _open_do_pq(ktdt) // ^. - { - return u3nt(c3__ktls, - u3nq(c3__cnhp, u3k(p_gen), u3k(q_gen), u3_nul), - u3k(q_gen)); - } -#if 0 - _open_do_pq(kthp) // ^- - { - return u3nt(c3__ktls, - _ap_bunt(_al_bore(ter, p_gen), p_gen), - u3k(q_gen)); - } -#endif -/*** -**** -***/ - _open_do_pq(brcb) // |_ - { - return u3nt(c3__tsls, - u3nc(c3__bctr, u3k(p_gen)), - u3nc(c3__brcn, u3k(q_gen))); - } - _open_do_pq(brkt) // |^ - { - u3_noun diz = u3nc(c3__ash, u3k(p_gen)); - u3_noun ret = u3nt(c3__tsgr, - u3nc(c3__brcn, - u3qdb_put(q_gen, u3_blip, diz)), - u3nc(c3__cnzy, u3_blip)); - - c3_assert(0); - u3z(diz); - return ret; - } - _open_do_pq(brls) // |+ - { - return u3nc(c3__ktbr, - u3nt(c3__brts, - u3k(p_gen), - u3k(q_gen))); - } - _open_do_p(brwt) // |? - { - return u3nt(c3__ktwt, - c3__brdt, - u3k(p_gen)); - } -/*** -**** -***/ - _open_do_pq(sgts) // ~= - { - return u3nt(c3__sggr, - u3nc(c3__germ, u3k(p_gen)), - u3k(q_gen)); - } -#if 0 - _open_do_pq(sgbr) // ~| - { - return u3nt - (c3__sggr, - u3nc(c3__mean, u3k(p_gen)), - u3k(q_gen)); - } -#endif - _open_do_pq(sggl) // ~> - { - return u3nt(c3__tsgl, - u3nq(c3__sggr, u3k(p_gen), u3_nul, 1), - u3k(q_gen)); - } - _open_do_pq(sgbc) // ~$ - { - return u3nt(c3__sggr, - u3nq(c3__live, - c3__dtzz, - u3_blip, - u3k(p_gen)), - u3k(q_gen)); - } - _open_do_pq(sgcb) // ~_ - { - return u3nt(c3__sggr, - u3nc(c3__mean, - u3nc(c3__brdt, - u3k(p_gen))), - u3k(q_gen)); - } - static u3_noun - _sgcn_a(u3_noun r_gen, - u3_noun nob) - { - if ( c3n == u3du(r_gen) ) { - return u3k(nob); - } else { - u3_noun ir_gen = u3h(r_gen); - u3_noun tr_gen = u3t(r_gen); - u3_noun pir_gen, qir_gen; - - u3x_cell(ir_gen, &pir_gen, &qir_gen); - - return u3nc(u3nc(u3nt(c3__dtzz, u3_blip, u3k(pir_gen)), - u3nc(c3__zpts, u3k(qir_gen))), - _sgcn_a(tr_gen, nob)); - } - } - _open_do_pqrs(sgcn) // ~% - { - return u3nt(c3__sggl, - u3nq(c3__sgcn, - c3__clls, - u3nt(c3__dtzz, u3_blip, u3k(p_gen)), - u3nt(u3nc(c3__zpts, u3k(q_gen)), - c3__clsg, - _sgcn_a(r_gen, u3_nul))), - u3k(s_gen)); - } - _open_do_pq(sgfs) // ~/ - { - return u3nc(c3__sgcn, - u3nq(u3k(p_gen), - u3nc(u3_nul, 7), - u3_nul, - u3k(q_gen))); - } - _open_do_pq(sgls) // ~+ - { - return u3nt(c3__sggr, - u3nq(c3__sgls, c3__dtzz, u3_blip, u3k(p_gen)), - u3k(q_gen)); - } - _open_do_pqr(sgpm) // ~& - { - return u3nt(c3__sggr, - u3nt(c3__slog, - u3nt(c3__dtzy, u3_blip, u3k(p_gen)), - u3nq(c3__cnhp, u3nc(c3__cnzy, c3__cain), - u3nc(c3__zpgr, u3k(q_gen)), u3_nul)), - u3k(r_gen)); - } - _open_do_pqrs(sgwt) // ~? - { - return u3nt(c3__tsls, - u3nq(c3__wtdt, - u3k(q_gen), - u3nc(c3__bczp, c3__null), - u3nc(u3nc(c3__bczp, c3__null), u3k(r_gen))), - u3nq(c3__wtsg, - u3nc(u3nc(u3_nul, 2),u3_nul), - u3nt(c3__tsgr, - u3nc(u3_nul, 3), - u3k(s_gen)), - u3nq(c3__sgpm, - u3k(p_gen), - u3nc(u3_nul, 5), - u3nt(c3__tsgr, - u3nc(u3_nul, 3), - u3k(s_gen))))); - } -/*** -**** -***/ - static u3_noun - _smcl_in(u3_noun q_gen) - { - u3_noun hq_gen = u3h(q_gen); - u3_noun tq_gen = u3t(q_gen); - - if ( c3n == u3du(tq_gen) ) { - return u3nt(c3__tsgr, - u3nc(u3_nul, 3), - u3k(hq_gen)); - } else { - return u3nc(c3__cnhp, - u3nq(u3nc(u3_nul, 2), - u3nt(c3__tsgr, - u3nc(u3_nul, 3), - u3k(hq_gen)), - _smcl_in(tq_gen), - u3_nul)); - } - } - _open_do_pq(smcl) - { - if ( c3n == u3du(q_gen) ) { - return u3nc(c3__zpzp, u3_nul); - } - else if ( u3_nul == u3t(q_gen) ) { - return u3k(u3h(q_gen)); - } - else { - return u3nt(c3__tsls, - u3k(p_gen), - _smcl_in(q_gen)); - } - } -#if 0 - _open_do_pq(smsm) - { - return - u3nt(c3__tsgr, u3nq(c3__ktts, c3__v, u3_nul, 1), - u3nt(c3__tsls, - u3nt(c3__ktts, c3__a, - u3nt(c3__tsgr, u3nc(c3__cnzy, c3__v), - u3k(p_gen))), - u3nt(c3__tsls, - u3nt(c3__ktts, c3__b, - u3nt(c3__tsgr, - u3nc(c3__cnzy, c3__v), - u3k(q_gen))), - u3nt(c3__tsls, - u3nt(c3__ktts, c3__c, - u3nq(c3__cnhp, - u3nc(c3__cnzy, c3__a), - u3nc(c3__cnzy, c3__b), - u3_nul)), - u3nt(c3__wtgr, - u3nt(c3__dtts, - u3nc(c3__cnzy, c3__c), - u3nc(c3__cnzy, c3__b)), - u3nc(c3__cnzy, c3__c)))))); - } -#endif - -/* functions -*/ - /** open - **/ - static u3_noun - _open_in(u3_noun ter, - u3_noun gen) - { - u3_noun p_gen, q_gen, r_gen, s_gen; - - return u3_none; - - if ( c3y == u3ud(gen) ) { - // printf("studly\n"); - // u3_err("stud m", gen); - return u3m_bail(c3__exit); - - return u3nt(c3__cnts, - u3nc(u3k(gen), u3_nul), - u3_nul); - } - else switch ( u3h(gen) ) { - default: return u3_none; - - case u3_nul: { - return u3nt(c3__cnts, - u3nc(u3k(gen), u3_nul), - u3_nul); - } - -# define _open_p(stem) \ - case c3__##stem: \ - return _open_in_##stem(ter, u3t(gen)); \ - -# define _open_pq(stem) \ - case c3__##stem: \ - if ( c3n == u3r_cell(u3t(gen), &p_gen, &q_gen) ) { \ - return u3m_bail(c3__fail); \ - } else return _open_in_##stem(ter, p_gen, q_gen); - -# define _open_pqr(stem) \ - case c3__##stem: \ - if ( c3n == u3r_trel(u3t(gen), &p_gen, &q_gen, &r_gen) ) { \ - return u3m_bail(c3__fail); \ - } else return _open_in_##stem(ter, p_gen, q_gen, r_gen); - -# define _open_pqrs(stem) \ - case c3__##stem: \ - if ( c3n == u3r_qual\ - (u3t(gen), &p_gen, &q_gen, &r_gen, &s_gen) )\ - { \ - return u3m_bail(c3__fail); \ - } else return _open_in_##stem(ter, p_gen, q_gen, r_gen, s_gen); - - _open_p (bccb); - _open_p (bctr); - _open_p (bczp); - - _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_pq (cncb); - // _open_pq (cncl); - _open_pq (cndt); - _open_pqrs(cnkt); - _open_pq (cnhp); - _open_pqr (cnls); - _open_pqr (cnsg); - _open_p (cnzy); - _open_p (cnzz); - - _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_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); - } - } - - /** rake - **/ - u3_noun - u3qfp_rake(u3_noun gen) - { - u3_noun p_gen, q_gen; - - if ( c3y == u3ud(gen) ) { - return u3nc(u3k(gen), u3_nul); - } - else switch ( u3h(gen) ) { - default: return u3m_error("rake-twig"); - - case u3_nul: return u3nc(u3k(gen), u3_nul); - - case c3__cnzy: { - return u3nc(u3k(u3t(gen)), u3_nul); - } - case c3__cnzz: { - return u3k(u3t(gen)); - } - case c3__cnts: { - if ( c3n == u3r_cell(u3t(gen), &p_gen, &q_gen) ) { - return u3m_bail(c3__fail); - } - else { - if ( u3_nul != q_gen ) { - return u3m_bail(c3__fail); - } - else { - return u3k(p_gen); - } - } - } - case c3__zpcb: { - if ( c3n == u3r_cell(u3t(gen), &p_gen, &q_gen) ) { - return u3m_bail(c3__fail); - } - else return u3qfp_rake(q_gen); - } - } - } - u3_noun - u3wfp_rake(u3_noun cor) - { - u3_noun gen; - - if ( u3_none == (gen = u3r_at(u3x_sam, cor)) ) { - return u3m_bail(c3__fail); - } else { - return u3qfp_rake(gen); - } - } - - /** hack - **/ - u3_noun - u3qfp_hack(u3_noun ter, - u3_noun gen) - { - u3_noun p_gen, q_gen; - u3_noun ret; - - if ( c3y == u3du(u3h(gen)) ) { - return u3nt(c3y, - u3k(u3h(gen)), - u3k(u3t(gen))); - } - else switch ( u3h(gen) ) { - case c3__tsgr: u3x_cell(u3t(gen), &p_gen, &q_gen); - { - if ( (c3n == u3du(p_gen)) || (u3_nul != u3h(p_gen)) ) { - return u3nc(c3n, u3k(gen)); - } - else { - u3_noun pyr = u3qfp_hack(ter, q_gen); - - if ( c3y == u3h(pyr) ) { - ret = u3nt(c3y, - u3nt(c3__tsgr, - u3k(p_gen), - u3k(u3h(u3t(pyr)))), - u3nt(c3__tsgr, - u3k(p_gen), - u3k(u3t(u3t(pyr))))); - } - else { - ret = u3nc(c3n, - u3nt(c3__tsgr, - u3k(p_gen), - u3k(u3t(pyr)))); - } - u3z(pyr); - return ret; - } - } - case c3__zpcb: u3x_cell(u3t(gen), &p_gen, &q_gen); - { - u3_noun pyr = u3qfp_hack(ter, q_gen); - - if ( c3y == u3h(pyr) ) { - ret = u3nt(c3y, - u3nt(c3__zpcb, - u3k(p_gen), - u3k(u3h(u3t(pyr)))), - u3nt(c3__zpcb, - u3k(p_gen), - u3k(u3t(u3t(pyr))))); - } - else { - ret = u3nc(c3n, - u3nt(c3__zpcb, - u3k(p_gen), - u3k(u3t(pyr)))); - } - u3z(pyr); - return ret; - } - default: break; - } - - { - u3_noun voq = _ap_open_l(ter, gen); - - if ( u3_none == voq ) { - return u3nc(c3n, u3k(gen)); - } - else if ( c3y == u3r_sing(voq, gen) ) { - return u3nc(c3n, voq); - } - else { - ret = u3qfp_hack(ter, voq); - - u3z(voq); - return ret; - } - } - } - - u3_noun - u3wfp_hack(u3_noun cor) - { - u3_noun gen; - - if ( u3_none == (gen = u3r_at(u3x_sam, cor)) ) { - return u3m_bail(c3__fail); - } else { - u3_noun ter = u3r_at(u3x_con, cor); - - return u3qfp_hack(ter, gen); - } - } -#endif - -/* boilerplate -*/ - static u3_noun - _ap_core(u3_noun ter, - u3_noun gen) - { - u3_noun gat = u3j_cook("_ap_core-ap", u3k(ter), "ap"); - - return u3i_molt(gat, u3x_sam, u3k(gen), 0); - } - - static u3_noun - _ar_core(u3_noun van, - u3_noun ref, - u3_noun syn) - { - u3_noun gat = u3j_hook(u3k(van), "ar"); - - return u3i_molt(gat, u3x_sam, u3nc(u3k(ref), u3k(syn)), 0); - } - -/* fish -*/ - u3_noun - u3qfr_fish(u3_noun van, - u3_noun ref, - u3_noun syn, - u3_noun axe) - { - u3_noun gat = u3j_soft(_ar_core(van, ref, syn), "fish"); - - return u3n_kick_on(u3i_molt(gat, - u3x_sam, - u3k(axe), - 0)); - } - -/* open -*/ - static u3_noun - _ap_open_n(u3_noun ter, - u3_noun fab, - u3_noun gen) - { - u3_noun cor = _ap_core(ter, gen); - -#if 1 - if ( c3n == fab ) { - cor = u3i_molt(cor, 14, c3n, 0); - } -#endif - return u3j_soft(cor, "open"); - } - static u3_noun - _ap_open_l(u3_noun ter, - u3_noun fab, - u3_noun gen) - { -#if 0 - u3_noun pro = _open_in(ter, gen); - - if ( u3_none != pro ) { - return pro; - } else { - return _ap_open_n(ter, gen); - } -#else - return _ap_open_n(ter, fab, gen); -#endif - } - - u3_noun - u3qfp_open(u3_noun ter, - u3_noun fab, - u3_noun gen) - { - return _ap_open_l(ter, fab, gen); - } - - u3_noun - u3wfp_open(u3_noun cor) - { - u3_noun gen; - - if ( u3_none == (gen = u3r_at(u3x_sam, cor)) ) { - return u3m_bail(c3__fail); - } else { - u3_noun ter = u3r_at(u3x_con, cor); - - return u3qfp_open(ter, c3y, gen); - } - } - diff --git a/pkg/urbit/jets/f/cell.c b/pkg/urbit/jets/f/cell.c deleted file mode 100644 index f4987eb8b..000000000 --- a/pkg/urbit/jets/f/cell.c +++ /dev/null @@ -1,29 +0,0 @@ -/* j/6/cell.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qf_cell(u3_noun hed, - u3_noun tal) - { - if ( (c3__void == hed) || (c3__void == tal) ) { - return c3__void; - } else { - return u3nt(c3__cell, u3k(hed), u3k(tal)); - } - } - u3_noun - u3wf_cell(u3_noun cor) - { - u3_noun hed, tal; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &hed, u3x_sam_3, &tal, 0) ) { - return u3m_bail(c3__fail); - } else { - return u3qf_cell(hed, tal); - } - } diff --git a/pkg/urbit/jets/f/comb.c b/pkg/urbit/jets/f/comb.c deleted file mode 100644 index eeb136fc1..000000000 --- a/pkg/urbit/jets/f/comb.c +++ /dev/null @@ -1,70 +0,0 @@ -/* j/6/comb.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qf_comb(u3_noun mal, - u3_noun buz) - { - if ( (u3_none == mal) || (u3_none == buz) ) { - return u3_none; - } - else { - u3_noun p_mal, q_mal, p_buz, q_buz, pp_buz, pq_buz; - - if ( (c3y == u3r_p(mal, 0, &p_mal)) && (0 != p_mal) ) { - if ( (c3y == u3r_p(buz, 0, &p_buz)) && (0 != p_buz) ) { - return u3nc(0, - u3qc_peg(p_mal, p_buz)); - } - else if ( c3y == u3r_pq(buz, 2, &p_buz, &q_buz) && - c3y == u3r_p(p_buz, 0, &pp_buz) && - c3y == u3r_p(q_buz, 0, &pq_buz) ) - { - return u3nt(2, - u3nc(0, - u3qc_peg(p_mal, pp_buz)), - u3nc(0, - u3qc_peg(p_mal, pq_buz))); - } - else return u3nt(7, - u3k(mal), - u3k(buz)); - } -#if 1 - else if ( (c3y == u3r_bush(mal, &p_mal, &q_mal)) && - (c3y == u3du(p_mal)) && - (c3y == u3du(q_mal)) && - (0 == u3h(q_mal)) && - (1 == u3t(q_mal)) ) - { - return u3nt(8, - u3k(p_mal), - u3k(buz)); - } -#endif - else if ( (c3y == u3r_p(buz, 0, &p_buz)) && - (c3y == u3r_sing(1, p_buz)) ) - { - return u3k(mal); - } - else return u3nt(7, - u3k(mal), - u3k(buz)); - } - } - u3_noun - u3wf_comb(u3_noun cor) - { - u3_noun mal, buz; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &mal, u3x_sam_3, &buz, 0) ) { - return u3_none; - } else { - return u3qf_comb(mal, buz); - } - } diff --git a/pkg/urbit/jets/f/cons.c b/pkg/urbit/jets/f/cons.c deleted file mode 100644 index be34fffd2..000000000 --- a/pkg/urbit/jets/f/cons.c +++ /dev/null @@ -1,54 +0,0 @@ -/* j/6/cons.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qf_cons(u3_noun vur, - u3_noun sed) - { - u3_noun p_vur, p_sed; - - if ( c3y == u3r_p(vur, 1, &p_vur) && - c3y == u3r_p(sed, 1, &p_sed) ) { - return u3nt(1, - u3k(p_vur), - u3k(p_sed)); - } -#if 0 - else if ( c3y == u3r_p(vur, 0, &p_vur) && - c3y == u3r_p(sed, 0, &p_sed) && - !(c3y == u3r_sing(1, p_vur)) && - !(c3y == u3r_sing(p_vur, p_sed)) && - (0 == u3r_nord(p_vur, p_sed)) ) - { - u3_atom fub = u3qa_div(p_vur, 2); - u3_atom nof = u3qa_div(p_sed, 2); - - if ( c3y == u3r_sing(fub, nof) ) { - u3z(nof); - - return u3nc(0, fub); - } - else { - u3z(fub); - u3z(nof); - } - } -#endif - return u3nc(u3k(vur), u3k(sed)); - } - u3_noun - u3wf_cons(u3_noun cor) - { - u3_noun vur, sed; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &vur, u3x_sam_3, &sed, 0) ) { - return u3m_bail(c3__fail); - } else { - return u3qf_cons(vur, sed); - } - } diff --git a/pkg/urbit/jets/f/core.c b/pkg/urbit/jets/f/core.c deleted file mode 100644 index 5d7ef8015..000000000 --- a/pkg/urbit/jets/f/core.c +++ /dev/null @@ -1,118 +0,0 @@ -/* j/6/core.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qf_core(u3_noun pac, - u3_noun con) - { - if ( (c3__void == pac) ) { - return c3__void; - } else { - { - u3_noun p_con, q_con, r_con, hr_con, tr_con; - - u3r_trel(con, &p_con, &q_con, &r_con); - u3r_cell(r_con, &hr_con, &tr_con); - if ( (c3y == u3du(hr_con)) && - (u3_nul == u3h(hr_con)) && - (u3_nul == u3t(hr_con)) ) - { - u3l_log("old core"); - abort(); - } - } - return u3nt(c3__core, u3k(pac), u3k(con)); - } - } - u3_noun - u3wf_core(u3_noun cor) - { - u3_noun pac, con; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &pac, u3x_sam_3, &con, 0) ) { - return u3m_bail(c3__fail); - } else { - return u3qf_core(pac, con); - } - } - -#if 0 - static void - _fork_test(const c3_c *lab_c, u3_noun set) - { - if ( u3_nul == set ) { - return; - } else { - u3_noun n_set, l_set, r_set; - - u3x_trel(set, &n_set, &l_set, &r_set); - - u3qf_test(lab_c, n_set); - _fork_test(lab_c, l_set); - _fork_test(lab_c, r_set); - } - } - void - u3qf_test(const c3_c* lab_c, u3_noun sut) - { - u3_noun p_sut, q_sut; - - if ( c3n == u3du(sut) ) switch ( sut ) { - default: u3m_bail(c3__fail); return; - - case c3__noun: - { - return; - } - case c3__void: - { - return; - } - } - else switch ( u3h(sut) ) { - default: u3m_bail(c3__fail); return; - - case c3__atom: u3x_cell(u3t(sut), &p_sut, &q_sut); - { - return; - } - case c3__cell: u3x_cell(u3t(sut), &p_sut, &q_sut); - { - u3qf_test(lab_c, p_sut); - u3qf_test(lab_c, q_sut); - return; - } - case c3__core: u3x_cell(u3t(sut), &p_sut, &q_sut); - { - u3qf_test(lab_c, p_sut); - return; - } - case c3__face: u3x_cell(u3t(sut), &p_sut, &q_sut); - { - u3qf_test(lab_c, q_sut); - return; - } - case c3__fork: p_sut = u3t(sut); - { - _fork_test(lab_c, p_sut); - return; - } - case c3__hint: u3x_cell(u3t(sut), &p_sut, &q_sut); - { - u3qf_test(lab_c, q_sut); - u3qf_test(lab_c, u3h(p_sut)); - return; - } - case c3__hold: u3x_cell(u3t(sut), &p_sut, &q_sut); - { - u3qf_test(lab_c, p_sut); - return; - } - } - } -#endif diff --git a/pkg/urbit/jets/f/face.c b/pkg/urbit/jets/f/face.c deleted file mode 100644 index 4e7fe7fda..000000000 --- a/pkg/urbit/jets/f/face.c +++ /dev/null @@ -1,31 +0,0 @@ -/* j/6/face.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qf_face(u3_noun sag, - u3_noun tip) - { - if ( c3__void == tip ) { - return c3__void; - } - else return u3nt(c3__face, - u3k(sag), - u3k(tip)); - } - u3_noun - u3wf_face(u3_noun cor) - { - u3_noun sag, tip; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &sag, u3x_sam_3, &tip, 0) ) { - return u3m_bail(c3__fail); - } else { - return u3qf_face(sag, tip); - } - } - diff --git a/pkg/urbit/jets/f/fine.c b/pkg/urbit/jets/f/fine.c deleted file mode 100644 index 24f40ae3f..000000000 --- a/pkg/urbit/jets/f/fine.c +++ /dev/null @@ -1,35 +0,0 @@ -/* j/6/fine.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qf_fine(u3_noun fuv, - u3_noun lup, - u3_noun mar) - { - if ( (c3__void == lup) || (c3__void == mar) ) { - return c3__void; - } else { - return u3nq(c3__fine, - u3k(fuv), - u3k(lup), - u3k(mar)); - } - } - u3_noun - u3wf_fine(u3_noun cor) - { - u3_noun fuv, lup, mar; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &fuv, - u3x_sam_6, &lup, - u3x_sam_7, &mar, 0) ) { - return u3m_bail(c3__fail); - } else { - return u3qf_fine(fuv, lup, mar); - } - } diff --git a/pkg/urbit/jets/f/fitz.c b/pkg/urbit/jets/f/fitz.c deleted file mode 100644 index 9350098a9..000000000 --- a/pkg/urbit/jets/f/fitz.c +++ /dev/null @@ -1,67 +0,0 @@ -/* j/6/fitz.c -** -*/ -#include "all.h" - - -/* functions -*/ - static u3_noun - _fitz_fiz(u3_noun yaz, - u3_noun wix) - { - c3_w yaz_w = u3r_met(3, yaz); - c3_w wix_w = u3r_met(3, wix); - c3_y yaz_y, wix_y; - - yaz_y = (0 == yaz_w) ? 0 : u3r_byte((yaz_w - 1), yaz); - if ( (yaz_y < 'A') || (yaz_y > 'Z') ) yaz_y = 0; - - wix_y = (0 == wix_w) ? 0 : u3r_byte((wix_w - 1), wix); - if ( (wix_y < 'A') || (wix_y > 'Z') ) wix_y = 0; - - if ( yaz_y && wix_y ) { - if ( !wix_y || (wix_y > yaz_y) ) { - return c3n; - } - } - return c3y; - } - - u3_noun - u3qf_fitz(u3_noun yaz, - u3_noun wix) - { - c3_w i_w, met_w = c3_min(u3r_met(3, yaz), u3r_met(3, wix)); - - if ( c3n == _fitz_fiz(yaz, wix) ) { - return c3n; - } - for ( i_w = 0; i_w < met_w; i_w++ ) { - c3_y yaz_y = u3r_byte(i_w, yaz); - c3_y wix_y = u3r_byte(i_w, wix); - - if ( (yaz_y >= 'A') && (yaz_y <= 'Z') ) yaz_y = 0; - if ( (wix_y >= 'A') && (wix_y <= 'Z') ) wix_y = 0; - - if ( yaz_y && wix_y && (yaz_y != wix_y) ) { - return c3n; - } - } - return c3y; - } - - u3_noun - u3wf_fitz(u3_noun cor) - { - u3_noun yaz, wix; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &yaz, u3x_sam_3, &wix, 0)) || - (c3n == u3ud(yaz)) || - (c3n == u3ud(wix)) ) - { - return u3m_bail(c3__fail); - } else { - return u3qf_fitz(yaz, wix); - } - } diff --git a/pkg/urbit/jets/f/flan.c b/pkg/urbit/jets/f/flan.c deleted file mode 100644 index 203336881..000000000 --- a/pkg/urbit/jets/f/flan.c +++ /dev/null @@ -1,47 +0,0 @@ -/* j/6/flan.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qf_flan(u3_noun bos, - u3_noun nif) - { - if ( c3y == u3r_sing(bos, nif) ) { - return u3k(bos); - } - if ( c3y == u3r_sing(1, u3h(bos)) ) { - if ( (u3_nul == u3t(bos)) ) { - return u3k(nif); - } - else return u3k(bos); - } - else { - if ( c3y == u3r_sing(1, u3h(nif)) ) { - if ( (u3_nul == u3t(nif)) ) { - return u3k(bos); - } - else return u3k(nif); - } - else { - return u3nq(6, - u3k(bos), - u3k(nif), - u3nc(1, c3n)); - } - } - } - u3_noun - u3wf_flan(u3_noun cor) - { - u3_noun bos, nif; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &bos, u3x_sam_3, &nif, 0) ) { - return u3m_bail(c3__fail); - } else { - return u3qf_flan(bos, nif); - } - } diff --git a/pkg/urbit/jets/f/flip.c b/pkg/urbit/jets/f/flip.c deleted file mode 100644 index 32f489061..000000000 --- a/pkg/urbit/jets/f/flip.c +++ /dev/null @@ -1,39 +0,0 @@ -/* j/6/flip.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qf_flip(u3_noun hel) - { - if ( c3y == u3r_sing(1, u3h(hel)) ) { - if ( (c3y == u3t(hel)) ) { - return u3nc(1, c3n); - } - else { - c3_assert((c3n == u3t(hel))); - - return u3nc(1, c3y); - } - } - else { - return u3nq(6, - u3k(hel), - u3nc(1, c3n), - u3nc(1, c3y)); - } - } - u3_noun - u3wf_flip(u3_noun cor) - { - u3_noun hel; - - if ( u3_none == (hel = u3r_at(u3x_sam, cor)) ) { - return u3m_bail(c3__fail); - } else { - return u3qf_flip(hel); - } - } diff --git a/pkg/urbit/jets/f/flor.c b/pkg/urbit/jets/f/flor.c deleted file mode 100644 index ba728c696..000000000 --- a/pkg/urbit/jets/f/flor.c +++ /dev/null @@ -1,47 +0,0 @@ -/* j/6/flor.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qf_flor(u3_noun bos, - u3_noun nif) - { - if ( c3y == u3r_sing(bos, nif) ) { - return u3k(bos); - } - if ( c3y == u3r_sing(1, u3h(bos)) ) { - if ( (u3_nul == u3t(bos)) ) { - return u3k(bos); - } - else return u3k(nif); - } - else { - if ( c3y == u3r_sing(1, u3h(nif)) ) { - if ( (u3_nul == u3t(nif)) ) { - return u3k(nif); - } - else return u3k(bos); - } - else { - return u3nq(6, - u3k(bos), - u3nc(1, c3y), - u3k(nif)); - } - } - } - u3_noun - u3wf_flor(u3_noun cor) - { - u3_noun bos, nif; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &bos, u3x_sam_3, &nif, 0) ) { - return u3m_bail(c3__fail); - } else { - return u3qf_flor(bos, nif); - } - } diff --git a/pkg/urbit/jets/f/fork.c b/pkg/urbit/jets/f/fork.c deleted file mode 100644 index 54f6f52c2..000000000 --- a/pkg/urbit/jets/f/fork.c +++ /dev/null @@ -1,78 +0,0 @@ -/* j/6/fork.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qf_forq(u3_noun hoz, - u3_noun bur) - { - if ( c3y == u3r_sing(hoz, bur) ) { - return u3k(hoz); - } - else if ( c3__void == bur ) { - return u3k(hoz); - } - else if ( c3__void == hoz ) { - return u3k(bur); - } - else return u3kf_fork(u3nt(u3k(hoz), u3k(bur), u3_nul)); - } - - u3_noun - u3qf_fork(u3_noun yed) - { - u3_noun lez = u3_nul; - - while ( u3_nul != yed ) { - u3_noun i_yed = u3h(yed); - - if ( c3__void != i_yed ) { - if ( (c3y == u3du(i_yed)) && (c3__fork == u3h(i_yed)) ) { - lez = u3kdi_uni(lez, u3k(u3t(i_yed))); - } - else { - lez = u3kdi_put(lez, u3k(i_yed)); - } - } - - yed = u3t(yed); - } - - if ( u3_nul == lez ) { - return c3__void; - } - else if ( (u3_nul == u3h(u3t(lez))) && (u3_nul == u3t(u3t(lez))) ) { - u3_noun ret = u3k(u3h(lez)); - - u3z(lez); - return ret; - } - else { - return u3nc(c3__fork, lez); - } - } - - u3_noun - u3wf_fork(u3_noun cor) - { - u3_noun yed; - - if ( c3n == u3r_mean(cor, u3x_sam, &yed, 0) ) { - return u3m_bail(c3__fail); - } else { - return u3qf_fork(yed); - } - } - - u3_noun - u3kf_fork(u3_noun yed) - { - u3_noun ret = u3qf_fork(yed); - - u3z(yed); - return ret; - } diff --git a/pkg/urbit/jets/f/help.c b/pkg/urbit/jets/f/help.c deleted file mode 100644 index e657e2d3b..000000000 --- a/pkg/urbit/jets/f/help.c +++ /dev/null @@ -1,31 +0,0 @@ -/* j/6/help.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qf_help(u3_noun sag, - u3_noun tip) - { - if ( c3__void == tip ) { - return c3__void; - } - else return u3nt(c3__help, - u3k(sag), - u3k(tip)); - } - u3_noun - u3wf_help(u3_noun cor) - { - u3_noun sag, tip; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &sag, u3x_sam_3, &tip, 0) ) { - return u3m_bail(c3__fail); - } else { - return u3qf_help(sag, tip); - } - } - diff --git a/pkg/urbit/jets/f/hike.c b/pkg/urbit/jets/f/hike.c deleted file mode 100644 index 6b1bb5b36..000000000 --- a/pkg/urbit/jets/f/hike.c +++ /dev/null @@ -1,137 +0,0 @@ -/* j/6/hike.c -** -*/ -#include "all.h" - - -/* internal tools -*/ - /* _lily_hike_belt_root(): convert (pac) to a list of root tools. - */ - static u3_noun - _lily_hike_belt_root(u3_noun pac) - { - if ( (u3_nul == pac) ) { - return u3_nul; - } - else { - u3_atom axis = u3h(u3h(pac)); - u3_noun tool = u3t(u3h(pac)); - u3_noun list_tool = _lily_hike_belt_root(u3t(pac)); - - if ( c3y == u3r_sing(1, axis) ) { - return u3nc(u3k(tool), - list_tool); - } - else return list_tool; - } - } - - /* _lily_hike_belt_l(): factor (pac) left. - */ - static u3_noun - _lily_hike_belt_l(u3_noun pac) - { - if ( (u3_nul == pac) ) { - return u3_nul; - } - else { - u3_atom axis = u3h(u3h(pac)); - u3_noun tool = u3t(u3h(pac)); - u3_noun belt_l = _lily_hike_belt_l(u3t(pac)); - - { - if ( (1 != axis) && - (c3y == u3r_sing(2, u3qc_cap(axis))) ) - { - u3_atom axis_tap = u3qc_mas(axis); - - return u3nc(u3nc(u3k(axis_tap), - u3k(tool)), - belt_l); - } - else return belt_l; - } - } - } - - /* _lily_hike_belt_r(): factor (pac) right. - */ - static u3_noun - _lily_hike_belt_r(u3_noun pac) - { - if ( (u3_nul == pac) ) { - return u3_nul; - } - else { - u3_atom axis = u3h(u3h(pac)); - u3_noun tool = u3t(u3h(pac)); - u3_noun belt_r = _lily_hike_belt_r(u3t(pac)); - - { - if ( (1 != axis) && - (c3y == u3r_sing(3, u3qc_cap(axis))) ) - { - u3_atom axis_tap = u3qc_mas(axis); - - return u3nc(u3nc(u3k(axis_tap), - u3k(tool)), - belt_r); - } - else return belt_r; - } - } - } - -/* functions -*/ - u3_noun - u3qf_hike(u3_noun axe, - u3_noun pac) - { - c3_assert(0); - if ( (u3_nul == pac) ) { - return u3nc(0, u3k(axe)); - } - else { - u3_noun zet = _lily_hike_belt_root(pac); - - if ( u3_nul != zet ) { - u3_noun fol = u3k(u3h(zet)); - - u3z(zet); - return fol; - } - else { - u3_noun tum = _lily_hike_belt_l(pac); - u3_noun gam = _lily_hike_belt_r(pac); - u3_noun hax = u3qc_peg(axe, 2); - u3_noun moz = u3qc_peg(axe, 3); - u3_noun zip = u3qf_hike(hax, tum); - u3_noun dof = u3qf_hike(moz, gam); - u3_noun fol = u3qf_cons(zip, dof); - - u3z(tum); - u3z(gam); - u3z(hax); - u3z(moz); - u3z(zip); - u3z(dof); - - return fol; - } - } - } - u3_noun - u3wf_hike(u3_noun cor) - { - u3_noun axe, pac; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &axe, u3x_sam_3, &pac, 0)) || - (c3n == u3ud(axe)) ) - { - return u3m_bail(c3__fail); - } else { - return u3qf_hike(axe, pac); - } - } diff --git a/pkg/urbit/jets/f/hint.c b/pkg/urbit/jets/f/hint.c deleted file mode 100644 index de3159255..000000000 --- a/pkg/urbit/jets/f/hint.c +++ /dev/null @@ -1,32 +0,0 @@ -/* j/6/help.c -** -*/ -#include "all.h" - - -/* functions -*/ - u3_noun - u3qf_hint(u3_noun sag, - u3_noun tip) - { - if ( c3__void == tip ) { - return c3__void; - } - if ( c3__noun == tip ) { - return c3__noun; - } - else return u3nt(c3__hint, u3k(sag), u3k(tip)); - } - u3_noun - u3wf_hint(u3_noun cor) - { - u3_noun sag, tip; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &sag, u3x_sam_3, &tip, 0) ) { - return u3m_bail(c3__fail); - } else { - return u3qf_hint(sag, tip); - } - } - diff --git a/pkg/urbit/jets/f/look.c b/pkg/urbit/jets/f/look.c deleted file mode 100644 index 038f7a522..000000000 --- a/pkg/urbit/jets/f/look.c +++ /dev/null @@ -1,134 +0,0 @@ -/* j/6/look.c -** -*/ -#include "all.h" - - -/* internals -*/ - static u3_noun - _look_in(u3_noun cog, - u3_noun dab, - u3_atom axe) - { - if ( u3_nul == dab ) { - return u3_nul; - } - else { - u3_noun n_dab, l_dab, r_dab; - - u3r_trel(dab, &n_dab, &l_dab, &r_dab); - if ( c3n == u3du(n_dab) ) { - // return u3m_bail(c3__fail); - u3l_log("bad look"); - return u3m_bail(c3__exit) ; - } - else { - u3_noun pn_dab = u3h(n_dab); - u3_noun qn_dab = u3t(n_dab); - - if ( (u3_nul == l_dab) && (u3_nul == r_dab) ) { - if ( (c3y == u3du(qn_dab)) && - (c3y == u3r_sing(cog, pn_dab)) ) { - return u3nt(u3_nul, - u3k(axe), - u3k(qn_dab)); - } - else { - return u3_nul; - } - } - else if ( (u3_nul == l_dab) ) { - if ( (c3y == u3du(qn_dab)) && - (c3y == u3r_sing(cog, pn_dab)) ) { - return u3nt(u3_nul, - u3qc_peg(axe, 2), - u3k(qn_dab)); - } - else { - if ( c3y == u3qc_gor(cog, pn_dab) ) { - return u3_nul; - } - else { - u3_noun pro; - - axe = u3qc_peg(axe, 3); - pro = _look_in(cog, r_dab, axe); - u3z(axe); - return pro; - } - } - } - else if ( (u3_nul == r_dab) ) { - if ( (c3y == u3du(qn_dab)) && - (c3y == u3r_sing(cog, pn_dab)) ) { - return u3nt(u3_nul, - u3qc_peg(axe, 2), - u3k(qn_dab)); - } - else { - if ( c3y == u3qc_gor(cog, pn_dab) ) { - u3_noun pro; - - axe = u3qc_peg(axe, 3); - pro = _look_in(cog, l_dab, axe); - u3z(axe); - return pro; - } - else { - return u3_nul; - } - } - } - else { - if ( (c3y == u3du(qn_dab)) && - (c3y == u3r_sing(cog, pn_dab)) ) { - return u3nt(u3_nul, - u3qc_peg(axe, 2), - u3k(qn_dab)); - } - else { - if ( c3y == u3qc_gor(cog, pn_dab) ) { - u3_noun pro; - - axe = u3qc_peg(axe, 6); - pro = _look_in(cog, l_dab, axe); - u3z(axe); - return pro; - } - else { - u3_noun pro; - - axe = u3qc_peg(axe, 7); - pro = _look_in(cog, r_dab, axe); - u3z(axe); - return pro; - } - } - } - } - } - } - - - - -/* functions -*/ - u3_noun - u3qf_look(u3_noun cog, - u3_noun dab) - { - return _look_in(cog, dab, 1); - } - u3_noun - u3wf_look(u3_noun cor) - { - u3_noun cog, dab; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &cog, u3x_sam_3, &dab, 0) ) { - return u3m_bail(c3__fail); - } else { - return u3qf_look(cog, dab); - } - } diff --git a/pkg/urbit/jets/f/loot.c b/pkg/urbit/jets/f/loot.c deleted file mode 100644 index fa0b5e680..000000000 --- a/pkg/urbit/jets/f/loot.c +++ /dev/null @@ -1,133 +0,0 @@ -/* j/6/loot.c -** -*/ -#include "all.h" - - -/* internals -*/ - static u3_noun - _loot_in(u3_noun cog, - u3_noun dom, - u3_atom axe) - { - if ( u3_nul == dom ) { - return u3_nul; - } - else { - u3_noun n_dom, l_dom, r_dom; - - u3r_trel(dom, &n_dom, &l_dom, &r_dom); - if ( c3n == u3du(n_dom) ) { - return u3m_bail(c3__fail); - } - else { - u3_noun qqn_dom = u3t(u3t(n_dom)); - u3_noun yep = u3qf_look(cog, qqn_dom); - - if ( (u3_nul == l_dom) && (u3_nul == r_dom) ) { - if ( u3_nul == yep ) { - return u3_nul; - } else { - u3_noun u_yep = u3t(yep); - u3_noun pro; - - pro = u3nt(u3_nul, u3qc_peg(axe, u3h(u_yep)), u3k(u3t(u_yep))); - u3z(yep); - return pro; - } - } - else if ( (u3_nul == l_dom) ) { - if ( u3_nul == yep ) { - u3_noun nax = u3qc_peg(axe, 3); - u3_noun pro; - - pro = _loot_in(cog, r_dom, nax); - u3z(nax); - return pro; - } - else { - u3_noun u_yep = u3t(yep); - u3_noun nax = u3qc_peg(axe, 2); - u3_noun pro; - - pro = u3nt(u3_nul, u3qc_peg(nax, u3h(u_yep)), u3k(u3t(u_yep))); - u3z(nax); - u3z(yep); - return pro; - } - } - else if ( (u3_nul == r_dom) ) { - if ( u3_nul == yep ) { - u3_noun nax = u3qc_peg(axe, 3); - u3_noun pro; - - pro = _loot_in(cog, l_dom, nax); - u3z(nax); - return pro; - } - else { - u3_noun u_yep = u3t(yep); - u3_noun nax = u3qc_peg(axe, 2); - u3_noun pro; - - pro = u3nt(u3_nul, u3qc_peg(nax, u3h(u_yep)), u3k(u3t(u_yep))); - u3z(nax); - u3z(yep); - return pro; - } - } - else { - if ( u3_nul == yep ) { - u3_noun nax = u3qc_peg(axe, 6); - u3_noun pey; - - pey = _loot_in(cog, l_dom, nax); - u3z(nax); - - if ( u3_nul != pey ) { - return pey; - } - else { - u3_noun nax = u3qc_peg(axe, 7); - u3_noun pro; - - pro = _loot_in(cog, r_dom, nax); - u3z(nax); - return pro; - } - } - else { - u3_noun u_yep = u3t(yep); - u3_noun nax = u3qc_peg(axe, 2); - u3_noun pro; - - pro = u3nt(u3_nul, u3qc_peg(nax, u3h(u_yep)), u3k(u3t(u_yep))); - u3z(nax); - u3z(yep); - return pro; - } - } - } - } - } - -/* functions -*/ - u3_noun - u3qf_loot(u3_noun cog, - u3_noun dom) - { - return _loot_in(cog, dom, 1); - } - u3_noun - u3wf_loot(u3_noun cor) - { - u3_noun cog, dom; - - if ( c3n == u3r_mean(cor, u3x_sam_2, &cog, u3x_sam_3, &dom, 0) ) { - return u3m_bail(c3__fail); - } else { - return u3qf_loot(cog, dom); - } - } diff --git a/pkg/urbit/jets/f/ut_crop.c b/pkg/urbit/jets/f/ut_crop.c deleted file mode 100644 index 68ea2beea..000000000 --- a/pkg/urbit/jets/f/ut_crop.c +++ /dev/null @@ -1,32 +0,0 @@ -/* j/6/crop.c -** -*/ -#include "all.h" - -u3_noun -u3wfu_crop(u3_noun cor) -{ - u3_noun bat, sut, ref, van; - - if ( (c3n == u3r_mean(cor, u3x_sam, &ref, u3x_con, &van, 0)) - || (u3_none == (bat = u3r_at(u3x_bat, van))) - || (u3_none == (sut = u3r_at(u3x_sam, van))) ) - { - return u3m_bail(c3__fail); - } - else { - u3_weak vet = u3r_at(u3qfu_van_vet, van); - c3_m fun_m = 141 + c3__crop + ((!!vet) << 8); - u3_noun key = u3z_key_3(fun_m, sut, ref, bat); - u3_weak pro = u3z_find(key); - - if ( u3_none != pro ) { - u3z(key); - return pro; - } - else { - pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); - return u3z_save(key, pro); - } - } -} diff --git a/pkg/urbit/jets/f/ut_fish.c b/pkg/urbit/jets/f/ut_fish.c deleted file mode 100644 index 2feb98990..000000000 --- a/pkg/urbit/jets/f/ut_fish.c +++ /dev/null @@ -1,33 +0,0 @@ -/* j/6/fish.c -** -*/ -#include "all.h" - -u3_noun -u3wfu_fish(u3_noun cor) -{ - u3_noun bat, sut, axe, van; - - if ( (c3n == u3r_mean(cor, u3x_sam, &axe, u3x_con, &van, 0)) - || (c3n == u3ud(axe)) - || (u3_none == (bat = u3r_at(u3x_bat, van))) - || (u3_none == (sut = u3r_at(u3x_sam, van))) ) - { - return u3m_bail(c3__fail); - } - else { - u3_weak vet = u3r_at(u3qfu_van_vet, van); - c3_m fun_m = 141 + c3__fish + ((!!vet) << 8); - u3_noun key = u3z_key_3(fun_m, sut, axe, bat); - u3_weak pro = u3z_find(key); - - if ( u3_none != pro ) { - u3z(key); - return pro; - } - else { - pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); - return u3z_save(key, pro); - } - } -} diff --git a/pkg/urbit/jets/f/ut_fuse.c b/pkg/urbit/jets/f/ut_fuse.c deleted file mode 100644 index 06eaecb4b..000000000 --- a/pkg/urbit/jets/f/ut_fuse.c +++ /dev/null @@ -1,32 +0,0 @@ -/* j/6/fuse.c -** -*/ -#include "all.h" - -u3_noun -u3wfu_fuse(u3_noun cor) -{ - u3_noun bat, sut, ref, van; - - if ( (c3n == u3r_mean(cor, u3x_sam, &ref, u3x_con, &van, 0)) - || (u3_none == (bat = u3r_at(u3x_bat, van))) - || (u3_none == (sut = u3r_at(u3x_sam, van))) ) - { - return u3m_bail(c3__fail); - } - else { - u3_weak vet = u3r_at(u3qfu_van_vet, van); - c3_m fun_m = 141 + c3__fuse + ((!!vet) << 8); - u3_noun key = u3z_key_3(fun_m, sut, ref, bat); - u3_weak pro = u3z_find(key); - - if ( u3_none != pro ) { - u3z(key); - return pro; - } - else { - pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); - return u3z_save(key, pro); - } - } -} diff --git a/pkg/urbit/jets/f/ut_mint.c b/pkg/urbit/jets/f/ut_mint.c deleted file mode 100644 index b3446f0e0..000000000 --- a/pkg/urbit/jets/f/ut_mint.c +++ /dev/null @@ -1,34 +0,0 @@ -/* j/6/mint.c -** -*/ -#include "all.h" - -u3_noun -u3wfu_mint(u3_noun cor) -{ - u3_noun bat, sut, gol, gen, van; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &gol, - u3x_sam_3, &gen, - u3x_con, &van, 0)) - || (u3_none == (bat = u3r_at(u3x_bat, van))) - || (u3_none == (sut = u3r_at(u3x_sam, van))) ) - { - return u3m_bail(c3__fail); - } - else { - c3_m fun_m = 141 + c3__mint; - u3_noun vet = u3r_at(u3qfu_van_vet, van); - u3_noun key = u3z_key_5(fun_m, vet, sut, gol, gen, bat); - u3_weak pro = u3z_find(key); - - if ( u3_none != pro ) { - u3z(key); - return pro; - } - else { - pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); - return u3z_save(key, pro); - } - } -} diff --git a/pkg/urbit/jets/f/ut_mull.c b/pkg/urbit/jets/f/ut_mull.c deleted file mode 100644 index c100b3658..000000000 --- a/pkg/urbit/jets/f/ut_mull.c +++ /dev/null @@ -1,35 +0,0 @@ -/* j/6/mull.c -** -*/ -#include "all.h" - -u3_noun -u3wfu_mull(u3_noun cor) -{ - u3_noun bat, sut, gol, dox, gen, van; - - if ( (c3n == u3r_mean(cor, u3x_sam_2, &gol, - u3x_sam_6, &dox, - u3x_sam_7, &gen, - u3x_con, &van, 0)) - || (u3_none == (bat = u3r_at(u3x_bat, van))) - || (u3_none == (sut = u3r_at(u3x_sam, van))) ) - { - return u3m_bail(c3__fail); - } - else { - u3_weak vet = u3r_at(u3qfu_van_vet, van); - c3_m fun_m = 141 + c3__mull + ((!!vet) << 8); - u3_noun key = u3z_key_5(fun_m, sut, gol, dox, gen, bat); - u3_weak pro = u3z_find(key); - - if ( u3_none != pro ) { - u3z(key); - return pro; - } - else { - pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); - return u3z_save(key, pro); - } - } -} diff --git a/pkg/urbit/jets/f/ut_nest.c b/pkg/urbit/jets/f/ut_nest.c deleted file mode 100644 index 27aa504f9..000000000 --- a/pkg/urbit/jets/f/ut_nest.c +++ /dev/null @@ -1,48 +0,0 @@ -/* j/6/ut_nest.c -** -*/ -#include "all.h" - -u3_noun -u3wfu_nest_dext(u3_noun dext_core) -{ - u3_noun nest_in_core, nest_core; - u3_noun bat, sut, ref, van, seg, reg, gil; - - if ( (u3_none == (nest_in_core = u3r_at(3, dext_core))) - || (c3n == u3r_mean(nest_in_core, u3x_sam_2, &seg, - u3x_sam_6, ®, - u3x_sam_7, &gil, - u3x_con, &nest_core, 0)) - || (c3n == u3r_mean(nest_core, u3x_sam_3, &ref, - u3x_con, &van, 0)) - || (u3_none == (bat = u3r_at(u3x_bat, van))) - || (u3_none == (sut = u3r_at(u3x_sam, van))) ) - { - return u3m_bail(c3__fail); - } - else { - u3_weak vet = u3r_at(u3qfu_van_vet, van); - c3_m fun_m = 141 + c3__dext + ((!!vet) << 8); - u3_noun key = u3z_key_3(fun_m, sut, ref, bat); - u3_weak pro = u3z_find(key); - - if ( u3_none != pro ) { - u3z(key); - return pro; - } - else { - pro = u3n_nock_on(u3k(dext_core), u3k(u3x_at(u3x_bat, dext_core))); - - if ( ((c3y == pro) && (u3_nul == reg)) || - ((c3n == pro) && (u3_nul == seg)) ) - { - return u3z_save(key, pro); - } - else { - u3z(key); - return pro; - } - } - } -} diff --git a/pkg/urbit/jets/f/ut_rest.c b/pkg/urbit/jets/f/ut_rest.c deleted file mode 100644 index c683a4155..000000000 --- a/pkg/urbit/jets/f/ut_rest.c +++ /dev/null @@ -1,32 +0,0 @@ -/* j/6/ut_rest.c -** -*/ -#include "all.h" - -u3_noun -u3wfu_rest(u3_noun cor) -{ - u3_noun bat, sut, leg, van; - - if ( (c3n == u3r_mean(cor, u3x_sam, &leg, u3x_con, &van, 0)) - || (u3_none == (bat = u3r_at(u3x_bat, van))) - || (u3_none == (sut = u3r_at(u3x_sam, van))) ) - { - return u3m_bail(c3__fail); - } - else { - u3_weak vet = u3r_at(u3qfu_van_vet, van); - c3_m fun_m = 141 + c3__rest + ((!!vet) << 8); - u3_noun key = u3z_key_3(fun_m, sut, leg, bat); - u3_weak pro = u3z_find(key); - - if ( u3_none != pro ) { - u3z(key); - return pro; - } - else { - pro = u3n_nock_on(u3k(cor), u3k(u3x_at(u3x_bat, cor))); - return u3z_save(key, pro); - } - } -} diff --git a/pkg/urbit/jets/tree.c b/pkg/urbit/jets/tree.c deleted file mode 100644 index 2e796035f..000000000 --- a/pkg/urbit/jets/tree.c +++ /dev/null @@ -1,2215 +0,0 @@ -/* - To generate the hashes, take the sha256 of the jammed battery. For example: - - ``` - > `@ux`(shax (jam -:rip)) - 0x2759.a693.1e9e.f9a5.2c8e.ee43.1088.43d9.4d39.32a6.b04f.86cb.6ba1.5553.4329.3a28 - ``` - - Becomes: - - ``` - 2759a6931e9ef9a52c8eee43108843d94d3932a6b04f86cb6ba1555343293a28 - ``` -*/ - -#include "all.h" - -static c3_c* no_hashes[] = { 0 }; - -static u3j_harm _140_hex_mimes_base16_en_a[] = {{".2", u3we_en_base16}, {}}; -static c3_c* _140_hex_mimes_base16_en_ha[] = { - "669807766b6802719769fcbfe149d77fb352fcf0922afaf35dc4ab8c201d84e5", - 0 -}; - -static u3j_harm _140_hex_mimes_base16_de_a[] = {{".2", u3we_de_base16}, {}}; -static c3_c* _140_hex_mimes_base16_de_ha[] = { - "f1e04d0f452f2783e17b3bd5bbbcf95a651624fe7a2aca28dd9a7feae1319734", - 0 -}; - -static u3j_core _140_hex_mimes_base16_d[] = - { { "en", 7, _140_hex_mimes_base16_en_a, 0, _140_hex_mimes_base16_en_ha }, - { "de", 7, _140_hex_mimes_base16_de_a, 0, _140_hex_mimes_base16_de_ha }, - {} - }; -static c3_c* _140_hex_mimes_base16_ha[] = { - "c71bdcc8542fd49aa307f296ac097e300a714fb3b3d1e475426f0916fa61f12c", - 0 -}; - -static u3j_core _140_hex_mimes_d[] = - { { "base16", 3, 0, _140_hex_mimes_base16_d, _140_hex_mimes_base16_ha }, - {} - }; -static c3_c* _140_hex_mimes_ha[] = { - "bca2510fd7172643812f9d224deb95ddd69400c990db3d8cfb517a7292e8f06e", - 0 -}; - -static u3j_harm _140_hex_aes_ecba_en_a[] = {{".2", u3wea_ecba_en}, {}}; -static c3_c* _140_hex_aes_ecba_en_ha[] = { - "d7674ad72666a787580c52785c5d4d37ca462ba05e904efbeded5d1bd8b02b4b", - 0 -}; -static u3j_harm _140_hex_aes_ecba_de_a[] = {{".2", u3wea_ecba_de}, {}}; -static c3_c* _140_hex_aes_ecba_de_ha[] = { - "6e6599e93bea2e4297b621814bfb17a9b10849f920d50b14e808ef2e4fe62383", - 0 -}; -static u3j_harm _140_hex_aes_ecbb_en_a[] = {{".2", u3wea_ecbb_en}, {}}; -static c3_c* _140_hex_aes_ecbb_en_ha[] = { - "2c0e3c8f4d741b37324563ecd0ab8fbf87721d1e017f1eeeaf8b6a60515c483b", - 0 -}; -static u3j_harm _140_hex_aes_ecbb_de_a[] = {{".2", u3wea_ecbb_de}, {}}; -static c3_c* _140_hex_aes_ecbb_de_ha[] = { - "cf78f314a1dbbc53b28d6405b98c66a4451350757872d8f7cf0477411e731acc", - 0 -}; -static u3j_harm _140_hex_aes_ecbc_en_a[] = {{".2", u3wea_ecbc_en}, {}}; -static c3_c* _140_hex_aes_ecbc_en_ha[] = { - "f56450f2662082e27ba1aecd2fe04c66aa8641d6eb155f8d3707e242a1e1cf1c", - 0 -}; -static u3j_harm _140_hex_aes_ecbc_de_a[] = {{".2", u3wea_ecbc_de}, {}}; -static c3_c* _140_hex_aes_ecbc_de_ha[] = { - "28c8c44002799fbe94d4aa07922f2b74dbbf234c84684cd8c3187622b4be6a5f", - 0 -}; - -static u3j_harm _140_hex_aes_cbca_en_a[] = {{".2", u3wea_cbca_en}, {}}; -static c3_c* _140_hex_aes_cbca_en_ha[] = { - "f85366d520b3179c5dabfb58ee1fa0554f5044f676340439db875841cd4058de", - 0 -}; -static u3j_harm _140_hex_aes_cbca_de_a[] = {{".2", u3wea_cbca_de}, {}}; -static c3_c* _140_hex_aes_cbca_de_ha[] = { - "8b876fbdb1849d8fbabba5e143aea0532a0e5dfff1c784d7ad15fd497ea376b1", - 0 -}; -static u3j_harm _140_hex_aes_cbcb_en_a[] = {{".2", u3wea_cbcb_en}, {}}; -static c3_c* _140_hex_aes_cbcb_en_ha[] = { - "6f961e0629c5efce47793e6a352220d355bb8fba6656c6941a68efb3ba10999d", - 0 -}; -static u3j_harm _140_hex_aes_cbcb_de_a[] = {{".2", u3wea_cbcb_de}, {}}; -static c3_c* _140_hex_aes_cbcb_de_ha[] = { - "7ee2f33f80612e91fda1fd84201266dea6cab596a4e23a535d1a14fb0763f1a3", - 0 -}; -static u3j_harm _140_hex_aes_cbcc_en_a[] = {{".2", u3wea_cbcc_en}, {}}; -static c3_c* _140_hex_aes_cbcc_en_ha[] = { - "b2578cf17a3095f48cc96cf7690dd7ab4f4e0b76b2578eadc1dce31a075f5b12", - 0 -}; -static u3j_harm _140_hex_aes_cbcc_de_a[] = {{".2", u3wea_cbcc_de}, {}}; -static c3_c* _140_hex_aes_cbcc_de_ha[] = { - "36586f89d702bedb8c2a01ea3614f61627e762488e373106cbb1b27c46e3493c", - 0 -}; -static u3j_harm _140_hex_aes_siva_en_a[] = {{".2", u3wea_siva_en}, {}}; -static c3_c* _140_hex_aes_siva_en_ha[] = { - "2a137039301788b8540ed81cbfafe450c9306348d02a6576f5c14f6d6f20ba81", - 0 -}; -static u3j_harm _140_hex_aes_siva_de_a[] = {{".2", u3wea_siva_de}, {}}; -static c3_c* _140_hex_aes_siva_de_ha[] = { - "d0130e9229e71c589429dd87843dc104bc4ee5b426400a547081d8c91a548eaa", - 0 -}; -static u3j_harm _140_hex_aes_sivb_en_a[] = {{".2", u3wea_sivb_en}, {}}; -static c3_c* _140_hex_aes_sivb_en_ha[] = { - "1638f56e8728f285e4175c7b514c5a4e1a24205acf33e105f0513cad7ae843cf", - 0 -}; -static u3j_harm _140_hex_aes_sivb_de_a[] = {{".2", u3wea_sivb_de}, {}}; -static c3_c* _140_hex_aes_sivb_de_ha[] = { - "64c9b199fffd6d31baf7457bf27d5a510121be45201b2ae5cc1d9565c0bdd0ff", - 0 -}; -static u3j_harm _140_hex_aes_sivc_en_a[] = {{".2", u3wea_sivc_en}, {}}; -static c3_c* _140_hex_aes_sivc_en_ha[] = { - "d721486dea943efd52d9e6450f4f48dd191c89637a2f842d3ff6edfd3beecbb9", - 0 -}; -static u3j_harm _140_hex_aes_sivc_de_a[] = {{".2", u3wea_sivc_de}, {}}; -static c3_c* _140_hex_aes_sivc_de_ha[] = { - "3ded831b992ea100582229a4d1d9b5c80380128ae6b59b5bb36403ed13dc5d55", - 0 -}; - -static u3j_core _140_hex_aes_ecba_d[] = - { { "en", 7, _140_hex_aes_ecba_en_a, 0, _140_hex_aes_ecba_en_ha }, - { "de", 7, _140_hex_aes_ecba_de_a, 0, _140_hex_aes_ecba_de_ha }, - {} - }; -static c3_c* _140_hex_aes_ecba_ha[] = { - "693409d27b777f73ce92cebd38e9ebceebe1e9c27ad8c9de9afc091e31bd7d9f", - 0 -}; - -static u3j_core _140_hex_aes_ecbb_d[] = - { { "en", 7, _140_hex_aes_ecbb_en_a, 0, _140_hex_aes_ecbb_en_ha }, - { "de", 7, _140_hex_aes_ecbb_de_a, 0, _140_hex_aes_ecbb_de_ha }, - {} - }; -static c3_c* _140_hex_aes_ecbb_ha[] = { - "7255c39f10e068007d0d64dd40e4f6e83492ed2e3222919440be0d28fd42a5e3", - 0 -}; - -static u3j_core _140_hex_aes_ecbc_d[] = - { { "en", 7, _140_hex_aes_ecbc_en_a, 0, _140_hex_aes_ecbc_en_ha }, - { "de", 7, _140_hex_aes_ecbc_de_a, 0, _140_hex_aes_ecbc_de_ha }, - {} - }; -static c3_c* _140_hex_aes_ecbc_ha[] = { - "65da73b8de06a6660ca2d36be881b708362e1f8bc12c01290aed90fdb2977667", - 0 -}; - -static u3j_core _140_hex_aes_cbca_d[] = - { { "en", 7, _140_hex_aes_cbca_en_a, 0, _140_hex_aes_cbca_en_ha }, - { "de", 7, _140_hex_aes_cbca_de_a, 0, _140_hex_aes_cbca_de_ha }, - {} - }; -static c3_c* _140_hex_aes_cbca_ha[] = { - "420d04c03b7816b656fe4e8d9fce04f7e6d51d3d274c6511e89cfdb43ebf107e", - 0 -}; - -static u3j_core _140_hex_aes_cbcb_d[] = - { { "en", 7, _140_hex_aes_cbcb_en_a, 0, _140_hex_aes_cbcb_en_ha }, - { "de", 7, _140_hex_aes_cbcb_de_a, 0, _140_hex_aes_cbcb_de_ha }, - {} - }; -static c3_c* _140_hex_aes_cbcb_ha[] = { - "1b84daab497795f2afd7238a6a6090be68b78eb6051b0ffa076b2ed9fedeebe5", - 0 -}; - -static u3j_core _140_hex_aes_cbcc_d[] = - { { "en", 7, _140_hex_aes_cbcc_en_a, 0, _140_hex_aes_cbcc_en_ha }, - { "de", 7, _140_hex_aes_cbcc_de_a, 0, _140_hex_aes_cbcc_de_ha }, - {} - }; -static c3_c* _140_hex_aes_cbcc_ha[] = { - "3bab1a59c7673afeb659821d54754e8e5e281243e79624fdbe4d7f85cae192c5", - 0 -}; - -static u3j_core _140_hex_aes_siva_d[] = - { { "en", 7, _140_hex_aes_siva_en_a, 0, _140_hex_aes_siva_en_ha }, - { "de", 7, _140_hex_aes_siva_de_a, 0, _140_hex_aes_siva_de_ha }, - {} - }; -static c3_c* _140_hex_aes_siva_ha[] = { - "435c5c769d2522d71ab60332bb57440d69c6803d5ca9a5faae88c825cb55d72e", - 0 -}; -static u3j_core _140_hex_aes_sivb_d[] = - { { "en", 7, _140_hex_aes_sivb_en_a, 0, _140_hex_aes_sivb_en_ha }, - { "de", 7, _140_hex_aes_sivb_de_a, 0, _140_hex_aes_sivb_de_ha }, - {} - }; -static c3_c* _140_hex_aes_sivb_ha[] = { - "0683f3f9067c2a16f68805c778c404179dc5df9019bbbe0f8d680a99a69e61fc", - 0 -}; -static u3j_core _140_hex_aes_sivc_d[] = - { { "en", 7, _140_hex_aes_sivc_en_a, 0, _140_hex_aes_sivc_en_ha }, - { "de", 7, _140_hex_aes_sivc_de_a, 0, _140_hex_aes_sivc_de_ha }, - {} - }; -static c3_c* _140_hex_aes_sivc_ha[] = { - "23ef582f110d28aff82b0795305b02e5a718d667bcae97091c08bc26790e7176", - 0 -}; - -static u3j_core _140_hex_aes_d[] = - { { "ecba", 7, 0, _140_hex_aes_ecba_d, _140_hex_aes_ecba_ha }, - { "ecbb", 7, 0, _140_hex_aes_ecbb_d, _140_hex_aes_ecbb_ha }, - { "ecbc", 7, 0, _140_hex_aes_ecbc_d, _140_hex_aes_ecbc_ha }, - { "cbca", 7, 0, _140_hex_aes_cbca_d, _140_hex_aes_cbca_ha }, - { "cbcb", 7, 0, _140_hex_aes_cbcb_d, _140_hex_aes_cbcb_ha }, - { "cbcc", 7, 0, _140_hex_aes_cbcc_d, _140_hex_aes_cbcc_ha }, - { "siva", 7, 0, _140_hex_aes_siva_d, _140_hex_aes_siva_ha }, - { "sivb", 7, 0, _140_hex_aes_sivb_d, _140_hex_aes_sivb_ha }, - { "sivc", 7, 0, _140_hex_aes_sivc_d, _140_hex_aes_sivc_ha }, - {} - }; -static c3_c* _140_hex_aes_ha[] = { - "ca4c1b0cff03db74ceca1b844f0223d669aa42934152a784d431469f0eb71527", - 0 -}; - -static u3j_harm _140_hex_leer_a[] = {{".2", u3we_leer}, {}}; -static c3_c* _140_hex_leer_ha[] = { - "8a4486bb09639f6b8cf7631f9bf883256529c6d7d9aa320ab6dfa5517611f0d7", - 0 -}; -static u3j_harm _140_hex_lore_a[] = {{".2", u3we_lore}, {}}; -static c3_c* _140_hex_lore_ha[] = { - "19b13cfea49fd14aafbb20b8b888ba454f809c3f50a7cfeebd43f87336fe052d", - 0 -}; -static u3j_harm _140_hex_loss_a[] = {{".2", u3we_loss}, {}}; -static c3_c* _140_hex_loss_ha[] = { - "67aacd21484078828ad4342297d44c38d9213b8809f83f695c2996378a92dc2a", - 0 -}; -static u3j_harm _140_hex_lune_a[] = {{".2", u3we_lune}, {}}; -static c3_c* _140_hex_lune_ha[] = { - "417472f35b885fe6dd0715e78fd0920cb59f68b738aadc9768e73bc5efa0e570", - 0 -}; - -static u3j_harm _140_hex_coed__ed_puck_a[] = {{".2", u3wee_puck}, {}}; -static c3_c* _140_hex_coed__ed_puck_ha[] = { - "1bc694675842345c50b0e20a2193bb5bcbb42f163fc832431a3d1822a81e4c98", - 0 -}; -static u3j_harm _140_hex_coed__ed_sign_a[] = {{".2", u3wee_sign}, {}}; -static c3_c* _140_hex_coed__ed_sign_ha[] = { - "34ad749bf8443611cbf1f7de90a066318bd12be36f2f7f6f55281f6f7ed79754", - 0 -}; -static u3j_harm _140_hex_coed__ed_veri_a[] = {{".2", u3wee_veri}, {}}; -static c3_c* _140_hex_coed__ed_veri_ha[] = { - "047a7eeccb2e68aeeee631b6db86e11a5a3aa9e179660553eca6304327612dcf", - 0 -}; -static u3j_harm _140_hex_coed__ed_shar_a[] = {{".2", u3wee_shar}, {}}; -static c3_c* _140_hex_coed__ed_shar_ha[] = { - "52d3b0a2f51f2b0a9dd72bb33db38c73dc873029c365d871d0559a1472a80e72", - 0 -}; - -static u3j_harm _140_hex_coed__ed_point_add_a[] = - {{".2", u3wee_point_add}, {}}; - -static u3j_harm _140_hex_coed__ed_scalarmult_a[] = - {{".2", u3wee_scalarmult}, {}}; -static c3_c* _140_hex_coed__ed_scalarmult_ha[] = { - "72e71cd3aa3af429cd65baa78632500c60edd1d4c82a39d3ba7f231ef97e6316", - 0 -}; - -static u3j_harm _140_hex_coed__ed_scalarmult_base_a[] = - {{".2", u3wee_scalarmult_base}, {}}; -static c3_c* _140_hex_coed__ed_scalarmult_base_ha[] = { - "976fdb8251f9b767af689a0d2c41b88941921bf53777c1ceeb5297511021f9d8", - 0 -}; - -static u3j_harm _140_hex_coed__ed_add_scalarmult_scalarmult_base_a[] = - {{".2", u3wee_add_scalarmult_scalarmult_base}, {}}; -static c3_c* _140_hex_coed__ed_add_scalarmult_scalarmult_base_ha[] = { - "11819071c24a2d7b36daea6e16c78b2e05f9ca3e857cf4815ffe652ce677a61a", - 0 -}; - -static u3j_harm _140_hex_coed__ed_add_double_scalarmult_a[] = - {{".2", u3wee_add_double_scalarmult}, {}}; -static c3_c* _140_hex_coed__ed_add_double_scalarmult_ha[] = { - "0fab78a1e890e53cecade1c22b95813db77e066044e33417a0919695b6cde9ba", - 0 -}; - -static u3j_core _140_hex_coed__ed_d[] = - { { "sign", 7, _140_hex_coed__ed_sign_a, 0, _140_hex_coed__ed_sign_ha }, - { "puck", 7, _140_hex_coed__ed_puck_a, 0, _140_hex_coed__ed_puck_ha }, - { "veri", 7, _140_hex_coed__ed_veri_a, 0, _140_hex_coed__ed_veri_ha }, - { "shar", 7, _140_hex_coed__ed_shar_a, 0, _140_hex_coed__ed_shar_ha }, - { "point-add", 7, _140_hex_coed__ed_point_add_a, 0, 0 }, - { "scalarmult", 7, _140_hex_coed__ed_scalarmult_a, 0, - _140_hex_coed__ed_scalarmult_ha }, - { "scalarmult-base", 7, _140_hex_coed__ed_scalarmult_base_a, 0, - _140_hex_coed__ed_scalarmult_base_ha }, - { "add-scalarmult-scalarmult-base", 7, - _140_hex_coed__ed_add_scalarmult_scalarmult_base_a, 0, - _140_hex_coed__ed_add_scalarmult_scalarmult_base_ha }, - { "add-double-scalarmult", 7, - _140_hex_coed__ed_add_double_scalarmult_a, 0, - _140_hex_coed__ed_add_double_scalarmult_ha }, - {} - }; -static c3_c* _140_hex_coed__ed_ha[] = { - "7a44a962aa72933588b5c99a8b68ebac21ce3c4710c081cb66b3599b45af9ced", - 0 -}; - -static u3j_core _140_hex_coed_d[] = -{ { "ed", 3, 0, _140_hex_coed__ed_d, _140_hex_coed__ed_ha }, - {} -}; -static c3_c* _140_hex_coed_ha[] = { - "4be0254f06d953b69509eb15550595ffad8767d3c3dc2dafcd7c22f92f7704c4", - 0 -}; - - static u3j_harm _140_hex_hmac_hmac_a[] = {{".2", u3we_hmac}, {}}; - static c3_c* _140_hex_hmac_hmac_ha[] = { - "d0dbd778156aef21d18f44a8cffd87296826120af5a4af020dd7aff0f95f03b1", - 0 - }; -static u3j_core _140_hex_hmac_d[] = - { { "hmac", 7, _140_hex_hmac_hmac_a, 0, _140_hex_hmac_hmac_ha }, - {} - }; -static c3_c* _140_hex_hmac_ha[] = { - "976bb4508dbe659eb12aa32d4a481dbd885e40f8a15c505762f1acf43b744234", - 0 -}; - - static u3j_harm _140_hex_argon2_a[] = {{".2", u3we_argon2}, {}}; - static c3_c* _140_hex_argon2_ha[] = { - "4df7cec141ffa2cc76b058846474ca42cc9840666ee3e7e80e565803e83ea98b", - 0 - }; -static u3j_core _140_hex_argon_d[] = - { { "argon2", 511, _140_hex_argon2_a, 0, _140_hex_argon2_ha }, - {} - }; -static c3_c* _140_hex_argon_ha[] = { - "dc704c786192ecd09d4c206a8f28db3202b6e0eb03e3ce63a95987510ac312d6", - 0 -}; - -static c3_c* _140_hex_scr_pbk_ha[] = { 0 }; -static u3j_harm _140_hex_scr_pbk_a[] = {{".2", u3wes_pbk, c3y}, {}}; -static c3_c* _140_hex_scr_pbl_ha[] = { 0 }; -static u3j_harm _140_hex_scr_pbl_a[] = {{".2", u3wes_pbl, c3y}, {}}; -static c3_c* _140_hex_scr_hsh_ha[] = { 0 }; -static u3j_harm _140_hex_scr_hsh_a[] = {{".2", u3wes_hsh, c3y}, {}}; -static c3_c* _140_hex_scr_hsl_ha[] = { 0 }; -static u3j_harm _140_hex_scr_hsl_a[] = {{".2", u3wes_hsl, c3y}, {}}; - -static c3_c* _140_hex_scr_ha[] = { 0 }; -static u3j_core _140_hex_scr_d[] = - { { "pbk", 7, _140_hex_scr_pbk_a, 0, _140_hex_scr_pbk_ha }, - { "pbl", 7, _140_hex_scr_pbl_a, 0, _140_hex_scr_pbl_ha }, - { "hsh", 7, _140_hex_scr_hsh_a, 0, _140_hex_scr_hsh_ha }, - { "hsl", 7, _140_hex_scr_hsl_a, 0, _140_hex_scr_hsl_ha }, - {} - }; - -static c3_c* _140_hex_secp_secp256k1_make_ha[] = { 0 }; -static u3j_harm _140_hex_secp_secp256k1_make_a[] = {{".2", u3we_make, c3y}, {}}; -static c3_c* _140_hex_secp_secp256k1_sign_ha[] = { 0 }; -static u3j_harm _140_hex_secp_secp256k1_sign_a[] = {{".2", u3we_sign, c3y}, {}}; -static c3_c* _140_hex_secp_secp256k1_reco_ha[] = { 0 }; -static u3j_harm _140_hex_secp_secp256k1_reco_a[] = {{".2", u3we_reco, c3y}, {}}; - -static c3_c* _140_hex_secp_secp256k1_schnorr_sosi_ha[] = { 0 }; -static u3j_harm _140_hex_secp_secp256k1_schnorr_sosi_a[] = - {{".2", u3we_sosi}, {}}; -static c3_c* _140_hex_secp_secp256k1_schnorr_sove_ha[] = { 0 }; -static u3j_harm _140_hex_secp_secp256k1_schnorr_sove_a[] = - {{".2", u3we_sove}, {}}; - -static c3_c* _140_hex_secp_secp256k1_schnorr_ha[] = { 0 }; -static u3j_core _140_hex_secp_secp256k1_schnorr_d[] = - { { "sosi", 7, - _140_hex_secp_secp256k1_schnorr_sosi_a, 0, - _140_hex_secp_secp256k1_schnorr_sosi_ha }, - { "sove", 7, - _140_hex_secp_secp256k1_schnorr_sove_a, 0, - _140_hex_secp_secp256k1_schnorr_sove_ha }, - {} - }; - -static c3_c* _140_hex_secp_secp256k1_ha[] = { - "e7fc0971a970aba7ded43bd89e9c82623eb2f346c9c720c63b22f2a646927861", - 0 -}; -static u3j_core _140_hex_secp_secp256k1_d[] = - { { "make", 7, _140_hex_secp_secp256k1_make_a, 0, _140_hex_secp_secp256k1_make_ha }, - { "sign", 7, _140_hex_secp_secp256k1_sign_a, 0, _140_hex_secp_secp256k1_sign_ha }, - { "reco", 7, _140_hex_secp_secp256k1_reco_a, 0, _140_hex_secp_secp256k1_reco_ha }, - { "schnorr", 7, 0, - _140_hex_secp_secp256k1_schnorr_d, - _140_hex_secp_secp256k1_schnorr_ha }, - {} - }; - -static c3_c* _140_hex_secp_ha[] = { - "9f5c23f0e7923b6cf1603388ba52401b6e43881be3560b3acfaab20b25071792", - 0 -}; -static u3j_core _140_hex_secp_d[] = - { { "secp256k1", 3, 0, _140_hex_secp_secp256k1_d, _140_hex_secp_secp256k1_ha }, - {} - }; - - static u3j_harm _140_hex_blake2b_a[] = {{".2", u3we_blake, c3y}, {}}; - static c3_c* _140_hex_blake2b_ha[] = { - "c432216ca53b5ad2284259167952761bb1046e280268c4d3b9ca70a2024e1934", - 0 - }; -static u3j_core _140_hex_blake_d[] = - { { "blake2b", 7, _140_hex_blake2b_a, 0, _140_hex_blake2b_ha }, - {} - }; -static c3_c* _140_hex_blake_ha[] = { - "ff30d99ffb3e13d8aa50b2b8461c8edfabf0e76de22312d16d1d6daaf3636b5f", - 0 -}; - - static u3j_harm _140_hex_kecc_k224_a[] = - {{".2", u3we_kecc224, c3y, c3y, c3y}, {}}; - - static u3j_harm _140_hex_kecc_k256_a[] = - {{".2", u3we_kecc256, c3y, c3y, c3y}, {}}; - - static u3j_harm _140_hex_kecc_k384_a[] = - {{".2", u3we_kecc384, c3y, c3y, c3y}, {}}; - - static u3j_harm _140_hex_kecc_k512_a[] = - {{".2", u3we_kecc512, c3y, c3y, c3y}, {}}; - -static u3j_core _140_hex_kecc_d[] = - { { "k224", 7, _140_hex_kecc_k224_a, 0, no_hashes }, - { "k256", 7, _140_hex_kecc_k256_a, 0, no_hashes }, - { "k384", 7, _140_hex_kecc_k384_a, 0, no_hashes }, - { "k512", 7, _140_hex_kecc_k512_a, 0, no_hashes }, - {} - }; - - static u3j_harm _140_hex_ripemd_160_a[] = {{".2", u3we_ripe, c3y}, {}}; - static c3_c* _140_hex_ripemd_160_ha[] = { - "176684b29926a01f5c60fa584e4691b0cbdc9b93608dcbe7d0cf3585683fa42f", - 0 - }; -static u3j_core _140_hex_ripe_d[] = - { { "ripemd160", 7, _140_hex_ripemd_160_a, 0, _140_hex_ripemd_160_ha }, - {} - }; -static c3_c* _140_hex_ripe_ha[] = { - "b0cb16bf206c0496bb480e5759ea1afa7dee1748b64e5243c23fddb09720ebd0", - 0 -}; - - -static u3j_core _140_hex_d[] = -{ { "lore", 63, _140_hex_lore_a, 0, _140_hex_lore_ha }, - { "leer", 63, _140_hex_leer_a, 0, _140_hex_leer_ha }, - { "loss", 63, _140_hex_loss_a, 0, _140_hex_loss_ha }, - { "lune", 127, _140_hex_lune_a, 0, _140_hex_lune_ha }, - - { "coed", 63, 0, _140_hex_coed_d, _140_hex_coed_ha }, - { "aes", 31, 0, _140_hex_aes_d, _140_hex_aes_ha }, - - { "hmac", 63, 0, _140_hex_hmac_d, _140_hex_hmac_ha }, - { "argon", 31, 0, _140_hex_argon_d, _140_hex_argon_ha }, - { "blake", 31, 0, _140_hex_blake_d, _140_hex_blake_ha }, - { "kecc", 31, 0, _140_hex_kecc_d, no_hashes }, - { "ripemd", 31, 0, _140_hex_ripe_d, _140_hex_ripe_ha }, - { "scr", 31, 0, _140_hex_scr_d, _140_hex_scr_ha }, - { "secp", 6, 0, _140_hex_secp_d, _140_hex_secp_ha }, - { "mimes", 31, 0, _140_hex_mimes_d, _140_hex_mimes_ha }, - {} -}; -static c3_c* _140_hex_ha[] = { - "7e393356dd7ac64eed5cd9f5cf0e320d401ca36a0a0ce0f954e7538824114844", - 0 -}; - -/* layer five -*/ -static u3j_harm _140_pen_cell_a[] = {{".2", u3wf_cell}, {}}; -static c3_c* _140_pen_cell_ha[] = { - "411649e69ff5c5d4a2976b300d213b99af3de724cec0e95f48404b808fc4f428", - 0 -}; -static u3j_harm _140_pen_comb_a[] = {{".2", u3wf_comb}, {}}; -static c3_c* _140_pen_comb_ha[] = { - "f9e37c3b3d5036c31af60f7047391594068638b54db7cf94bfea9dabbdffa547", - 0 -}; -static u3j_harm _140_pen_cons_a[] = {{".2", u3wf_cons}, {}}; -static c3_c* _140_pen_cons_ha[] = { - "b698cc6bc49ea0473e344c784075e99a433b4c5738f90fc58ab17c3eaa44b2e9", - 0 -}; -static u3j_harm _140_pen_core_a[] = {{".2", u3wf_core}, {}}; -static c3_c* _140_pen_core_ha[] = { - "1180e9371cf3465783ef192f9a7f580cd90533f5b52b77b456287f1d580a3535", - 0 -}; -static u3j_harm _140_pen_face_a[] = {{".2", u3wf_face}, {}}; -static c3_c* _140_pen_face_ha[] = { - "a184c44d57f5c94b84a3258b05bf891f3c96a4a4bbff3a8934d11cad0efa81d8", - 0 -}; -static u3j_harm _140_pen_fitz_a[] = {{".2", u3wf_fitz}, {}}; -static c3_c* _140_pen_fitz_ha[] = { - "469abe976ec15eeff9a87bce385f2c87c9bd89814ce2858aa9fee094beea1e5d", - 0 -}; -static u3j_harm _140_pen_flan_a[] = {{".2", u3wf_flan}, {}}; -static c3_c* _140_pen_flan_ha[] = { - "cc00cb9373b0274af4e17d7acd77f65d8a2fa886e422c949c12d9d9e7cb3525b", - 0 -}; -static u3j_harm _140_pen_flip_a[] = {{".2", u3wf_flip}, {}}; -static c3_c* _140_pen_flip_ha[] = { - "6e97fab9d039e715a30af5da93ef97389babfdcae7ef87655d278e77a1af0f0c", - 0 -}; -static u3j_harm _140_pen_flor_a[] = {{".2", u3wf_flor}, {}}; -static c3_c* _140_pen_flor_ha[] = { - "ab5360aacf0c9a325727e90e1caea9c42f5d94ccc248c9e1f253b0922b4c4e63", - 0 -}; -static u3j_harm _140_pen_fork_a[] = {{".2", u3wf_fork}, {}}; -static c3_c* _140_pen_fork_ha[] = { - "36f0ea0e2eb30328b8b83ed43a81c8c9a1f5b4c5a03fd68fd25701991a40b9dd", - 0 -}; - -// hike disabled while implementing edit -// static u3j_harm _140_pen_hike_a[] = {{".2", u3wf_hike}, {}}; -// static c3_c* _140_pen_hike_ha[] = {0}; - -static u3j_harm _140_pen_look_a[] = {{".2", u3wf_look}, {}}; -static c3_c* _140_pen_look_ha[] = { - "fdda2166a2b9e1a9bda6ab375dd6fb6c610e18f54636a5e89896b45fd0a7169b", - 0 -}; -static u3j_harm _140_pen_loot_a[] = {{".2", u3wf_loot}, {}}; -static c3_c* _140_pen_loot_ha[] = { - "e275da4562ae6da9bd333aeae6b9829e886874c8b891898c0ef5306268eb45c1", - 0 -}; - - static u3j_harm _140_pen__ut_crop_a[] = {{".2", u3wfu_crop}, {}}; - static c3_c* _140_pen__ut_crop_ha[] = { - "e2c6fc3e714a3a98ccd28423dcb9f2c6480935e26b54dd0581eb2ad7e5b16d6f", - 0 - }; - static u3j_harm _140_pen__ut_fish_a[] = {{".2", u3wfu_fish}, {}}; - static c3_c* _140_pen__ut_fish_ha[] = { - "080caee60b5ee4616bf9568bdbceabbf044379c47466e0ae3968cb0146049a84", - 0 - }; - static u3j_harm _140_pen__ut_fuse_a[] = {{".2", u3wfu_fuse}, {}}; - static c3_c* _140_pen__ut_fuse_ha[] = { - "519aac7b40b7018d5df00ddf3977c2ebe0c2e05bcee34796d56a1d54c15e0c84", - 0 - }; - static u3j_harm _140_pen__ut_mint_a[] = {{".2", u3wfu_mint}, {}}; - static c3_c* _140_pen__ut_mint_ha[] = { - "7d980f7425b51bb10fbbd8b465b5d83f5dd4cb6e66d88758a9f7490b812a765e", - 0 - }; - static u3j_harm _140_pen__ut_mull_a[] = {{".2", u3wfu_mull}, {}}; - static c3_c* _140_pen__ut_mull_ha[] = { - "c806329aefd920501ea0faa0cfb0ce3280a74408782efe6d82878ec43ec44fb7", - 0 - }; - - static u3j_harm _140_pen__ut_nest_dext_a[] = {{".2", u3wfu_nest_dext}, {}}; - static c3_c* _140_pen__ut_nest_dext_ha[] = { - "72f33df96800034fc63531293f9b110e6505027195bf8a10ff94b9a1f1ef719b", - 0 - }; - static u3j_core _140_pen__ut_nest_in_d[] = - { - { "nest-dext", 3, _140_pen__ut_nest_dext_a, 0, _140_pen__ut_nest_dext_ha }, - {} - }; - static c3_c* _140_pen__ut_nest_in_ha[] = { - "68378dfa1d1fee0b1cd9593fb561234cec2ae9371a5ffa287c3d2ab9620e198c", - 0 - }; - - static u3j_core _140_pen__ut_nest_d[] = - { - { "nest-in", 7, 0, _140_pen__ut_nest_in_d, _140_pen__ut_nest_in_ha }, - {} - }; - static c3_c* _140_pen__ut_nest_ha[] = { - "1e8de5d1225facc1158c92c2ea5e0dc84129cbb317fde3691e224b8c2550d950", - 0 - }; - - static u3j_harm _140_pen__ut_rest_a[] = {{".2", u3wfu_rest}, {}}; - static c3_c* _140_pen__ut_rest_ha[] = { - "b4a83073f4cb03898ef099fab5722a046122dc96a5332ffc82f988df6c186e74", - 0 - }; - -static u3j_core _140_pen__ut_d[] = - { - { "crop", 7, _140_pen__ut_crop_a, 0, _140_pen__ut_crop_ha }, - { "fish", 7, _140_pen__ut_fish_a, 0, _140_pen__ut_fish_ha }, - { "fuse", 7, _140_pen__ut_fuse_a, 0, _140_pen__ut_fuse_ha }, - { "mint", 7, _140_pen__ut_mint_a, 0, _140_pen__ut_mint_ha }, - { "mull", 7, _140_pen__ut_mull_a, 0, _140_pen__ut_mull_ha }, - { "nest", 7, 0, _140_pen__ut_nest_d, _140_pen__ut_nest_ha }, - { "rest", 7, _140_pen__ut_rest_a, 0, _140_pen__ut_rest_ha }, - {} - }; - -static c3_c* _140_pen__ut_ha[] = { - "50c79204c82a3ba8f01e085a2e27e7716e5c7ab1929f94423ef1da92cf5ac631", - 0 -}; - -static u3j_hood _140_pen__ut_ho[] = { - { "ar", 12282 }, - { "fan", 28, c3n }, - { "rib", 58, c3n }, - { "vet", 59, c3n }, - - { "blow", 6015 }, - { "burp", 342 }, - { "busk", 1373 }, - { "buss", 374 }, - { "crop", 1494 }, - { "duck", 1524 }, - { "dune", 2991 }, - { "dunk", 3066 }, - { "epla", 12206 }, - { "emin", 1534 }, - { "emul", 6134 }, - { "feel", 1502 }, - { "felt", 94 }, - { "fine", 49086 }, - { "fire", 4 }, - { "fish", 6006 }, - { "fond", 12283 }, - { "fund", 6014 }, - // XX +funk is not part of +ut, and this hook appears to be unused - // remove from here and the +ut hint - // - { "funk", 0xbefafa, c3y, 31 }, - { "fuse", 24021 }, - { "gain", 380 }, - { "lose", 0x2fefe }, - { "mile", 382 }, - { "mine", 372 }, - { "mint", 49083 }, - { "moot", 0x2feff }, - { "mull", 24020 }, - { "nest", 92 }, - { "peel", 1526 }, - { "play", 3006 }, - { "peek", 1532 }, - { "repo", 22 }, - { "rest", 6102 }, - { "tack", 6007 }, - { "toss", 24540 }, - { "wrap", 6140 }, - {}, -}; - -// XX unused, hook removed, delete source -// -#if 0 -static u3j_harm _140_pen__ap_a[] = - { {"open", u3wfp_open}, - {"rake", u3wfp_rake}, - {} - }; -static c3_c* _140_pen__ap_ha[] = {0}; -#endif - -static u3j_core _140_pen_d[] = -{ { "hex", 7, 0, _140_hex_d, _140_hex_ha }, - - { "cell", 7, _140_pen_cell_a, 0, _140_pen_cell_ha }, - { "comb", 7, _140_pen_comb_a, 0, _140_pen_comb_ha }, - { "cons", 7, _140_pen_cons_a, 0, _140_pen_cons_ha }, - { "core", 7, _140_pen_core_a, 0, _140_pen_core_ha }, - { "face", 7, _140_pen_face_a, 0, _140_pen_face_ha }, - { "fitz", 7, _140_pen_fitz_a, 0, _140_pen_fitz_ha }, - { "flan", 7, _140_pen_flan_a, 0, _140_pen_flan_ha }, - { "flip", 7, _140_pen_flip_a, 0, _140_pen_flip_ha }, - { "flor", 7, _140_pen_flor_a, 0, _140_pen_flor_ha }, - { "fork", 7, _140_pen_fork_a, 0, _140_pen_fork_ha }, - // XX implementation obsolete, update or remove - // - // { "hike", 7, _140_pen_hike_a, 0, _140_pen_hike_ha }, - { "look", 7, _140_pen_look_a, 0, _140_pen_look_ha }, - { "loot", 7, _140_pen_loot_a, 0, _140_pen_loot_ha }, - - // XX unused, hook removed, delete source - // - // { "ap", 7, _140_pen__ap_a, 0, _140_pen__ap_ha }, - { "ut", 15, 0, _140_pen__ut_d, _140_pen__ut_ha, _140_pen__ut_ho }, - {} -}; -static c3_c* _140_pen_ha[] = { - "e6c9e2362bdf2d1f9a2837a0efa154c0b8b9d51aea03a86b5aece573ff423cb1", - 0 -}; - -static u3j_hood _140_pen_ho[] = { - { "ap", 22 }, - { "ut", 86 }, - {}, -}; - -/* layer four -*/ -static u3j_harm _140_qua_trip_a[] = {{".2", u3we_trip}, {}}; -static c3_c* _140_qua_trip_ha[] = { - "05423b940d10d03891cc23f36eea14b233e5884ef539de3d985d6818dd427b05", - 0 -}; - -static u3j_harm _140_qua_slaw_a[] = {{".2", u3we_slaw}, {}}; -static c3_c* _140_qua_slaw_ha[] = { - "306c9692f48e2700675ed6581e9df4feaee951e1bed3cad7f89aab392e80000f", - 0 -}; -static u3j_harm _140_qua_scot_a[] = {{".2", u3we_scot}, {}}; -static c3_c* _140_qua_scot_ha[] = { - 0 -}; -static u3j_harm _140_qua_scow_a[] = {{".2", u3we_scow}, {}}; -static c3_c* _140_qua_scow_ha[] = { - 0 -}; - -static u3j_harm _140_qua__po_ind_a[] = {{".2", u3wcp_ind}, {}}; -static c3_c* _140_qua__po_ind_ha[] = { - "95bbe9867dbbd1b9ce12671d64cf7b1dee8d987c6770955a83c73291c4537a61", - 0 -}; -static u3j_harm _140_qua__po_ins_a[] = {{".2", u3wcp_ins}, {}}; -static c3_c* _140_qua__po_ins_ha[] = { - "aae783fb258dff7f8ade49756e01f96a2d2100411a88a886732270dcf9f174f0", - 0 -}; -static u3j_harm _140_qua__po_tod_a[] = {{".2", u3wcp_tod}, {}}; -static c3_c* _140_qua__po_tod_ha[] = { - "153aeba45ca2a87aa918e9cea1b26e8104a6e4395979257b075546c1e2654a17", - 0 -}; -static u3j_harm _140_qua__po_tos_a[] = {{".2", u3wcp_tos}, {}}; -static c3_c* _140_qua__po_tos_ha[] = { - "7c5ffad03bcf8b4ea9bdf0c7f7500351923bc0431f3d62d6ce0472790f668fb4", - 0 -}; - static u3j_core _140_qua__po_d[] = - { { "ind", 7, _140_qua__po_ind_a, 0, _140_qua__po_ind_ha }, - { "ins", 7, _140_qua__po_ins_a, 0, _140_qua__po_ins_ha }, - { "tod", 7, _140_qua__po_tod_a, 0, _140_qua__po_tod_ha }, - { "tos", 7, _140_qua__po_tos_a, 0, _140_qua__po_tos_ha }, - {} - }; - static c3_c* _140_qua__po_ha[] = { - "efc5fa7c0efedd490e9a270bb5cf9f90809e6b224f8a381a6b8a481253b237a1", - 0 - }; - -static u3j_harm _140_qua__bend_fun_a[] = {{".2", u3we_bend_fun}, {}}; -static c3_c* _140_qua__bend_fun_ha[] = { - "e6ea05e3d765a005fccde9eb88fb93e06f0b6ea198afa8ed599b056ba179396a", - 0 -}; - static u3j_core _140_qua__bend_d[] = - { { "fun", 7, _140_qua__bend_fun_a, 0, _140_qua__bend_fun_ha }, - {} - }; - static c3_c* _140_qua__bend_ha[] = { - "adc59c6db6d5b26122bc6c04e25c3efe830c9eef68ecf81c492a59ee5e9e20a2", - 0 - }; - -static u3j_harm _140_qua__cold_fun_a[] = {{".2", u3we_cold_fun}, {}}; -static c3_c* _140_qua__cold_fun_ha[] = { - "ad5a0ab7405be9ffda0a9dd34580c6039f6bbb0301920fb2df0c31be3c72c58e", - 0 -}; - static u3j_core _140_qua__cold_d[] = - { { "fun", 7, _140_qua__cold_fun_a, 0, _140_qua__cold_fun_ha }, - {} - }; - static c3_c* _140_qua__cold_ha[] = { - "06c49d8dab6cb057e3ae1d1164e96950944ea48e54ad72347239ea434f1d4b9c", - 0 - }; - -static u3j_harm _140_qua__cook_fun_a[] = {{".2", u3we_cook_fun}, {}}; -static c3_c* _140_qua__cook_fun_ha[] = { - "f2a45612ad9c279b723334ab0915d3ed3ece7727309968c2555f45e0668eeb27", - 0 -}; - static u3j_core _140_qua__cook_d[] = - { { "fun", 7, _140_qua__cook_fun_a, 0, _140_qua__cook_fun_ha }, - {} - }; - static c3_c* _140_qua__cook_ha[] = { - "3ccd46dd21828d7be11f8c093536e305b1df982393a69c40ea73f63a574b3bb1", - 0 - }; - -static u3j_harm _140_qua__comp_fun_a[] = {{".2", u3we_comp_fun}, {}}; -static c3_c* _140_qua__comp_fun_ha[] = { - "bd7fdba84b05b00a63c24d19a03b882578ee9a3b922a3a688f7827c6e64daf96", - 0 -}; - static u3j_core _140_qua__comp_d[] = - { { "fun", 7, _140_qua__comp_fun_a, 0, _140_qua__comp_fun_ha }, - {} - }; - static c3_c* _140_qua__comp_ha[] = { - "7baad25ba87bcbba8ce4fe328280a799765dcf62a8bb761ffd87b939dd8734f2", - 0 - }; - -static u3j_harm _140_qua__easy_fun_a[] = {{".2", u3we_easy_fun}, {}}; -static c3_c* _140_qua__easy_fun_ha[] = { - "4bbbc43ece463d961e572301d0824d3e3cab3ba09ec2756cbefae63ee106044b", - 0 -}; - static u3j_core _140_qua__easy_d[] = - { { "fun", 7, _140_qua__easy_fun_a, 0, _140_qua__easy_fun_ha }, - {} - }; - static c3_c* _140_qua__easy_ha[] = { - "fdcf833943e24323deb6b071497498933ce6c4ba7d4742f2752b6ddb7fb9634e", - 0 - }; - -static u3j_harm _140_qua__glue_fun_a[] = {{".2", u3we_glue_fun}, {}}; -static c3_c* _140_qua__glue_fun_ha[] = { - "ffe0fe8815a2298c51a58e963efbbb7af90830abf11ce50bf9a47f479ce452fb", - 0 -}; - static u3j_core _140_qua__glue_d[] = - { { "fun", 7, _140_qua__glue_fun_a, 0, _140_qua__glue_fun_ha }, - {} - }; - static c3_c* _140_qua__glue_ha[] = { - "079c8a395428c2921b266a84bcf271fbe62f3d873b26680661e13a78df1a3989", - 0 - }; - -static u3j_harm _140_qua__here_fun_a[] = {{".2", u3we_here_fun}, {}}; -static c3_c* _140_qua__here_fun_ha[] = { - "47ec445fcfa89d266dae3c3590ed041d1b05f92d1bce360f232da5d496e4f2eb", - 0 -}; - static u3j_core _140_qua__here_d[] = - { { "fun", 7, _140_qua__here_fun_a, 0, _140_qua__here_fun_ha }, - {} - }; - static c3_c* _140_qua__here_ha[] = { - "4600093be5becba9a65a14b67624e3d9e4c66e0c97ba57b2bc271907eea32ffe", - 0 - }; - -static u3j_harm _140_qua__just_fun_a[] = {{".2", u3we_just_fun}, {}}; -static c3_c* _140_qua__just_fun_ha[] = { - "38bf1fb843bc29837868f2828f32d7e2bbb419b0cb9a1236adea28dfc6ce1040", - 0 -}; - static u3j_core _140_qua__just_d[] = - { { "fun", 7, _140_qua__just_fun_a, 0, _140_qua__just_fun_ha }, - {} - }; - static c3_c* _140_qua__just_ha[] = { - "7d6b2165e52dec478d96cf72478a35b7a92b014e6a15f046f026c0c8cb07679b", - 0 - }; - -static u3j_harm _140_qua__mask_fun_a[] = {{".2", u3we_mask_fun}, {}}; -static c3_c* _140_qua__mask_fun_ha[] = { - "892dfcd5f3d90981fa6e7608e93f0517000d316e7d9c07b3bd390c4966c97f5f", - 0 -}; - static u3j_core _140_qua__mask_d[] = - { { "fun", 7, _140_qua__mask_fun_a, 0, _140_qua__mask_fun_ha }, - {} - }; - static c3_c* _140_qua__mask_ha[] = { - "48e11fc12d7c453cda6ca42577d68e968446aa4d0ad3b99cc674affc7f4507b4", - 0 - }; - -static u3j_harm _140_qua__shim_fun_a[] = {{".2", u3we_shim_fun}, {}}; -static c3_c* _140_qua__shim_fun_ha[] = { - "4e26a0e98adb13ee6718fd68d90910c630df9bb7023b3e3ef40cda6710075fc9", - 0 -}; - static u3j_core _140_qua__shim_d[] = - { { "fun", 7, _140_qua__shim_fun_a, 0, _140_qua__shim_fun_ha }, - {} - }; - static c3_c* _140_qua__shim_ha[] = { - "226b96d1a59daada23a1ea80227c2dbf32ddd748d4c6363f316147ab7f292ced", - 0 - }; - -static u3j_harm _140_qua__stag_fun_a[] = {{".2", u3we_stag_fun}, {}}; -static c3_c* _140_qua__stag_fun_ha[] = { - "f76c7205c23e77809af793bc506f4727071fd029d234317fe78a7f65e2b7d6ea", - 0 -}; - static u3j_core _140_qua__stag_d[] = - { { "fun", 7, _140_qua__stag_fun_a, 0, _140_qua__stag_fun_ha }, - {} - }; - static c3_c* _140_qua__stag_ha[] = { - "fc978af18fb13dc0d77501b6f3eeb538b079b4345eb9195c3dd44c516e69424a", - 0 - }; - -static u3j_harm _140_qua__stew_fun_a[] = {{".2", u3we_stew_fun}, {}}; -static c3_c* _140_qua__stew_fun_ha[] = { - "a700f6bdfdb83ba33b2a3fe92fda3cb1bbfe95e595401538c8371b55fcc61447", - 0 -}; - static u3j_core _140_qua__stew_d[] = - { { "fun", 31, _140_qua__stew_fun_a, 0, _140_qua__stew_fun_ha }, - {} - }; - static c3_c* _140_qua__stew_ha[] = { - "29303fd6ab78cbbccdfc5bcf23d0bff126a0ef2bf4fa11ce70fcf4e6aa5fe60b", - 0 - }; - -static u3j_harm _140_qua__stir_fun_a[] = {{".2", u3we_stir_fun}, {}}; -static c3_c* _140_qua__stir_fun_ha[] = { - "6251308ea3c741e76ef9cb2dc5a71c9d8706d6cce6fdb420fef12915e0c032d6", - 0 -}; - static u3j_core _140_qua__stir_d[] = - { { "fun", 7, _140_qua__stir_fun_a, 0, _140_qua__stir_fun_ha }, - {} - }; - static c3_c* _140_qua__stir_ha[] = { - "4e466aef4d91f0ced008c00e8a4330afb3a43ef81dc1a6d93f1853685f69b9ca", - 0 - }; - -static u3j_harm _140_qua_pfix_a[] = {{".2", u3we_pfix}, {}}; -static c3_c* _140_qua_pfix_ha[] = { - "f7019bccc8b3b04a969878ffed84c9eba4dfa60ee32f984119cacb0c2381656b", - 0 -}; - -static u3j_harm _140_qua_plug_a[] = {{".2", u3we_plug}, {}}; -static c3_c* _140_qua_plug_ha[] = { - "5f5a9824e0952fd565748cc0a20f96cf883a41e2f5707c8a7797e6edd617b79c", - 0 -}; -static u3j_harm _140_qua_pose_a[] = {{".2", u3we_pose}, {}}; -static c3_c* _140_qua_pose_ha[] = { - "5c77203f288ef0f7bcd87871c69673db7fc804b647ecc42992707dc32f0f4611", - 0 -}; - -static u3j_harm _140_qua_sfix_a[] = {{".2", u3we_sfix}, {}}; -static c3_c* _140_qua_sfix_ha[] = { - "00987ed37104b902c5264d4d013826d762bfa80a6b29cfe4b7fa61b1ddd9cfac", - 0 -}; - -static u3j_harm _140_qua_mink_a[] = {{".2", u3we_mink}, {}}; -static c3_c* _140_qua_mink_ha[] = { - "99b653da6a21fa3375424811af288f59164592ece4a072abc460df03e81abcaf", - 0 -}; -static u3j_harm _140_qua_mole_a[] = {{".2", u3we_mole}, {}}; -static c3_c* _140_qua_mole_ha[] = { - "029c1acaff1911c54ce31a3693397394604ea970bf076078c1a1cfa23d2fa74e", - 0 -}; -static u3j_harm _140_qua_mule_a[] = {{".2", u3we_mule}, {}}; -static c3_c* _140_qua_mule_ha[] = { - "d54688d726565ddade7f2636741cad7209ea40fab28d3335555d8a02ff6001c4", - 0 -}; - -static u3j_core _140_qua_d[] = -{ { "pen", 3, 0, _140_pen_d, _140_pen_ha, _140_pen_ho }, - - { "po", 7, 0, _140_qua__po_d, _140_qua__po_ha }, - - { "trip", 7, _140_qua_trip_a, 0, _140_qua_trip_ha }, - - { "bend", 7, 0, _140_qua__bend_d, _140_qua__bend_ha }, - { "cold", 7, 0, _140_qua__cold_d, _140_qua__cold_ha }, - { "comp", 7, 0, _140_qua__comp_d, _140_qua__comp_ha }, - { "cook", 7, 0, _140_qua__cook_d, _140_qua__cook_ha }, - { "easy", 7, 0, _140_qua__easy_d, _140_qua__easy_ha }, - { "glue", 7, 0, _140_qua__glue_d, _140_qua__glue_ha }, - { "here", 7, 0, _140_qua__here_d, _140_qua__here_ha }, - { "just", 7, 0, _140_qua__just_d, _140_qua__just_ha }, - { "mask", 7, 0, _140_qua__mask_d, _140_qua__mask_ha }, - { "shim", 7, 0, _140_qua__shim_d, _140_qua__shim_ha }, - { "stag", 7, 0, _140_qua__stag_d, _140_qua__stag_ha }, - { "stew", 7, 0, _140_qua__stew_d, _140_qua__stew_ha }, - { "stir", 7, 0, _140_qua__stir_d, _140_qua__stir_ha }, - - { "pfix", 7, _140_qua_pfix_a, 0, _140_qua_pfix_ha }, - { "plug", 7, _140_qua_plug_a, 0, _140_qua_plug_ha }, - { "pose", 7, _140_qua_pose_a, 0, _140_qua_pose_ha }, - { "sfix", 7, _140_qua_sfix_a, 0, _140_qua_sfix_ha }, - - { "mink", 7, _140_qua_mink_a, 0, _140_qua_mink_ha }, - { "mole", 7, _140_qua_mole_a, 0, _140_qua_mole_ha }, - { "mule", 7, _140_qua_mule_a, 0, _140_qua_mule_ha }, - - // XX disabled, implicated in memory corruption - // write tests and re-enable - // - // { "scot", 7, _140_qua_scot_a, 0, _140_qua_scot_ha }, - // { "scow", 7, _140_qua_scow_a, 0, _140_qua_scow_ha }, - { "slaw", 7, _140_qua_slaw_a, 0, _140_qua_slaw_ha }, - {} -}; -static c3_c* _140_qua_ha[] = { - "db9b4b21c0a8a8324105cbccc1421ef2a715ef0562c280b943fe1d96651cd9cc", - 0 -}; - -static u3j_hood _140_qua_ho[] = { - { "mute", 0x2fbabe }, - { "show", 24406 }, - { "mure", 1404 }, - {}, -}; - -/* layer three -*/ - static u3j_harm _140_tri__cofl__drg_a[] = {{".2", u3wef_drg}, {}}; - static c3_c* _140_tri__cofl__drg_ha[] = { - "6063adb8cac639f7b20d5e7700c8108266be04f99cce4434f906240b424bf36d", - 0 - }; - static u3j_harm _140_tri__cofl__lug_a[] = {{".2", u3wef_lug}, {}}; - static c3_c* _140_tri__cofl__lug_ha[] = { - "f146a84731447e5c4b1e7b6e9331b33d1babed09bb0618e134c9535062154a87", - 0 - }; -static u3j_core _140_tri__cofl_d[] = - { { "drg", 7, _140_tri__cofl__drg_a, 0, _140_tri__cofl__drg_ha }, - { "lug", 7, _140_tri__cofl__lug_a, 0, _140_tri__cofl__lug_ha }, - {} - }; -static c3_c* _140_tri__cofl_ha[] = { - "f320c5bf51db85f55b900f4160f7e0ab9ef267f43ddb698900de034c6e2600d5", - 0 -}; - - static u3j_harm _140_tri__rd_add_a[] = {{".2", u3wer_add}, {}}; - static c3_c* _140_tri__rd_add_ha[] = { - "90dfaaadb2878d6d89a808ce4199e5bb239fa981e1c2edf24dc54aa3fcab55a5", - 0 - }; - static u3j_harm _140_tri__rd_sub_a[] = {{".2", u3wer_sub}, {}}; - static c3_c* _140_tri__rd_sub_ha[] = { - "5898a2424ba815d66d83917953f01860e63207f4200a447f632d9a5cc77a8a9c", - 0 - }; - static u3j_harm _140_tri__rd_mul_a[] = {{".2", u3wer_mul}, {}}; - static c3_c* _140_tri__rd_mul_ha[] = { - "a3af44ef4cd89afe78f1088bddb7d56dfa7fc209153256557c98ff34b67976bc", - 0 - }; - static u3j_harm _140_tri__rd_div_a[] = {{".2", u3wer_div}, {}}; - static c3_c* _140_tri__rd_div_ha[] = { - "9be3b38b9b4b0b0cd0bb060529c8f439cb0589aa9c3528efc519fbcc6845e98d", - 0 - }; - static u3j_harm _140_tri__rd_sqt_a[] = {{".2", u3wer_sqt}, {}}; - static c3_c* _140_tri__rd_sqt_ha[] = { - "0413678ac8ec89c3425ba762cd24b2a8a455543ec9b5dd719524e6b834e0c99c", - 0 - }; - static u3j_harm _140_tri__rd_fma_a[] = {{".2", u3wer_fma}, {}}; - static c3_c* _140_tri__rd_fma_ha[] = { - "7c920238dd42fb645c057cc950ed7ece775d5f502a0faf6ef5d17d348e0fc3e3", - 0 - }; - static u3j_harm _140_tri__rd_lth_a[] = {{".2", u3wer_lth}, {}}; - static c3_c* _140_tri__rd_lth_ha[] = { - "a108f1ac15c1d4e2c86457c9afc97a97a5954003c709c3c19c722b37255bcba9", - 0 - }; - static u3j_harm _140_tri__rd_lte_a[] = {{".2", u3wer_lte}, {}}; - static c3_c* _140_tri__rd_lte_ha[] = { - "ef9a6b2c5cdd0d4de550a32679d242693131cdc3cf40ac914eadfa7d6d9f1bac", - 0 - }; - static u3j_harm _140_tri__rd_equ_a[] = {{".2", u3wer_equ}, {}}; - static c3_c* _140_tri__rd_equ_ha[] = { - "c93cdb951dca3b0ac61070780f95e1baa3718fe519d0268305c032cf14a21e39", - 0 - }; - static u3j_harm _140_tri__rd_gte_a[] = {{".2", u3wer_gte}, {}}; - static c3_c* _140_tri__rd_gte_ha[] = { - "6857077d97e2fc203b555dc20748c33d34b694d33c48f628543bea6491e722a6", - 0 - }; - static u3j_harm _140_tri__rd_gth_a[] = {{".2", u3wer_gth}, {}}; - static c3_c* _140_tri__rd_gth_ha[] = { - "87fd815913fa590c715d3a96ada5bae6298f3e7823af90ffcdf235f493c56330", - 0 - }; -static u3j_core _140_tri__rd_d[] = - { { "add", 7, _140_tri__rd_add_a, 0, _140_tri__rd_add_ha }, - { "sub", 7, _140_tri__rd_sub_a, 0, _140_tri__rd_sub_ha }, - { "mul", 7, _140_tri__rd_mul_a, 0, _140_tri__rd_mul_ha }, - { "div", 7, _140_tri__rd_div_a, 0, _140_tri__rd_div_ha }, - { "sqt", 7, _140_tri__rd_sqt_a, 0, _140_tri__rd_sqt_ha }, - { "fma", 7, _140_tri__rd_fma_a, 0, _140_tri__rd_fma_ha }, - { "lth", 7, _140_tri__rd_lth_a, 0, _140_tri__rd_lth_ha }, - { "lte", 7, _140_tri__rd_lte_a, 0, _140_tri__rd_lte_ha }, - { "equ", 7, _140_tri__rd_equ_a, 0, _140_tri__rd_equ_ha }, - { "gte", 7, _140_tri__rd_gte_a, 0, _140_tri__rd_gte_ha }, - { "gth", 7, _140_tri__rd_gth_a, 0, _140_tri__rd_gth_ha }, - {} - }; -static c3_c* _140_tri__rd_ha[] = { - "0afab285837f9c88faff3ac8f3f49b5e259da253e0505cd823a53d4e826261f7", - 0 -}; - - static u3j_harm _140_tri__rs_add_a[] = {{".2", u3wet_add}, {}}; - static c3_c* _140_tri__rs_add_ha[] = { - "b89a1e348628fd9b4fd520aabbf6c53e12be5bbf661b9094f7a9841be3f51de9", - 0 - }; - static u3j_harm _140_tri__rs_sub_a[] = {{".2", u3wet_sub}, {}}; - static c3_c* _140_tri__rs_sub_ha[] = { - "9d13b86d17908830f93b920e80e1a985105583597f6fb640f175c98052e357f1", - 0 - }; - static u3j_harm _140_tri__rs_mul_a[] = {{".2", u3wet_mul}, {}}; - static c3_c* _140_tri__rs_mul_ha[] = { - "5c61a9e335f6c139332523d871ca5773ab476365b623444370474fde08639061", - 0 - }; - static u3j_harm _140_tri__rs_div_a[] = {{".2", u3wet_div}, {}}; - static c3_c* _140_tri__rs_div_ha[] = { - "a7147a81be3ef5a1c0de6587edb2990e30057d7871d73632eabc8dc567e751c8", - 0 - }; - static u3j_harm _140_tri__rs_sqt_a[] = {{".2", u3wet_sqt}, {}}; - static c3_c* _140_tri__rs_sqt_ha[] = { - "c403bb48d78bcfa9cd4128b7f9eb362e71e5269ab6578fb0bb5e70b4244c5781", - 0 - }; - static u3j_harm _140_tri__rs_fma_a[] = {{".2", u3wet_fma}, {}}; - static c3_c* _140_tri__rs_fma_ha[] = { - "afc14914eb8f579a0c6620db69bc951329325747a8ef01c2d0e5feb29e9a9ddd", - 0 - }; - static u3j_harm _140_tri__rs_lth_a[] = {{".2", u3wet_lth}, {}}; - static c3_c* _140_tri__rs_lth_ha[] = { - "e7efa422def6b6dbd25b5f664462adb3895b8b45f9531877c9dbfe40a96612bf", - 0 - }; - static u3j_harm _140_tri__rs_lte_a[] = {{".2", u3wet_lte}, {}}; - static c3_c* _140_tri__rs_lte_ha[] = { - "b45e1ef16c47dc9b99865c7e75d4c2094c0e206ed538818a38da0adb7fbe2ce3", - 0 - }; - static u3j_harm _140_tri__rs_equ_a[] = {{".2", u3wet_equ}, {}}; - static c3_c* _140_tri__rs_equ_ha[] = { - "8c1178311ded837292c297380e48cf7e0bc4d83962dadcafda0c9ef9f20e39f2", - 0 - }; - static u3j_harm _140_tri__rs_gte_a[] = {{".2", u3wet_gte}, {}}; - static c3_c* _140_tri__rs_gte_ha[] = { - "50f5eb237b74e772eb6a3257441078461450cd4a25cf9bd97cb1a5e00f4ff4d2", - 0 - }; - static u3j_harm _140_tri__rs_gth_a[] = {{".2", u3wet_gth}, {}}; - static c3_c* _140_tri__rs_gth_ha[] = { - "505842ff486f0bb8fa63f04d2fd6f806dc760f9b4a12a3bf2d57da92f560785b", - 0 - }; -static u3j_core _140_tri__rs_d[] = - { { "add", 7, _140_tri__rs_add_a, 0, _140_tri__rs_add_ha }, - { "sub", 7, _140_tri__rs_sub_a, 0, _140_tri__rs_sub_ha }, - { "mul", 7, _140_tri__rs_mul_a, 0, _140_tri__rs_mul_ha }, - { "div", 7, _140_tri__rs_div_a, 0, _140_tri__rs_div_ha }, - { "sqt", 7, _140_tri__rs_sqt_a, 0, _140_tri__rs_sqt_ha }, - { "fma", 7, _140_tri__rs_fma_a, 0, _140_tri__rs_fma_ha }, - { "lth", 7, _140_tri__rs_lth_a, 0, _140_tri__rs_lth_ha }, - { "lte", 7, _140_tri__rs_lte_a, 0, _140_tri__rs_lte_ha }, - { "equ", 7, _140_tri__rs_equ_a, 0, _140_tri__rs_equ_ha }, - { "gte", 7, _140_tri__rs_gte_a, 0, _140_tri__rs_gte_ha }, - { "gth", 7, _140_tri__rs_gth_a, 0, _140_tri__rs_gth_ha }, - {} - }; - static c3_c* _140_tri__rs_ha[] = { - "6c7027c5de34540a4b1548039e5423fb44727079af054b7135a3e961ec8dede8", - 0 - }; - - static u3j_harm _140_tri__rq_add_a[] = {{".2", u3weq_add}, {}}; - static c3_c* _140_tri__rq_add_ha[] = { - "9c4c2a37550930605495401886d41fb9fbc2eba487e0ba845130fe88e4c52a01", - 0 - }; - static u3j_harm _140_tri__rq_sub_a[] = {{".2", u3weq_sub}, {}}; - static c3_c* _140_tri__rq_sub_ha[] = { - "f3b027090a1bb5af74234301facfbf64503b3e0599501ade12cb05aa158a79a3", - 0 - }; - static u3j_harm _140_tri__rq_mul_a[] = {{".2", u3weq_mul}, {}}; - static c3_c* _140_tri__rq_mul_ha[] = { - "15c03b1f3081514c4767d86297aaebf1d62af7f3437f30821f011b17ed769f3a", - 0 - }; - static u3j_harm _140_tri__rq_div_a[] = {{".2", u3weq_div}, {}}; - static c3_c* _140_tri__rq_div_ha[] = { - "094105c77e37e548ea1b8d49a132ab97d90a0ab5f329340400c381bcd44de347", - 0 - }; - static u3j_harm _140_tri__rq_sqt_a[] = {{".2", u3weq_sqt}, {}}; - static c3_c* _140_tri__rq_sqt_ha[] = { - "a031cd5b8e05f997323b0ca1ca9d2419401d7d2acc2da6fc6387fe57701b84b0", - 0 - }; - static u3j_harm _140_tri__rq_fma_a[] = {{".2", u3weq_fma}, {}}; - static c3_c* _140_tri__rq_fma_ha[] = { - "871664a9305808a671aacf1de0e83f8e951611033170d86370352afb363b79bc", - 0 - }; - static u3j_harm _140_tri__rq_lth_a[] = {{".2", u3weq_lth}, {}}; - static c3_c* _140_tri__rq_lth_ha[] = { - "b10822caa442c8e9f6b9eb52aac5796a42bed5ae0eef7fe49d4075b38bf78ddd", - 0 - }; - static u3j_harm _140_tri__rq_lte_a[] = {{".2", u3weq_lte}, {}}; - static c3_c* _140_tri__rq_lte_ha[] = { - "3316346be3e9464fbb5b0feff16cd2252086004229d08f8eaa320f9509d6a029", - 0 - }; - static u3j_harm _140_tri__rq_equ_a[] = {{".2", u3weq_equ}, {}}; - static c3_c* _140_tri__rq_equ_ha[] = { - "154be82a7b8ecf4571015d9ef6c0e90ffd8c3e8803441d9c2df5a4ea484ccf3b", - 0 - }; - static u3j_harm _140_tri__rq_gte_a[] = {{".2", u3weq_gte}, {}}; - static c3_c* _140_tri__rq_gte_ha[] = { - "edbe94f9cfefa89deef7f6c11f4ce8240fd93970dbd6130e632d0447452a612a", - 0 - }; - static u3j_harm _140_tri__rq_gth_a[] = {{".2", u3weq_gth}, {}}; - static c3_c* _140_tri__rq_gth_ha[] = { - "50e85936cfad61659ed1bfdab26fda2b2696571b9aa4b4c55dc5c0d919edc296", - 0 - }; -static u3j_core _140_tri__rq_d[] = - { { "add", 7, _140_tri__rq_add_a, 0, _140_tri__rq_add_ha }, - { "sub", 7, _140_tri__rq_sub_a, 0, _140_tri__rq_sub_ha }, - { "mul", 7, _140_tri__rq_mul_a, 0, _140_tri__rq_mul_ha }, - { "div", 7, _140_tri__rq_div_a, 0, _140_tri__rq_div_ha }, - { "sqt", 7, _140_tri__rq_sqt_a, 0, _140_tri__rq_sqt_ha }, - { "fma", 7, _140_tri__rq_fma_a, 0, _140_tri__rq_fma_ha }, - { "lth", 7, _140_tri__rq_lth_a, 0, _140_tri__rq_lth_ha }, - { "lte", 7, _140_tri__rq_lte_a, 0, _140_tri__rq_lte_ha }, - { "equ", 7, _140_tri__rq_equ_a, 0, _140_tri__rq_equ_ha }, - { "gte", 7, _140_tri__rq_gte_a, 0, _140_tri__rq_gte_ha }, - { "gth", 7, _140_tri__rq_gth_a, 0, _140_tri__rq_gth_ha }, - {} - }; -static c3_c* _140_tri__rq_ha[] = { - "b772cd5901a18dc91852fada74c2a1e4b1bbf4e7465451b0d8bdcc86d2288c22", - 0 -}; - - static u3j_harm _140_tri__rh_add_a[] = {{".2", u3wes_add}, {}}; - static c3_c* _140_tri__rh_add_ha[] = { - "7e2b600eced08d774800a6a3d82e18189db85010b870c26905ee38008d3d301e", - 0 - }; - static u3j_harm _140_tri__rh_sub_a[] = {{".2", u3wes_sub}, {}}; - static c3_c* _140_tri__rh_sub_ha[] = { - "827dfb41660cb4743a88d921b4185bd2000ee6f0708ec36ac8aba2e4e19c0875", - 0 - }; - static u3j_harm _140_tri__rh_mul_a[] = {{".2", u3wes_mul}, {}}; - static c3_c* _140_tri__rh_mul_ha[] = { - "ec2a010128aca0a6f74196f3de4fe7b6617fd810d3b19f7bf5878afb787e8b86", - 0 - }; - static u3j_harm _140_tri__rh_div_a[] = {{".2", u3wes_div}, {}}; - static c3_c* _140_tri__rh_div_ha[] = { - "067a3dafb0158bc2441729beb2c0934c6c6ccf0a9b5193db9c16f22b490b27c6", - 0 - }; - static u3j_harm _140_tri__rh_sqt_a[] = {{".2", u3wes_sqt}, {}}; - static c3_c* _140_tri__rh_sqt_ha[] = { - "3fdbba47626d91d41fcdf460ad38018c78b0233d7ec4d0fac406a8c5357a2384", - 0 - }; - static u3j_harm _140_tri__rh_fma_a[] = {{".2", u3wes_fma}, {}}; - static c3_c* _140_tri__rh_fma_ha[] = { - "ada2adf5a88ba61759219926aef950e72ae6926c6e10c30ecd0f9c99e79beca0", - 0 - }; - static u3j_harm _140_tri__rh_lth_a[] = {{".2", u3wes_lth}, {}}; - static c3_c* _140_tri__rh_lth_ha[] = { - "70c9bc0073d23371d8155c28795f5acbff1a9504a5a3881c8693aa7c1f3d35d4", - 0 - }; - static u3j_harm _140_tri__rh_lte_a[] = {{".2", u3wes_lte}, {}}; - static c3_c* _140_tri__rh_lte_ha[] = { - "6157e766050f9697c05b111ad2a582459a63a98b3b1ec70881f9ad943f951a0d", - 0 - }; - static u3j_harm _140_tri__rh_equ_a[] = {{".2", u3wes_equ}, {}}; - static c3_c* _140_tri__rh_equ_ha[] = { - "72664392e2a00137383aa5a55e947c5e95c7b3172f71a7238dc0d55050196884", - 0 - }; - static u3j_harm _140_tri__rh_gte_a[] = {{".2", u3wes_gte}, {}}; - static c3_c* _140_tri__rh_gte_ha[] = { - "145355b13712b9471031e755d0ab271907efdb9a287b1bacb2f1d0338d28dbf6", - 0 - }; - static u3j_harm _140_tri__rh_gth_a[] = {{".2", u3wes_gth}, {}}; - static c3_c* _140_tri__rh_gth_ha[] = { - "d53219ee10acdd291a1e2b34fa5f543c780a0301357e93cfebd466e556f9824e", - 0 - }; -static u3j_core _140_tri__rh_d[] = - { { "add", 7, _140_tri__rh_add_a, 0, _140_tri__rh_add_ha }, - { "sub", 7, _140_tri__rh_sub_a, 0, _140_tri__rh_sub_ha }, - { "mul", 7, _140_tri__rh_mul_a, 0, _140_tri__rh_mul_ha }, - { "div", 7, _140_tri__rh_div_a, 0, _140_tri__rh_div_ha }, - { "sqt", 7, _140_tri__rh_sqt_a, 0, _140_tri__rh_sqt_ha }, - { "fma", 7, _140_tri__rh_fma_a, 0, _140_tri__rh_fma_ha }, - { "lth", 7, _140_tri__rh_lth_a, 0, _140_tri__rh_lth_ha }, - { "lte", 7, _140_tri__rh_lte_a, 0, _140_tri__rh_lte_ha }, - { "equ", 7, _140_tri__rh_equ_a, 0, _140_tri__rh_equ_ha }, - { "gte", 7, _140_tri__rh_gte_a, 0, _140_tri__rh_gte_ha }, - { "gth", 7, _140_tri__rh_gth_a, 0, _140_tri__rh_gth_ha }, - {} - }; -static c3_c* _140_tri__rh_ha[] = { - "c38f8c0a7e2f1fccb52c459f60a30ec5d21635cafaf1aa120b70c1fa91cf7da5", - 0 -}; - - static u3j_harm _140_tri__og_raw_a[] = {{".2", u3weo_raw}, {}}; - static c3_c* _140_tri__og_raw_ha[] = { - "bbcbefc237dbebf6c141ba14fd9e0464a836127fd123d10da5f121e82d49ebdb", - 0 - }; -static u3j_core _140_tri__og_d[] = - { { "raw", 7, _140_tri__og_raw_a, 0, _140_tri__og_raw_ha }, - {} - }; -static c3_c* _140_tri__og_ha[] = { - "74b9ae67eeabbffcff969ac7fdc7f4f0f4f67af64931e969bcac50d084e15fc0", - 0 -}; - - static u3j_harm _140_tri__sha_sha1_a[] = {{".2", u3we_sha1}, {}}; - static c3_c* _140_tri__sha_sha1_ha[] = { - "75aababa0688619d9df36238269119302a64ad2e3c69c53bd0057fe6b1abaf0c", - 0 - }; -static u3j_core _140_tri__sha_d[] = - { { "sha1", 7, _140_tri__sha_sha1_a, 0, _140_tri__sha_sha1_ha }, - {} - }; -static c3_c* _140_tri__sha_ha[] = { - "3c22d2f8719cb626e8dfe1a4206bcbc14b678c1422c48322054b40f84416d557", - 0 -}; - -static u3j_harm _140_tri_shax_a[] = {{".2", u3we_shax}, {}}; -static c3_c* _140_tri_shax_ha[] = { - "0fc53de3ddc8b8f84a46136f1728fa3ed66a5113888d14907589d16bf5927ad8", - 0 -}; -static u3j_harm _140_tri_shay_a[] = {{".2", u3we_shay}, {}}; -static c3_c* _140_tri_shay_ha[] = { - "b6dbc72e15c2204f83f902619b7a60328f29c9d302ddb35c435111dea28c5470", - 0 -}; -static u3j_harm _140_tri_shas_a[] = {{".2", u3we_shas}, {}}; -static c3_c* _140_tri_shas_ha[] = { - "5230583767b7625b3496248ed03b6b94c1d4ee9b26342f9390bf999ec9b6cfdb", - 0 -}; -static u3j_harm _140_tri_shal_a[] = {{".2", u3we_shal}, {}}; -static c3_c* _140_tri_shal_ha[] = { - "3242912e29e3e1ed8d1a395cc860a82d78961b4278ed79bbdeb37cb5615bbf20", - 0 -}; - -static u3j_harm _140_ob_fein_a[] = {{".2", u3we_fein_ob}, {}}; -static c3_c* _140_ob_fein_ha[] = { - 0 -}; - -static u3j_harm _140_ob_fynd_a[] = {{".2", u3we_fynd_ob}, {}}; -static c3_c* _140_ob_fynd_ha[] = { - 0 -}; - - -static u3j_core _140_ob_d[] = { - { "fein", 7, _140_ob_fein_a, 0, _140_ob_fein_ha }, - { "fynd", 7, _140_ob_fynd_a, 0, _140_ob_fynd_ha }, - {} -}; -static c3_c* _140_ob_ha[] = { - "13ebfbdee69396bc1d980fc4dcbcdaa9cc3fb9c011e6cf188e71311a8bffc8e6", - 0 -}; -static u3j_hood _140_ob_ho[] = { - { "fein", 42 }, - { "fynd", 20 }, - {}, -}; - -static u3j_core _140_tri_d[] = -{ { "qua", 3, 0, _140_qua_d, _140_qua_ha, _140_qua_ho }, - { "cofl", 7, 0, _140_tri__cofl_d, _140_tri__cofl_ha }, - { "rd", 7, 0, _140_tri__rd_d, _140_tri__rd_ha }, - { "rs", 7, 0, _140_tri__rs_d, _140_tri__rs_ha }, - { "rq", 7, 0, _140_tri__rq_d, _140_tri__rq_ha }, - { "rh", 7, 0, _140_tri__rh_d, _140_tri__rh_ha }, - { "og", 7, 0, _140_tri__og_d, _140_tri__og_ha }, - - { "sha", 7, 0, _140_tri__sha_d, _140_tri__sha_ha }, - { "shax", 7, _140_tri_shax_a, 0, _140_tri_shax_ha }, - { "shay", 7, _140_tri_shay_a, 0, _140_tri_shay_ha }, - { "shas", 7, _140_tri_shas_a, 0, _140_tri_shas_ha }, - { "shal", 7, _140_tri_shal_a, 0, _140_tri_shal_ha }, - { "ob", 3, 0, _140_ob_d, _140_ob_ha, _140_ob_ho }, - {} -}; -static c3_c* _140_tri_ha[] = { - "e7339eb317038f64555717c5624e4571fe9654d471c1a78454129afdbcad9b53", - 0 -}; - -static u3j_hood _140_tri_ho[] = { - { "ob", 20 }, - { "yore", 5462 }, - { "year", 44975 }, - {}, -}; - -/* layer two -*/ -static u3j_harm _140_two_find_a[] = {{".2", u3wb_find, c3y}, {}}; -static c3_c* _140_two_find_ha[] = { - "cab18d537962b48d38fa061844f44c4635ee11c74fdf403aa80d3a6d1b15c177", - 0 -}; -static u3j_harm _140_two_flop_a[] = {{".2", u3wb_flop, c3y}, {}}; -static c3_c* _140_two_flop_ha[] = { - "73d496aac2ce6fd9475645c76f949ae0228f8f5ae6738529b08ed9aeb58255fe", - 0 -}; -static u3j_harm _140_two_lent_a[] = {{".2", u3wb_lent, c3y}, {}}; -static c3_c* _140_two_lent_ha[] = { - "1b98ab19350f6a6753ea4bd6daf4509a7c5681b7ac20c83204fe62846d46c2c3", - 0 -}; -static u3j_harm _140_two_levy_a[] = {{".2", u3wb_levy, c3y}, {}}; -static c3_c* _140_two_levy_ha[] = { - "634f1f506b17b4b50e6902f6e21b290ffc5305d1546075cba745c9e195fcc56b", - 0 -}; -static u3j_harm _140_two_lien_a[] = {{".2", u3wb_lien, c3y}, {}}; -static c3_c* _140_two_lien_ha[] = { - "2ffb70864f2be120b48869b27c614aadeed1390bde497d8940fe85b7861093ea", - 0 -}; -static u3j_harm _140_two_murn_a[] = {{".2", u3wb_murn, c3y}, {}}; -static c3_c* _140_two_murn_ha[] = { - "53257aaee131c2a892529c2ee75271160811814086456e8fdf249eebdf31b990", - 0 -}; -static u3j_harm _140_two_need_a[] = {{".2", u3wb_need, c3y}, {}}; -static c3_c* _140_two_need_ha[] = { - "bfdd39af478811efe816e69e8c9202d10c41f646c0d27f39c23e4fe1aec807dd", - 0 -}; -static u3j_harm _140_two_reap_a[] = {{".2", u3wb_reap, c3y}, {}}; -static c3_c* _140_two_reap_ha[] = { - "cf6bd10b97b418b67c645374712c768d9e7e9809c14ecf36a5c507e5fc4b4039", - 0 -}; -static u3j_harm _140_two_reel_a[] = {{".2", u3wb_reel, c3y}, {}}; -static c3_c* _140_two_reel_ha[] = { - "36108d1ba09617cf62e739e0ff2dcf9286f322ca0e8faa3521ef127e9840eebf", - 0 -}; -static u3j_harm _140_two_roll_a[] = {{".2", u3wb_roll, c3y}, {}}; -static c3_c* _140_two_roll_ha[] = { - "42abc6b3defd7c5eb8f6d14d57a14ba2a02d559907c03141c70a65e0803c01e5", - 0 -}; -static u3j_harm _140_two_skid_a[] = {{".2", u3wb_skid, c3y}, {}}; -static c3_c* _140_two_skid_ha[] = { - "832366432a85005f9a9849d6de9a9045c8f9a591050519b06aec6a9a1a54c360", - 0 -}; -static u3j_harm _140_two_skim_a[] = {{".2", u3wb_skim, c3y}, {}}; -static c3_c* _140_two_skim_ha[] = { - "ccbecb459b90d05ed6c1073859a58987bf9a479820b5550fa75f37b95f98a279", - 0 -}; -static u3j_harm _140_two_skip_a[] = {{".2", u3wb_skip, c3y}, {}}; -static c3_c* _140_two_skip_ha[] = { - "873e3e4d6b8f16212911aa982065dd0d36b1f6e8834828d5eb5d59afa9da2384", - 0 -}; -static u3j_harm _140_two_scag_a[] = {{".2", u3wb_scag, c3y}, {}}; -static c3_c* _140_two_scag_ha[] = { - "ddba868a28eb9655c9f6e06cfecb4ec9e9ff78277290579b9bb9b25339bb4ab9", - 0 -}; -static u3j_harm _140_two_slag_a[] = {{".2", u3wb_slag, c3y}, {}}; -static c3_c* _140_two_slag_ha[] = { - "811f7f67de7ab3f33b85198a69b1bf344498cd4922b0273d918a48b803b7877d", - 0 -}; -static u3j_harm _140_two_snag_a[] = {{".2", u3wb_snag, c3y}, {}}; -static c3_c* _140_two_snag_ha[] = { - "12a1d53541d4df9be60bda45f2dae6c6e6381f85edd4de062af23c6654860591", - 0 -}; -static u3j_harm _140_two_sort_a[] = {{".2", u3wb_sort, c3y}, {}}; -static c3_c* _140_two_sort_ha[] = { - "dc14f91fdedacd3b77bdf241d22555fe2bf0a231e9cab58b4ae779791e54c4e7", - 0 -}; -static u3j_harm _140_two_turn_a[] = {{".2", u3wb_turn, c3y}, {}}; -static c3_c* _140_two_turn_ha[] = { - "e13d9f52434ba810e182017f50a73d4d44eaa298a833231e90353f2a32ea6a78", - 0 -}; -static u3j_harm _140_two_weld_a[] = {{".2", u3wb_weld, c3y}, {}}; -static c3_c* _140_two_weld_ha[] = { - "d855628821d57392f575c5da000c7326eaaa19e08cda967a4772859269669df2", - 0 -}; -static u3j_harm _140_two_welp_a[] = {{".2", u3wb_welp, c3y}, {}}; -static c3_c* _140_two_welp_ha[] = { - "0bccae6625e62ce622c62f9e828a2a6469e2fbf42342d95e23c3b926f340140d", - 0 -}; -static u3j_harm _140_two_zing_a[] = {{".2", u3wb_zing, c3y}, {}}; -static c3_c* _140_two_zing_ha[] = { - "113bdea043e9e05cf4a63dac793caf34634bc58414d00250af87139405521b9d", - 0 -}; - -static u3j_harm _140_two_bex_a[] = {{".2", u3wc_bex, c3y}, {}}; -static c3_c* _140_two_bex_ha[] = { - "ee7a095ea21b6438ec19ab235e73877b96108f0a14cae02cecbd8a48c44e70e3", - 0 -}; -static u3j_harm _140_two_can_a[] = {{".2", u3wc_can, c3y}, {}}; -static c3_c* _140_two_can_ha[] = { - "c49ee52487369ba17a0105a61aa658df60e7a537e3e8737ab582644fe00b3938", - 0 -}; -static u3j_harm _140_two_cat_a[] = {{".2", u3wc_cat, c3y}, {}}; -static c3_c* _140_two_cat_ha[] = { - "467f007931110ac0755dcd44c5aaee65785a63b9042b8eea6a7838fa86cc5d8f", - 0 -}; -static u3j_harm _140_two_con_a[] = {{".2", u3wc_con, c3y}, {}}; -static c3_c* _140_two_con_ha[] = { - "d20f091bd4f28d37c1a78373df939f3d3a41e025129e9a2bb5e2b9a710358965", - 0 -}; -static u3j_harm _140_two_cut_a[] = {{".2", u3wc_cut, c3y}, {}}; -static c3_c* _140_two_cut_ha[] = { - "96bb4e9a259d6a1ede5461956b6a6fb73f05cb8e745c4803c2bae4ec0b7f0800", - 0 -}; -static u3j_harm _140_two_dis_a[] = {{".2", u3wc_dis, c3y}, {}}; -static c3_c* _140_two_dis_ha[] = { - "4b3987314451e20a45d2c7baff51d5d39be57e5970f23f86df4dd6569826ddff", - 0 -}; -static u3j_harm _140_two_dor_a[] = {{".2", u3wc_dor, c3y}, {}}; -static c3_c* _140_two_dor_ha[] = { - "277927a2e49e4d942e81ffc7740a71e68a7b732df886a9f84dc7d914be911879", - 0 -}; -static u3j_harm _140_two_end_a[] = {{".2", u3wc_end, c3y}, {}}; -static c3_c* _140_two_end_ha[] = { - "403c9f12f2481966ffb07842006713149960c67c6bcad8edd78cdf837bc0d854", - 0 -}; -static u3j_harm _140_two_gor_a[] = {{".2", u3wc_gor, c3y}, {}}; -static c3_c* _140_two_gor_ha[] = { - "8a1e3ed1de749ff2ff61d489466df618e4e0773498cb9693ec2e612e9733385c", - 0 -}; -static u3j_harm _140_two_lsh_a[] = {{".2", u3wc_lsh, c3y}, {}}; -static c3_c* _140_two_lsh_ha[] = { - "3db89b02bc596a57c7fb72a991c9fbf3197de501c56b3d1df26911b664c45f3d", - 0 -}; -static u3j_harm _140_two_met_a[] = {{".2", u3wc_met, c3y}, {}}; -static c3_c* _140_two_met_ha[] = { - "39dc9b1d10d9e93414b43f315f9a375596c99b4e8172d71d26759996bb7bab08", - 0 -}; -static u3j_harm _140_two_mix_a[] = {{".2", u3wc_mix, c3y}, {}}; -static c3_c* _140_two_mix_ha[] = { - "c84b3e487850d73dd5e4af18fb54b623028be3c45ae9b712718754233057fbc3", - 0 -}; -static u3j_harm _140_two_mor_a[] = {{".2", u3wc_mor, c3y}, {}}; -static c3_c* _140_two_mor_ha[] = { - "7c2d86e952606e571e5bcd988e70ded072c0eaa45d1fd958849d76360a763ddf", - 0 -}; -static u3j_harm _140_two_mug_a[] = {{".2", u3wc_mug, c3y}, {}}; -static c3_c* _140_two_mug_ha[] = { - "6da3f3aa1e951ef2d00e5131945d140fb52728558867237891e029160b7f5010", - 0 -}; -static u3j_harm _140_two_muk_a[] = {{".2", u3wc_muk, c3y}, {}}; -static c3_c* _140_two_muk_ha[] = { - "5a04a09bf7d22c8ef048ba2cc86be8f3a02066eab84cf4a45bbdf2bf534ff9f6", - 0 -}; -static u3j_harm _140_two_pow_a[] = {{".2", u3wc_pow, c3y}, {}}; -static c3_c* _140_two_pow_ha[] = { - "6cfcb9da6ad812eb72788e22e1370b4ab1b6ab64ab0628dfdff78ccead325406", - 0 -}; -static u3j_harm _140_two_rap_a[] = {{".2", u3wc_rap, c3y}, {}}; -static c3_c* _140_two_rap_ha[] = { - "f694f96bcbf97b339285d6c73ed5d33d112b911f7a991acefdef223ff01d8834", - 0 -}; -static u3j_harm _140_two_rep_a[] = {{".2", u3wc_rep, c3y}, {}}; -static c3_c* _140_two_rep_ha[] = { - "25aa2f1746e1cf2235117f22a3db152fa86e003d9bf9f9cfcda79e76e51f382f", - 0 -}; -static u3j_harm _140_two_rev_a[] = {{".2", u3wc_rev, c3y}, {}}; -static c3_c* _140_two_rev_ha[] = { - "15e20592ac1d9c0c80d99589e67cadb4ed7566be1d21844bbe7ef936e0db4524", - 0 -}; -static u3j_harm _140_two_rip_a[] = {{".2", u3wc_rip, c3y}, {}}; -static c3_c* _140_two_rip_ha[] = { - "16026c27499953978f69dbf81c1530b2dec8d5a2403c5561f7a5afcc180e129e", - 0 -}; -static u3j_harm _140_two_rsh_a[] = {{".2", u3wc_rsh, c3y}, {}}; -static c3_c* _140_two_rsh_ha[] = { - "55bd777f239a2a7c849e0c7a35bb967b79279c79bbd985f31ba272761f97928f", - 0 -}; -static u3j_harm _140_two_swp_a[] = {{".2", u3wc_swp, c3y}, {}}; -static c3_c* _140_two_swp_ha[] = { - "2c4583c36d73c9c2857052b893b87e1170a794e0edbbdba9d767ba7639e7c1ec", - 0 -}; -static u3j_harm _140_two_sqt_a[] = {{".2", u3wc_sqt, c3y}, {}}; -static c3_c* _140_two_sqt_ha[] = { - "fc28ff327ae69f55ccf257b69a1477b845552ef9e615e85718902c249bdeca6f", - 0 -}; -static u3j_harm _140_two_xeb_a[] = {{".2", u3wc_xeb, c3y}, {}}; -static c3_c* _140_two_xeb_ha[] = { - "41403aafe1e2ccb1a02edde96fe742085feffe028d02529eb2b13f925884a499", - 0 -}; - - static u3j_harm _140_two__in_apt_a[] = {{".2", u3wdi_apt}, {}}; - static c3_c* _140_two__in_apt_ha[] = { - "a40812fa255f13afdaf196bff38d2d9bfcb38f09c48ace9139a2701a555a0c9a", - 0 - }; - static u3j_harm _140_two__in_bif_a[] = {{".2", u3wdi_bif}, {}}; - static c3_c* _140_two__in_bif_ha[] = { - "edd0d727b9099e75c3e5b73b3025ad9737136eacedc2f8088b6edb02dbe06cb3", - 0 - }; - static u3j_harm _140_two__in_del_a[] = {{".2", u3wdi_del}, {}}; - static c3_c* _140_two__in_del_ha[] = { - "33a21e7aaf71105e2d48e1af61ff463fb8a0b7e04f8a8c30a6f6a2d1f967795f", - 0 - }; - static u3j_harm _140_two__in_dif_a[] = {{".2", u3wdi_dif}, {}}; - static c3_c* _140_two__in_dif_ha[] = { - "a488f0be5adbb1c04e2038a2315ac065591e7daadcafc1d47aea272979680468", - 0 - }; - static u3j_harm _140_two__in_gas_a[] = {{".2", u3wdi_gas}, {}}; - static c3_c* _140_two__in_gas_ha[] = { - "223a60a43a10f1f90a3b205ecfce8e17af1adfcf9dbf3cff9b8b1362656b1af1", - 0 - }; - static u3j_harm _140_two__in_has_a[] = {{".2", u3wdi_has}, {}}; - static c3_c* _140_two__in_has_ha[] = { - "a65e666e92176401040a883801e4f05bd650fe6c094a6c8d7f4afcaee9cf55ad", - 0 - }; - - static u3j_harm _140_two__in_int_a[] = {{".2", u3wdi_int}, {}}; - static c3_c* _140_two__in_int_ha[] = { - "a71b0e355fa02d18447c02922f69096f42043da451e8c79e7a9270460c3a44e6", - 0 - }; - - static u3j_harm _140_two__in_put_a[] = {{".2", u3wdi_put}, {}}; - static c3_c* _140_two__in_put_ha[] = { - "19b27267e18ef156d85d84d37e02692a17fec0b7a2a0fe4120a3ae02b841c8f4", - 0 - }; - static u3j_harm _140_two__in_rep_a[] = {{".2", u3wdi_rep}, {}}; - static c3_c* _140_two__in_rep_ha[] = { - "05bfb84a52ed8ccc330a96faca29a49afd28300960ac089d00dba32212b971a7", - 0 - }; - static u3j_harm _140_two__in_run_a[] = {{".2", u3wdi_run}, {}}; - static c3_c* _140_two__in_run_ha[] = { - "7f2061dbee19fa20925bd5a80cc41ed71e462e0f49ee6e845fd750c219734864", - 0 - }; - static u3j_harm _140_two__in_tap_a[] = {{".2", u3wdi_tap}, {}}; - static c3_c* _140_two__in_tap_ha[] = { - "7dde59e2bd7684e785ce9787bc394571bd1216d7a62398c703447fc951c6b352", - 0 - }; - static u3j_harm _140_two__in_wyt_a[] = {{".2", u3wdi_wyt}, {}}; - static c3_c* _140_two__in_wyt_ha[] = { - "fac9248ebd1defade9df695cd81f94355bebb271f85b164ff34658a5f45c71a0", - 0 - }; - static u3j_harm _140_two__in_uni_a[] = {{".2", u3wdi_uni}, {}}; - static c3_c* _140_two__in_uni_ha[] = { - "6bd72ef1fb12482a839f4435a2b163ace1b56036297a3cec6968be33d6863096", - 0 - }; - -static u3j_core _140_two__in_d[] = - { { "apt", 7, _140_two__in_apt_a, 0, _140_two__in_apt_ha }, - { "bif", 7, _140_two__in_bif_a, 0, _140_two__in_bif_ha }, - { "del", 7, _140_two__in_del_a, 0, _140_two__in_del_ha }, - { "dif", 7, _140_two__in_dif_a, 0, _140_two__in_dif_ha }, - { "gas", 7, _140_two__in_gas_a, 0, _140_two__in_gas_ha }, - { "has", 7, _140_two__in_has_a, 0, _140_two__in_has_ha }, - { "int", 7, _140_two__in_int_a, 0, _140_two__in_int_ha }, - { "put", 7, _140_two__in_put_a, 0, _140_two__in_put_ha }, - { "rep", 7, _140_two__in_rep_a, 0, _140_two__in_rep_ha }, - { "run", 7, _140_two__in_run_a, 0, _140_two__in_run_ha }, - { "tap", 7, _140_two__in_tap_a, 0, _140_two__in_tap_ha }, - { "uni", 7, _140_two__in_uni_a, 0, _140_two__in_uni_ha }, - { "wyt", 3, _140_two__in_wyt_a, 0, _140_two__in_wyt_ha }, - {} - }; -static c3_c* _140_two__in_ha[] = { - "8bbb90ce0a49d627194aa267f6cf1fd78df677111b553ce03119fea19f9d763c", - 0 -}; - static u3j_harm _140_two__by_all_a[] = {{".2", u3wdb_all, c3y}, {}}; - static c3_c* _140_two__by_all_ha[] = { - "c2e87d0047c14b4488d03aad98fa43080c736d86d2ff723a037aaf1843aa9285", - 0 - }; - static u3j_harm _140_two__by_any_a[] = {{".2", u3wdb_any, c3y}, {}}; - static c3_c* _140_two__by_any_ha[] = { - "96b95c942dcbc97f5291fa6f7342c3e19a87d69cc254965b0f75d95133a19301", - 0 - }; - static u3j_harm _140_two__by_apt_a[] = {{".2", u3wdb_apt, c3y}, {}}; - static c3_c* _140_two__by_apt_ha[] = { - "1f0a6f8b945b243520b77069060589938d9e651e34b24924db9528d02a98014f", - 0 - }; - static u3j_harm _140_two__by_bif_a[] = {{".2", u3wdb_bif, c3y}, {}}; - static c3_c* _140_two__by_bif_ha[] = { - "d377a032a3866e76f6f5217c7c0ed0519b768d8b1c5107e35f7dbf18d8f60880", - 0 - }; - static u3j_harm _140_two__by_del_a[] = {{".2", u3wdb_del, c3y}, {}}; - static c3_c* _140_two__by_del_ha[] = { - "09f78d6235d3fce8303c7bc663988349b7d4592abdacfb09b833d2f43629b6b6", - 0 - }; - static u3j_harm _140_two__by_dif_a[] = {{".2", u3wdb_dif, c3y}, {}}; - static c3_c* _140_two__by_dif_ha[] = { - "0334e6df6fd0bd5013b94a1b22c29e4c436da0a2d5573f1992faad1c8a059cc7", - 0 - }; - static u3j_harm _140_two__by_gas_a[] = {{".2", u3wdb_gas, c3y}, {}}; - static c3_c* _140_two__by_gas_ha[] = { - "43046602e0b9e568b09448cfe18527e2331f3393a2f32e485d9707a14c346698", - 0 - }; - static u3j_harm _140_two__by_get_a[] = {{".2", u3wdb_get, c3y}, {}}; - static c3_c* _140_two__by_get_ha[] = { - "4de4cea8fa98ef48e9faae10c90ba5bd77971670030ffb00483d0608af4c466f", - 0 - }; - static u3j_harm _140_two__by_has_a[] = {{".2", u3wdb_has, c3y}, {}}; - static c3_c* _140_two__by_has_ha[] = { - "04ecc67ab25961bee1b7c9dbcf42965d16f32474b9bbdd2b286983f998e3957a", - 0 - }; - - static u3j_harm _140_two__by_int_a[] = {{".2", u3wdb_int, c3y}, {}}; - static c3_c* _140_two__by_int_ha[] = { - "a2345429482c271a1668f3c0675a559452bb7b13cb7393c3acb7de44c603aef9", - 0 - }; - - static u3j_harm _140_two__by_jab_a[] = {{".2", u3wdb_jab, c3y}, {}}; - static c3_c* _140_two__by_jab_ha[] = { - "48930133d9b26e912dce54d1bc486cfe9dcb32bb3c2b1ad76143382799aec156", - 0 - }; - static u3j_harm _140_two__by_key_a[] = {{".2", u3wdb_key, c3y}, {}}; - static c3_c* _140_two__by_key_ha[] = { - "0096c77b93e9fe36b98d9f433eb73300f024283b93b3d73a4001afb9f9804d1b", - 0 - }; - static u3j_harm _140_two__by_put_a[] = {{".2", u3wdb_put, c3y}, {}}; - static c3_c* _140_two__by_put_ha[] = { - "b7307589fed604bfb92e8ad5ffad611c82d835baf02a86c6911b279930f4e8d7", - 0 - }; - static u3j_harm _140_two__by_rep_a[] = {{".2", u3wdb_rep, c3y}, {}}; - static c3_c* _140_two__by_rep_ha[] = { - "05bfb84a52ed8ccc330a96faca29a49afd28300960ac089d00dba32212b971a7", - 0 - }; - static u3j_harm _140_two__by_run_a[] = {{".2", u3wdb_run, c3y}, {}}; - static c3_c* _140_two__by_run_ha[] = { - "adea01e9036e0b40e4969814d4eed935d7d69a52e4a55de5520df2fa5204d8e7", - 0 - }; - static u3j_harm _140_two__by_tap_a[] = {{".2", u3wdb_tap, c3y}, {}}; - static c3_c* _140_two__by_tap_ha[] = { - "7dde59e2bd7684e785ce9787bc394571bd1216d7a62398c703447fc951c6b352", - 0 - }; - static u3j_harm _140_two__by_uni_a[] = {{".2", u3wdb_uni, c3y}, {}}; - static c3_c* _140_two__by_uni_ha[] = { - "f18bc4dac19abe14a6f56afc15d838b7394d48969156f4b37c3c84edd5d46752", - 0 - }; - static u3j_harm _140_two__by_urn_a[] = {{".2", u3wdb_urn, c3y}, {}}; - static c3_c* _140_two__by_urn_ha[] = { - "a409cf78e7f1c2ce8440115730f74367839b658cde2d6a1daa8af067b790eb83", - 0 - }; - static u3j_harm _140_two__by_wyt_a[] = {{".2", u3wdb_wyt, c3y}, {}}; - static c3_c* _140_two__by_wyt_ha[] = { - "fac9248ebd1defade9df695cd81f94355bebb271f85b164ff34658a5f45c71a0", - 0 - }; - -static u3j_core _140_two__by_d[] = - { { "all", 7, _140_two__by_all_a, 0, _140_two__by_all_ha }, - { "any", 7, _140_two__by_any_a, 0, _140_two__by_any_ha }, - { "apt", 7, _140_two__by_apt_a, 0, _140_two__by_apt_ha }, - { "bif", 7, _140_two__by_bif_a, 0, _140_two__by_bif_ha }, - { "del", 7, _140_two__by_del_a, 0, _140_two__by_del_ha }, - { "dif", 7, _140_two__by_dif_a, 0, _140_two__by_dif_ha }, - { "gas", 7, _140_two__by_gas_a, 0, _140_two__by_gas_ha }, - { "get", 7, _140_two__by_get_a, 0, _140_two__by_get_ha }, - { "has", 7, _140_two__by_has_a, 0, _140_two__by_has_ha }, - { "int", 7, _140_two__by_int_a, 0, _140_two__by_int_ha }, - { "jab", 7, _140_two__by_jab_a, 0, _140_two__by_jab_ha }, - { "key", 7, _140_two__by_key_a, 0, _140_two__by_key_ha }, - { "put", 7, _140_two__by_put_a, 0, _140_two__by_put_ha }, - { "rep", 7, _140_two__by_rep_a, 0, _140_two__by_rep_ha }, - { "run", 7, _140_two__by_run_a, 0, _140_two__by_run_ha }, - { "tap", 7, _140_two__by_tap_a, 0, _140_two__by_tap_ha }, - { "uni", 7, _140_two__by_uni_a, 0, _140_two__by_uni_ha }, - { "urn", 7, _140_two__by_urn_a, 0, _140_two__by_urn_ha }, - { "wyt", 3, _140_two__by_wyt_a, 0, _140_two__by_wyt_ha }, - {} - }; -static c3_c* _140_two__by_ha[] = { - "9c70e973de46335405a7ff932d4742743f54db579f2584758ef2b02afd4fbfe8", - 0 -}; - -static u3j_harm _140_two_cue_a[] = {{".2", u3we_cue}, {}}; -static c3_c* _140_two_cue_ha[] = { - "a52b584c5a92fc653e47f50c3389caf3427e13d20ddb8bd701a2d7bca12cb742", - 0 -}; -static u3j_harm _140_two_jam_a[] = {{".2", u3we_jam}, {}}; -static c3_c* _140_two_jam_ha[] = { - "61f86be74cb1fd5a1d7f531cc9588f8f34a972be8de487c93d25c8e026592ed2", - 0 -}; -static u3j_harm _140_two_mat_a[] = {{".2", u3we_mat}, {}}; -static c3_c* _140_two_mat_ha[] = { - "b5cd9fd1eded54fcb9bfd06af3c34460c1aa4cfc46f1ee9bd3f6476aa8fbb8c8", - 0 -}; -static u3j_harm _140_two_rub_a[] = {{".2", u3we_rub}, {}}; -static c3_c* _140_two_rub_ha[] = { - "87fcf40fb6fce8c3cb778373670d0682785ae650f785531db8ff69d431bc14c6", - 0 -}; - -static u3j_core _140_two_d[] = -{ { "tri", 3, 0, _140_tri_d, _140_tri_ha, _140_tri_ho }, - - { "find", 7, _140_two_find_a, 0, _140_two_find_ha }, - { "flop", 7, _140_two_flop_a, 0, _140_two_flop_ha }, - { "lent", 7, _140_two_lent_a, 0, _140_two_lent_ha }, - { "levy", 7, _140_two_levy_a, 0, _140_two_levy_ha }, - { "lien", 7, _140_two_lien_a, 0, _140_two_lien_ha }, - { "murn", 7, _140_two_murn_a, 0, _140_two_murn_ha }, - { "need", 7, _140_two_need_a, 0, _140_two_need_ha }, - { "reap", 7, _140_two_reap_a, 0, _140_two_reap_ha }, - { "reel", 7, _140_two_reel_a, 0, _140_two_reel_ha }, - { "roll", 7, _140_two_roll_a, 0, _140_two_roll_ha }, - { "skid", 7, _140_two_skid_a, 0, _140_two_skid_ha }, - { "skim", 7, _140_two_skim_a, 0, _140_two_skim_ha }, - { "skip", 7, _140_two_skip_a, 0, _140_two_skip_ha }, - { "scag", 7, _140_two_scag_a, 0, _140_two_scag_ha }, - { "slag", 7, _140_two_slag_a, 0, _140_two_slag_ha }, - { "snag", 7, _140_two_snag_a, 0, _140_two_snag_ha }, - { "sort", 7, _140_two_sort_a, 0, _140_two_sort_ha }, - { "turn", 7, _140_two_turn_a, 0, _140_two_turn_ha }, - { "weld", 7, _140_two_weld_a, 0, _140_two_weld_ha }, - { "welp", 7, _140_two_welp_a, 0, _140_two_welp_ha }, - { "zing", 7, _140_two_zing_a, 0, _140_two_zing_ha }, - - { "bex", 7, _140_two_bex_a, 0, _140_two_bex_ha }, - { "cat", 7, _140_two_cat_a, 0, _140_two_cat_ha }, - { "can", 7, _140_two_can_a, 0, _140_two_can_ha }, - { "con", 7, _140_two_con_a, 0, _140_two_con_ha }, - { "cue", 7, _140_two_cue_a, 0, _140_two_cue_ha }, - { "cut", 7, _140_two_cut_a, 0, _140_two_cut_ha }, - { "dis", 7, _140_two_dis_a, 0, _140_two_dis_ha }, - { "dor", 7, _140_two_dor_a, 0, _140_two_dor_ha }, - { "end", 7, _140_two_end_a, 0, _140_two_end_ha }, - { "gor", 7, _140_two_gor_a, 0, _140_two_gor_ha }, - { "jam", 7, _140_two_jam_a, 0, _140_two_jam_ha }, - { "lsh", 7, _140_two_lsh_a, 0, _140_two_lsh_ha }, - { "mat", 7, _140_two_mat_a, 0, _140_two_mat_ha }, - { "met", 7, _140_two_met_a, 0, _140_two_met_ha }, - { "mix", 7, _140_two_mix_a, 0, _140_two_mix_ha }, - { "mor", 7, _140_two_mor_a, 0, _140_two_mor_ha }, - { "mug", 7, _140_two_mug_a, 0, _140_two_mug_ha }, - { "muk", 59, _140_two_muk_a, 0, _140_two_muk_ha }, - { "rap", 7, _140_two_rap_a, 0, _140_two_rap_ha }, - { "rep", 7, _140_two_rep_a, 0, _140_two_rep_ha }, - { "rev", 7, _140_two_rev_a, 0, _140_two_rev_ha }, - { "rip", 7, _140_two_rip_a, 0, _140_two_rip_ha }, - { "rsh", 7, _140_two_rsh_a, 0, _140_two_rsh_ha }, - { "swp", 7, _140_two_swp_a, 0, _140_two_swp_ha }, - { "rub", 7, _140_two_rub_a, 0, _140_two_rub_ha }, - { "pow", 7, _140_two_pow_a, 0, _140_two_pow_ha }, - { "sqt", 7, _140_two_sqt_a, 0, _140_two_sqt_ha }, - { "xeb", 7, _140_two_xeb_a, 0, _140_two_xeb_ha }, - - { "by", 7, 0, _140_two__by_d, _140_two__by_ha }, - { "in", 7, 0, _140_two__in_d, _140_two__in_ha }, - {} -}; -static c3_c* _140_two_ha[] = { - "f693e1f5ff57ec741fe28a48a18252b3e12dead2bfe3bcd4ea8e904a36905c0b", - 0 -}; - -/* layer one -*/ -static u3j_harm _140_one_add_a[] = {{".2", u3wa_add, c3y}, {}}; -static c3_c* _140_one_add_ha[] = { - "46407e27fe5d7c20b3ba25c02657c227b37217ddab8501b2d3b70b818aca7a44", - 0 -}; -static u3j_harm _140_one_dec_a[] = {{".2", u3wa_dec, c3y}, {}}; -static c3_c* _140_one_dec_ha[] = { - "6345d28d34c62c4b4f9da98828574bc9060ff0869789968d9045d90faeb3580c", - 0 -}; -static u3j_harm _140_one_div_a[] = {{".2", u3wa_div, c3y}, {}}; -static c3_c* _140_one_div_ha[] = { - "e3292e76feb274b9314e7693827de11e96677629c556b3a6c72cc15ebad45113", - 0 -}; -static u3j_harm _140_one_dvr_a[] = {{".2", u3wc_dvr, c3y}, {}}; -static c3_c* _140_one_dvr_ha[] = { - "fc259f46d770f82767163544f3662dfd45b1484a7bcffad396c7420651f092a4", - 0 -}; -static u3j_harm _140_one_gte_a[] = {{".2", u3wa_gte, c3y}, {}}; -static c3_c* _140_one_gte_ha[] = { - "f3ff2c0fc1f386226183e8834cff87420a1206583f8710e1e75f0e34ed8df5fe", - 0 -}; -static u3j_harm _140_one_gth_a[] = {{".2", u3wa_gth, c3y}, {}}; -static c3_c* _140_one_gth_ha[] = { - "62692d64c8166c7d48bb2a00713064846da9629a1dd2d924c3b15cfd18a5912a", - 0 -}; -static u3j_harm _140_one_lte_a[] = {{".2", u3wa_lte, c3y}, {}}; -static c3_c* _140_one_lte_ha[] = { - "6ca61752aa27b453f28f20e12f652610d45695c3bd965190d5b4fa8b9daa518c", - 0 -}; -static u3j_harm _140_one_lth_a[] = {{".2", u3wa_lth, c3y}, {}}; -static c3_c* _140_one_lth_ha[] = { - "39260325faffbbf5bd88c4abb3efb09c5a7e1deb81a2126498d6c0f49474955e", - 0 -}; -static u3j_harm _140_one_mod_a[] = {{".2", u3wa_mod, c3y}, {}}; -static c3_c* _140_one_mod_ha[] = { - "374d2f3cd0ece33f680bd7103b99891d7dae03590f9eb9faac03a4a501f17038", - 0 -}; -static u3j_harm _140_one_mul_a[] = {{".2", u3wa_mul, c3y}, {}}; -static c3_c* _140_one_mul_ha[] = { - "51e45dbea29cf65a5c26ead095a20eb12ba078840652c88b9c1997820e670bc6", - 0 -}; -static u3j_harm _140_one_sub_a[] = {{".2", u3wa_sub, c3y}, {}}; -static c3_c* _140_one_sub_ha[] = { - "016695719ffe93c177e8a03afa5d29fc428ff596bb8962ace50f7706cd6e53a6", - 0 -}; - -static u3j_harm _140_one_cap_a[] = {{".2", u3wc_cap, c3y}, {}}; -static c3_c* _140_one_cap_ha[] = { - "407e764ee978c712b81c9c3452932e0f7d33faeda36dfe99aaf81d543db16254", - 0 -}; -static u3j_harm _140_one_peg_a[] = {{".2", u3wc_peg, c3y}, {}}; -static c3_c* _140_one_peg_ha[] = { - "8b608d2d2e2eccec3e2fc8cd2d92fd69504c72b26581bb9cbfa4ff51f997251f", - 0 -}; -static u3j_harm _140_one_mas_a[] = {{".2", u3wc_mas, c3y}, {}}; -static c3_c* _140_one_mas_ha[] = { - "1439dcd809f0819b09fb5fe7e83bc1292ca6fd33b5819d78e706d402c053b02a", - 0 -}; - -static u3j_core _140_one_d[] = -{ { "two", 3, 0, _140_two_d, _140_two_ha }, - - { "add", 7, _140_one_add_a, 0, _140_one_add_ha }, - { "dec", 7, _140_one_dec_a, 0, _140_one_dec_ha }, - { "div", 7, _140_one_div_a, 0, _140_one_div_ha }, - { "dvr", 7, _140_one_dvr_a, 0, _140_one_dvr_ha }, - { "gte", 7, _140_one_gte_a, 0, _140_one_gte_ha }, - { "gth", 7, _140_one_gth_a, 0, _140_one_gth_ha }, - { "lte", 7, _140_one_lte_a, 0, _140_one_lte_ha }, - { "lth", 7, _140_one_lth_a, 0, _140_one_lth_ha }, - { "mod", 7, _140_one_mod_a, 0, _140_one_mod_ha }, - { "mul", 7, _140_one_mul_a, 0, _140_one_mul_ha }, - { "sub", 7, _140_one_sub_a, 0, _140_one_sub_ha }, - - { "cap", 7, _140_one_cap_a, 0, _140_one_cap_ha }, - { "mas", 7, _140_one_mas_a, 0, _140_one_mas_ha }, - { "peg", 7, _140_one_peg_a, 0, _140_one_peg_ha }, - {} -}; -static c3_c* _140_one_ha[] = { - "2501f8dbe62384d144ab0f805501ed66325bd77a733eca0c80d1da673e4b16fb", - 0 -}; - -u3j_core _k140_d[] = -{ { "one", 3, 0, _140_one_d, _140_one_ha }, - {} -}; -static c3_c* _k140_ha[] = { - "9b82a903093c077afb3f0b9d4e95e1a9c9789d1ca605b57bbacf79857e3d5c52", - 0 -}; - - -// TODO: probably need different ha hashes - -static u3j_core _a50_two__by_d[] = - { { "apt", 7, _140_two__by_apt_a, 0, _140_two__by_apt_ha }, - { "del", 7, _140_two__by_del_a, 0, _140_two__by_del_ha }, - { "get", 7, _140_two__by_get_a, 0, _140_two__by_get_ha }, - { "has", 7, _140_two__by_has_a, 0, _140_two__by_has_ha }, - { "put", 7, _140_two__by_put_a, 0, _140_two__by_put_ha }, - {} - }; - -static u3j_core _a50_two__in_d[] = - { { "apt", 7, _140_two__in_apt_a, 0, _140_two__in_apt_ha }, - { "del", 7, _140_two__in_del_a, 0, _140_two__in_del_ha }, - { "put", 7, _140_two__in_put_a, 0, _140_two__in_put_ha }, - {} - }; - -u3j_core _a50_d[] = -{ { "add", 7, _140_one_add_a, 0, _140_one_add_ha }, - { "dec", 7, _140_one_dec_a, 0, _140_one_dec_ha }, - { "div", 7, _140_one_div_a, 0, _140_one_div_ha }, - { "dvr", 7, _140_one_dvr_a, 0, _140_one_dvr_ha }, - { "gte", 7, _140_one_gte_a, 0, _140_one_gte_ha }, - { "gth", 7, _140_one_gth_a, 0, _140_one_gth_ha }, - { "lte", 7, _140_one_lte_a, 0, _140_one_lte_ha }, - { "lth", 7, _140_one_lth_a, 0, _140_one_lth_ha }, - { "mod", 7, _140_one_mod_a, 0, _140_one_mod_ha }, - { "mul", 7, _140_one_mul_a, 0, _140_one_mul_ha }, - { "sub", 7, _140_one_sub_a, 0, _140_one_sub_ha }, - - { "bex", 7, _140_two_bex_a, 0, _140_two_bex_ha }, - { "cat", 7, _140_two_cat_a, 0, _140_two_cat_ha }, - { "can", 7, _140_two_can_a, 0, _140_two_can_ha }, - { "con", 7, _140_two_con_a, 0, _140_two_con_ha }, - { "cut", 7, _140_two_cut_a, 0, _140_two_cut_ha }, - { "dis", 7, _140_two_dis_a, 0, _140_two_dis_ha }, - { "dor", 7, _140_two_dor_a, 0, _140_two_dor_ha }, - { "end", 7, _140_two_end_a, 0, _140_two_end_ha }, - { "gor", 7, _140_two_gor_a, 0, _140_two_gor_ha }, - { "lsh", 7, _140_two_lsh_a, 0, _140_two_lsh_ha }, - { "met", 7, _140_two_met_a, 0, _140_two_met_ha }, - { "mix", 7, _140_two_mix_a, 0, _140_two_mix_ha }, - { "mor", 7, _140_two_mor_a, 0, _140_two_mor_ha }, - { "mug", 7, _140_two_mug_a, 0, _140_two_mug_ha }, - { "muk", 59, _140_two_muk_a, 0, _140_two_muk_ha }, // TODO: why 59? - { "rep", 7, _140_two_rep_a, 0, _140_two_rep_ha }, - { "rip", 7, _140_two_rip_a, 0, _140_two_rip_ha }, - { "rsh", 7, _140_two_rsh_a, 0, _140_two_rsh_ha }, - { "swp", 7, _140_two_swp_a, 0, _140_two_swp_ha }, - - { "flop", 7, _140_two_flop_a, 0, _140_two_flop_ha }, - { "lent", 7, _140_two_lent_a, 0, _140_two_lent_ha }, - { "levy", 7, _140_two_levy_a, 0, _140_two_levy_ha }, - { "reap", 7, _140_two_reap_a, 0, _140_two_reap_ha }, - { "slag", 7, _140_two_slag_a, 0, _140_two_slag_ha }, - { "snag", 7, _140_two_snag_a, 0, _140_two_snag_ha }, - { "turn", 7, _140_two_turn_a, 0, _140_two_turn_ha }, - { "welp", 7, _140_two_welp_a, 0, _140_two_welp_ha }, - - { "by", 7, 0, _a50_two__by_d, _140_two__by_ha }, - { "in", 7, 0, _a50_two__in_d, _140_two__in_ha }, - {} -}; - -static u3j_core _d[] = { - { "k140", 0, 0, _k140_d, _k140_ha, 0, (u3j_core*) 140, 0 }, - { "a50", 0, 0, _a50_d, _k140_ha, 0, (u3j_core*) c3__a50, 0 }, - {} -}; - -u3j_dash -u3j_Dash = { - _d, - 0, - 0 -}; diff --git a/pkg/urbit/noun/allocate.c b/pkg/urbit/noun/allocate.c deleted file mode 100644 index 3eb32dac8..000000000 --- a/pkg/urbit/noun/allocate.c +++ /dev/null @@ -1,2621 +0,0 @@ -/* g/a.c -** -*/ -#include "all.h" - -// declarations of inline functions -// -void -u3a_drop(const u3a_pile* pil_u); -void* -u3a_peek(const u3a_pile* pil_u); -void* -u3a_pop(const u3a_pile* pil_u); -void* -u3a_push(const u3a_pile* pil_u); -c3_o -u3a_pile_done(const u3a_pile* pil_u); - -/* _box_count(): adjust memory count. -*/ -#ifdef U3_CPU_DEBUG -static void -_box_count(c3_ws siz_ws) -{ - u3R->all.fre_w += siz_ws; - - { - c3_w end_w = u3a_heap(u3R); - c3_w all_w = (end_w - u3R->all.fre_w); - - if ( all_w > u3R->all.max_w ) { - u3R->all.max_w = all_w; - } - } -} -#else -static void -_box_count(c3_ws siz_ws) { } -#endif - -/* _box_slot(): select the right free list to search for a block. -*/ -static c3_w -_box_slot(c3_w siz_w) -{ - if ( siz_w < u3a_minimum ) { - return 0; - } - else { - c3_w i_w = 1; - - while ( 1 ) { - if ( i_w == u3a_fbox_no ) { - return (i_w - 1); - } - if ( siz_w < 16 ) { - return i_w; - } - siz_w = (siz_w + 1) >> 1; - i_w += 1; - } - } -} - -/* _box_make(): construct a box. -*/ -static u3a_box* -_box_make(void* box_v, c3_w siz_w, c3_w use_w) -{ - u3a_box* box_u = box_v; - c3_w* box_w = box_v; - - c3_assert(siz_w >= u3a_minimum); - - box_w[0] = siz_w; - box_w[siz_w - 1] = siz_w; - box_u->use_w = use_w; - -# ifdef U3_MEMORY_DEBUG - box_u->cod_w = u3_Code; - box_u->eus_w = 0; -# endif - - return box_u; -} - -/* _box_attach(): attach a box to the free list. -*/ -static void -_box_attach(u3a_box* box_u) -{ - c3_assert(box_u->siz_w >= (1 + c3_wiseof(u3a_fbox))); - c3_assert(0 != u3of(u3a_fbox, box_u)); - -#if 0 - // For debugging, fill the box with beef. - { - c3_w* box_w = (void *)box_u; - c3_w i_w; - - for ( i_w = c3_wiseof(u3a_box); (i_w + 1) < box_u->siz_w; i_w++ ) { - box_w[i_w] = 0xdeadbeef; - } - } -#endif - - _box_count(box_u->siz_w); - { - c3_w sel_w = _box_slot(box_u->siz_w); - u3p(u3a_fbox) fre_p = u3of(u3a_fbox, box_u); - u3p(u3a_fbox)* pfr_p = &u3R->all.fre_p[sel_w]; - u3p(u3a_fbox) nex_p = *pfr_p; - - u3to(u3a_fbox, fre_p)->pre_p = 0; - u3to(u3a_fbox, fre_p)->nex_p = nex_p; - if ( u3to(u3a_fbox, fre_p)->nex_p ) { - u3to(u3a_fbox, u3to(u3a_fbox, fre_p)->nex_p)->pre_p = fre_p; - } - (*pfr_p) = fre_p; - } -} - -/* _box_detach(): detach a box from the free list. -*/ -static void -_box_detach(u3a_box* box_u) -{ - u3p(u3a_fbox) fre_p = u3of(u3a_fbox, box_u); - u3p(u3a_fbox) pre_p = u3to(u3a_fbox, fre_p)->pre_p; - u3p(u3a_fbox) nex_p = u3to(u3a_fbox, fre_p)->nex_p; - - _box_count(-(box_u->siz_w)); - - if ( nex_p ) { - if ( u3to(u3a_fbox, nex_p)->pre_p != fre_p ) { - c3_assert(!"loom: corrupt"); - } - u3to(u3a_fbox, nex_p)->pre_p = pre_p; - } - if ( pre_p ) { - if( u3to(u3a_fbox, pre_p)->nex_p != fre_p ) { - c3_assert(!"loom: corrupt"); - } - u3to(u3a_fbox, pre_p)->nex_p = nex_p; - } - else { - c3_w sel_w = _box_slot(box_u->siz_w); - - if ( fre_p != u3R->all.fre_p[sel_w] ) { - c3_assert(!"loom: corrupt"); - } - u3R->all.fre_p[sel_w] = nex_p; - } -} - -/* _box_free(): free and coalesce. -*/ -static void -_box_free(u3a_box* box_u) -{ - c3_w* box_w = (c3_w *)(void *)box_u; - - c3_assert(box_u->use_w != 0); - box_u->use_w -= 1; - if ( 0 != box_u->use_w ) { - return; - } - -#if 0 - /* Clear the contents of the block, for debugging. - */ - { - c3_w i_w; - - for ( i_w = c3_wiseof(u3a_box); (i_w + 1) < box_u->siz_w; i_w++ ) { - box_w[i_w] = 0xdeadbeef; - } - } -#endif - - if ( c3y == u3a_is_north(u3R) ) { - /* Try to coalesce with the block below. - */ - if ( box_w != u3a_into(u3R->rut_p) ) { - c3_w laz_w = *(box_w - 1); - u3a_box* pox_u = (u3a_box*)(void *)(box_w - laz_w); - - if ( 0 == pox_u->use_w ) { - _box_detach(pox_u); - _box_make(pox_u, (laz_w + box_u->siz_w), 0); - - box_u = pox_u; - box_w = (c3_w*)(void *)pox_u; - } - } - - /* Try to coalesce with the block above, or the wilderness. - */ - if ( (box_w + box_u->siz_w) == u3a_into(u3R->hat_p) ) { - u3R->hat_p = u3a_outa(box_w); - } - else { - u3a_box* nox_u = (u3a_box*)(void *)(box_w + box_u->siz_w); - - if ( 0 == nox_u->use_w ) { - _box_detach(nox_u); - _box_make(box_u, (box_u->siz_w + nox_u->siz_w), 0); - } - _box_attach(box_u); - } - } - else { - /* Try to coalesce with the block above. - */ - if ( (box_w + box_u->siz_w) != u3a_into(u3R->rut_p) ) { - u3a_box* nox_u = (u3a_box*)(void *)(box_w + box_u->siz_w); - - if ( 0 == nox_u->use_w ) { - _box_detach(nox_u); - _box_make(box_u, (box_u->siz_w + nox_u->siz_w), 0); - } - } - - /* Try to coalesce with the block below, or with the wilderness. - */ - if ( box_w == u3a_into(u3R->hat_p) ) { - u3R->hat_p = u3a_outa(box_w + box_u->siz_w); - } - else { - c3_w laz_w = *(box_w - 1); - u3a_box* pox_u = (u3a_box*)(void *)(box_w - laz_w); - - if ( 0 == pox_u->use_w ) { - _box_detach(pox_u); - _box_make(pox_u, (laz_w + box_u->siz_w), 0); - box_u = pox_u; - } - _box_attach(box_u); - } - } -} - -/* _me_align_pad(): pad to first point after pos_p aligned at (ald_w, alp_w). -*/ -static __inline__ c3_w -_me_align_pad(u3_post pos_p, c3_w ald_w, c3_w alp_w) -{ - c3_w adj_w = (ald_w - (alp_w + 1)); - c3_p off_p = (pos_p + adj_w); - c3_p orp_p = off_p &~ (ald_w - 1); - c3_p fin_p = orp_p + alp_w; - c3_w pad_w = (fin_p - pos_p); - - return pad_w; -} - -/* _me_align_dap(): pad to last point before pos_p aligned at (ald_w, alp_w). -*/ -static __inline__ c3_w -_me_align_dap(u3_post pos_p, c3_w ald_w, c3_w alp_w) -{ - c3_w adj_w = alp_w; - c3_p off_p = (pos_p - adj_w); - c3_p orp_p = (off_p &~ (ald_w - 1)); - c3_p fin_p = orp_p + alp_w; - c3_w pad_w = (pos_p - fin_p); - - return pad_w; -} - -/* _ca_box_make_hat(): in u3R, allocate directly on the hat. -*/ -static u3a_box* -_ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w alp_w, c3_w use_w) -{ - c3_w pad_w, siz_w; - u3_post all_p; - - if ( c3y == u3a_is_north(u3R) ) { - all_p = u3R->hat_p; - pad_w = _me_align_pad(all_p, ald_w, alp_w); - siz_w = (len_w + pad_w); - - // hand-inlined: siz_w >= u3a_open(u3R) - // - if ( (siz_w >= (u3R->cap_p - u3R->hat_p)) ) { - return 0; - } - u3R->hat_p = (all_p + siz_w); - } - else { - all_p = (u3R->hat_p - len_w); - pad_w = _me_align_dap(all_p, ald_w, alp_w); - siz_w = (len_w + pad_w); - all_p -= pad_w; - - // hand-inlined: siz_w >= u3a_open(u3R) - // - if ( siz_w >= (u3R->hat_p - u3R->cap_p) ) { - return 0; - } - u3R->hat_p = all_p; - } - return _box_make(u3a_into(all_p), siz_w, use_w); -} - -#if 0 -/* _me_road_all_hat(): in u3R, allocate directly on the hat. -*/ -static u3a_box* -_ca_box_make_hat(c3_w len_w, c3_w alm_w, c3_w use_w) -{ - return _box_make(_me_road_all_hat(len_w), len_w, use_w); -} -#endif - -#if 0 // not yet used -/* _me_road_all_cap(): in u3R, allocate directly on the cap. -*/ -static c3_w* -_me_road_all_cap(c3_w len_w) -{ - if ( len_w > u3a_open(u3R) ) { - u3m_bail(c3__meme); return 0; - } - - if ( c3y == u3a_is_north(u3R) ) { - u3R->cap_p -= len_w; - return u3a_into(u3R->cap_p); - } - else { - u3_post all_p; - - all_p = u3R->cap_p; - u3R->cap_p += len_w; - return u3a_into(all_p); - } -} -#endif - -#if 0 -/* u3a_sane(): check allocator sanity. -*/ -void -u3a_sane(void) -{ - c3_w i_w; - - for ( i_w = 0; i_w < u3a_fbox_no; i_w++ ) { - u3a_fbox* fre_u = u3R->all.fre_u[i_w]; - - while ( fre_u ) { - if ( fre_u == u3R->all.fre_u[i_w] ) { - c3_assert(fre_u->pre_u == 0); - } - else { - c3_assert(fre_u->pre_u != 0); - c3_assert(fre_u->pre_u->nex_u == fre_u); - if ( fre_u->nex_u != 0 ) { - c3_assert(fre_u->nex_u->pre_u == fre_u); - } - } - fre_u = fre_u->nex_u; - } - } -} -#endif - -/* u3a_reflux(): dump 1K cells from the cell list into regular memory. -*/ -void -u3a_reflux(void) -{ - c3_w i_w; - - for ( i_w = 0; u3R->all.cel_p && (i_w < 1024); i_w++ ) { - u3_post cel_p = u3R->all.cel_p; - u3a_box* box_u = &(u3to(u3a_fbox, cel_p)->box_u); - - u3R->all.cel_p = u3to(u3a_fbox, cel_p)->nex_p; - - // otherwise _box_free() will double-count it - // - _box_count(-(u3a_minimum)); - _box_free(box_u); - - } -} - -/* _ca_reclaim_half(): reclaim from memoization cache. -*/ -static void -_ca_reclaim_half(void) -{ - // XX u3l_log avoid here, as it can - // cause problems when handling errors - - if ( (0 == u3R->cax.har_p) || - (0 == u3to(u3h_root, u3R->cax.har_p)->use_w) ) - { - fprintf(stderr, "allocate: reclaim: memo cache: empty\r\n"); - u3m_bail(c3__meme); - } - -#if 1 - fprintf(stderr, "allocate: reclaim: half of %d entries\r\n", - u3to(u3h_root, u3R->cax.har_p)->use_w); - - u3h_trim_to(u3R->cax.har_p, u3to(u3h_root, u3R->cax.har_p)->use_w / 2); -#else - /* brutal and guaranteed effective - */ - u3h_free(u3R->cax.har_p); - u3R->cax.har_p = u3h_new(); -#endif -} - -/* _ca_willoc(): u3a_walloc() internals. -*/ -static void* -_ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) -{ - c3_w siz_w = c3_max(u3a_minimum, u3a_boxed(len_w)); - c3_w sel_w = _box_slot(siz_w); - - alp_w = (alp_w + c3_wiseof(u3a_box)) % ald_w; - - // XX: this logic is totally bizarre, but preserve it. - // - if ( (sel_w != 0) && (sel_w != u3a_fbox_no - 1) ) { - sel_w += 1; - } - - // u3l_log("walloc %d: *pfr_p %x", len_w, u3R->all.fre_p[sel_w]); - while ( 1 ) { - u3p(u3a_fbox) *pfr_p = &u3R->all.fre_p[sel_w]; - - while ( 1 ) { - if ( 0 == *pfr_p ) { - if ( sel_w < (u3a_fbox_no - 1) ) { - sel_w += 1; - break; - } - else { - // nothing in top free list; chip away at the hat - // - u3a_box* box_u; - - // memory nearly empty; reclaim; should not be needed - // - // if ( (u3a_open(u3R) + u3R->all.fre_w) < 65536 ) { _ca_reclaim_half(); } - box_u = _ca_box_make_hat(siz_w, ald_w, alp_w, 1); - - /* Flush a bunch of cell cache, then try again. - */ - if ( 0 == box_u ) { - if ( u3R->all.cel_p ) { - u3a_reflux(); - - return _ca_willoc(len_w, ald_w, alp_w); - } - else { - _ca_reclaim_half(); - return _ca_willoc(len_w, ald_w, alp_w); - } - } - else return u3a_boxto(box_u); - } - } - else { - c3_w pad_w = _me_align_pad(*pfr_p, ald_w, alp_w); - - if ( 1 == ald_w ) c3_assert(0 == pad_w); - - if ( (siz_w + pad_w) > u3to(u3a_fbox, *pfr_p)->box_u.siz_w ) { - /* This free block is too small. Continue searching. - */ - pfr_p = &(u3to(u3a_fbox, *pfr_p)->nex_p); - continue; - } - else { - u3a_box* box_u = &(u3to(u3a_fbox, *pfr_p)->box_u); - - /* We have found a free block of adequate size. Remove it - ** from the free list. - */ - siz_w += pad_w; - _box_count(-(box_u->siz_w)); - { - if ( (0 != u3to(u3a_fbox, *pfr_p)->pre_p) && - (u3to(u3a_fbox, u3to(u3a_fbox, *pfr_p)->pre_p)->nex_p - != (*pfr_p)) ) - { - c3_assert(!"loom: corrupt"); - } - - if( (0 != u3to(u3a_fbox, *pfr_p)->nex_p) && - (u3to(u3a_fbox, u3to(u3a_fbox, *pfr_p)->nex_p)->pre_p - != (*pfr_p)) ) - { - c3_assert(!"loom: corrupt"); - } - - if ( 0 != u3to(u3a_fbox, *pfr_p)->nex_p ) { - u3to(u3a_fbox, u3to(u3a_fbox, *pfr_p)->nex_p)->pre_p = - u3to(u3a_fbox, *pfr_p)->pre_p; - } - *pfr_p = u3to(u3a_fbox, *pfr_p)->nex_p; - } - - /* If we can chop off another block, do it. - */ - if ( (siz_w + u3a_minimum) <= box_u->siz_w ) { - /* Split the block. - */ - c3_w* box_w = ((c3_w *)(void *)box_u); - c3_w* end_w = box_w + siz_w; - c3_w lef_w = (box_u->siz_w - siz_w); - - _box_attach(_box_make(end_w, lef_w, 0)); - return u3a_boxto(_box_make(box_w, siz_w, 1)); - } - else { - c3_assert(0 == box_u->use_w); - box_u->use_w = 1; - -#ifdef U3_MEMORY_DEBUG - box_u->cod_w = u3_Code; -#endif - return u3a_boxto(box_u); - } - } - } - } - } -} - -/* _ca_walloc(): u3a_walloc() internals. -*/ -static void* -_ca_walloc(c3_w len_w, c3_w ald_w, c3_w alp_w) -{ - void* ptr_v; - - while ( 1 ) { - ptr_v = _ca_willoc(len_w, ald_w, alp_w); - if ( 0 != ptr_v ) { - break; - } - _ca_reclaim_half(); - } - return ptr_v; -} - -/* u3a_walloc(): allocate storage words on hat heap. -*/ -void* -u3a_walloc(c3_w len_w) -{ - void* ptr_v; - - ptr_v = _ca_walloc(len_w, 1, 0); - -#if 0 - if ( (703 == u3_Code) && - u3a_botox(ptr_v) == (u3a_box*)(void *)0x200dfe3e4 ) { - static int xuc_i; - - u3l_log("xuc_i %d", xuc_i); - if ( 1 == xuc_i ) { - u3a_box* box_u = u3a_botox(ptr_v); - - box_u->cod_w = 999; - } - xuc_i++; - } -#endif - return ptr_v; -} - -/* u3a_wealloc(): realloc in words. -*/ -void* -u3a_wealloc(void* lag_v, c3_w len_w) -{ - if ( !lag_v ) { - return u3a_malloc(len_w); - } - else { - u3a_box* box_u = u3a_botox(lag_v); - c3_w* old_w = lag_v; - c3_w tiz_w = c3_min(box_u->siz_w, len_w); - { - c3_w* new_w = u3a_walloc(len_w); - c3_w i_w; - - for ( i_w = 0; i_w < tiz_w; i_w++ ) { - new_w[i_w] = old_w[i_w]; - } - u3a_wfree(lag_v); - return new_w; - } - } -} - -/* u3a_pile_prep(): initialize stack control. -*/ -void -u3a_pile_prep(u3a_pile* pil_u, c3_w len_w) -{ - // frame size, in words - // - c3_w wor_w = (len_w + 3) >> 2; - c3_o nor_o = u3a_is_north(u3R); - - pil_u->mov_ws = (c3y == nor_o) ? -wor_w : wor_w; - pil_u->off_ws = (c3y == nor_o) ? 0 : -wor_w; - pil_u->top_p = u3R->cap_p; - -#ifdef U3_MEMORY_DEBUG - pil_u->rod_u = u3R; -#endif -} - -/* u3a_wfree(): free storage. -*/ -void -u3a_wfree(void* tox_v) -{ - _box_free(u3a_botox(tox_v)); -} - -/* u3a_wtrim(): trim storage. -*/ -void -u3a_wtrim(void* tox_v, c3_w old_w, c3_w len_w) -{ - c3_w* nov_w = tox_v; - - if ( (old_w > len_w) - && ((old_w - len_w) >= u3a_minimum) ) - { - c3_w* box_w = (void *)u3a_botox(nov_w); - c3_w* end_w = (nov_w + len_w + 1); - c3_w asz_w = (end_w - box_w); - c3_w bsz_w = box_w[0] - asz_w; - - _box_attach(_box_make(end_w, bsz_w, 0)); - - box_w[0] = asz_w; - box_w[asz_w - 1] = asz_w; - } -} - -/* u3a_calloc(): allocate and zero-initialize array -*/ -void* -u3a_calloc(size_t num_i, size_t len_i) -{ - size_t byt_i = num_i * len_i; - c3_w* out_w; - - c3_assert(byt_i / len_i == num_i); - out_w = u3a_malloc(byt_i); - memset(out_w, 0, byt_i); - - return out_w; -} - -/* u3a_malloc(): aligned storage measured in bytes. -*/ -void* -u3a_malloc(size_t len_i) -{ - c3_w len_w = (c3_w)((len_i + 3) >> 2); - c3_w* ptr_w = _ca_walloc(len_w + 1, 4, 3); - u3_post ptr_p = u3a_outa(ptr_w); - c3_w pad_w = _me_align_pad(ptr_p, 4, 3); - c3_w* out_w = u3a_into(ptr_p + pad_w + 1); - -#if 0 - if ( u3a_botox(out_w) == (u3a_box*)(void *)0x3bdd1c80) { - static int xuc_i = 0; - - u3l_log("xuc_i %d", xuc_i); - // if ( 1 == xuc_i ) { abort(); } - xuc_i++; - } -#endif - out_w[-1] = pad_w; - - return out_w; -} - -/* u3a_cellblock(): allocate a block of cells on the hat. -*/ -static c3_o -u3a_cellblock(c3_w num_w) -{ - u3p(u3a_fbox) fre_p; - c3_w i_w; - - if ( c3y == u3a_is_north(u3R) ) { - if ( u3R->cap_p <= (u3R->hat_p + (num_w * u3a_minimum) + (1 << u3a_page)) ) { - return c3n; - } - else { - u3_post cel_p = u3R->all.cel_p; - u3_post hat_p = u3R->hat_p; - u3R->hat_p += (num_w * u3a_minimum); - - for ( i_w = 0; i_w < num_w; i_w++) { - u3_post all_p = hat_p; - void* box_v = u3a_into(all_p); - u3a_box* box_u = box_v; - c3_w* box_w = box_v; - - // hand inline of _box_make(u3a_into(all_p), u3a_minimum, 1) - { - box_w[0] = u3a_minimum; - box_w[u3a_minimum - 1] = u3a_minimum; - box_u->use_w = 1; -#ifdef U3_MEMORY_DEBUG - box_u->cod_w = 0; - box_u->eus_w = 0; -#endif - } - hat_p += u3a_minimum; - - fre_p = u3of(u3a_fbox, box_u); - u3to(u3a_fbox, fre_p)->nex_p = cel_p; - cel_p = fre_p; - } - - u3R->all.cel_p = cel_p; - } - } - else { - if ( (u3R->cap_p + (num_w * u3a_minimum) + (1 << u3a_page)) >= u3R->hat_p ) { - return c3n; - } - else { - u3_post cel_p = u3R->all.cel_p; - u3_post hat_p = u3R->hat_p; - u3R->hat_p -= (num_w * u3a_minimum); - - for ( i_w = 0; i_w < num_w; i_w++ ) { - u3_post all_p = (hat_p -= u3a_minimum); - void* box_v = u3a_into(all_p); - u3a_box* box_u = box_v; - c3_w* box_w = box_v; - - // hand inline of _box_make(u3a_into(all_p), u3a_minimum, 1); - { - box_w[0] = u3a_minimum; - box_w[u3a_minimum - 1] = u3a_minimum; - box_u->use_w = 1; -# ifdef U3_MEMORY_DEBUG - box_u->cod_w = 0; - box_u->eus_w = 0; -# endif - } - fre_p = u3of(u3a_fbox, box_u); - u3to(u3a_fbox, fre_p)->nex_p = cel_p; - cel_p = fre_p; - } - - u3R->all.cel_p = cel_p; - } - } - _box_count(num_w * u3a_minimum); - return c3y; -} - -/* u3a_celloc(): allocate a cell. -*/ -c3_w* -u3a_celloc(void) -{ -#ifdef U3_CPU_DEBUG - u3R->pro.cel_d++; -#endif - -#ifdef U3_MEMORY_DEBUG - if ( u3C.wag_w & u3o_debug_ram ) { - return u3a_walloc(c3_wiseof(u3a_cell)); - } -#endif - - u3p(u3a_fbox) cel_p; - - if ( !(cel_p = u3R->all.cel_p) ) { - if ( u3R == &(u3H->rod_u) ) { - // no cell allocator on home road - // - return u3a_walloc(c3_wiseof(u3a_cell)); - } - else { - if ( c3n == u3a_cellblock(4096) ) { - return u3a_walloc(c3_wiseof(u3a_cell)); - } - cel_p = u3R->all.cel_p; - } - } - - { - u3a_box* box_u = &(u3to(u3a_fbox, cel_p)->box_u); - - - box_u->use_w = 1; - u3R->all.cel_p = u3to(u3a_fbox, cel_p)->nex_p; - - _box_count(-(u3a_minimum)); - - return u3a_boxto(box_u); - } -} - -/* u3a_cfree(): free a cell. -*/ -void -u3a_cfree(c3_w* cel_w) -{ -#ifdef U3_MEMORY_DEBUG - if ( u3C.wag_w & u3o_debug_ram ) { - return u3a_wfree(cel_w); - } -#endif - - if ( u3R == &(u3H->rod_u) ) { - return u3a_wfree(cel_w); - } - else { - u3a_box* box_u = u3a_botox(cel_w); - u3p(u3a_fbox) fre_p = u3of(u3a_fbox, box_u); - - _box_count(u3a_minimum); - - u3to(u3a_fbox, fre_p)->nex_p = u3R->all.cel_p; - u3R->all.cel_p = fre_p; - } -} - -/* u3a_realloc(): aligned realloc in bytes. -*/ -void* -u3a_realloc(void* lag_v, size_t len_i) -{ - if ( !lag_v ) { - return u3a_malloc(len_i); - } - else { - c3_w len_w = (c3_w)((len_i + 3) >> 2); - c3_w* lag_w = lag_v; - c3_w pad_w = lag_w[-1]; - c3_w* org_w = lag_w - (pad_w + 1); - u3a_box* box_u = u3a_botox((void *)org_w); - c3_w* old_w = lag_v; - c3_w tiz_w = c3_min(box_u->siz_w, len_w); - { - c3_w* new_w = u3a_malloc(len_i); - c3_w i_w; - - for ( i_w = 0; i_w < tiz_w; i_w++ ) { - new_w[i_w] = old_w[i_w]; - } - u3a_wfree(org_w); - return new_w; - } - } - c3_w len_w = (c3_w)len_i; - - return u3a_wealloc(lag_v, (len_w + 3) >> 2); -} - -/* u3a_free(): free for aligned malloc. -*/ -void -u3a_free(void* tox_v) -{ - if (NULL == tox_v) - return; - - c3_w* tox_w = tox_v; - c3_w pad_w = tox_w[-1]; - c3_w* org_w = tox_w - (pad_w + 1); - - // u3l_log("free %p %p", org_w, tox_w); - u3a_wfree(org_w); -} - -/* _me_wash_north(): clean up mug slots after copy. -*/ -static void _me_wash_north(u3_noun dog); -static void -_me_wash_north_in(u3_noun som) -{ - if ( _(u3a_is_cat(som)) ) return; - if ( !_(u3a_north_is_junior(u3R, som)) ) return; - - _me_wash_north(som); -} -static void -_me_wash_north(u3_noun dog) -{ - c3_assert(c3y == u3a_is_dog(dog)); - // c3_assert(c3y == u3a_north_is_junior(u3R, dog)); - { - u3a_noun* dog_u = u3a_to_ptr(dog); - - if ( dog_u->mug_w == 0 ) return; - - dog_u->mug_w = 0; // power wash - // if ( dog_u->mug_w >> 31 ) { dog_u->mug_w = 0; } - - if ( _(u3a_is_pom(dog)) ) { - u3a_cell* god_u = (u3a_cell *)(void *)dog_u; - - _me_wash_north_in(god_u->hed); - _me_wash_north_in(god_u->tel); - } - } -} - -/* _me_wash_south(): clean up mug slots after copy. -*/ -static void _me_wash_south(u3_noun dog); -static void -_me_wash_south_in(u3_noun som) -{ - if ( _(u3a_is_cat(som)) ) return; - if ( !_(u3a_south_is_junior(u3R, som)) ) return; - - _me_wash_south(som); -} -static void -_me_wash_south(u3_noun dog) -{ - c3_assert(c3y == u3a_is_dog(dog)); - // c3_assert(c3y == u3a_south_is_junior(u3R, dog)); - { - u3a_noun* dog_u = u3a_to_ptr(dog); - - if ( dog_u->mug_w == 0 ) return; - - dog_u->mug_w = 0; // power wash - // if ( dog_u->mug_w >> 31 ) { dog_u->mug_w = 0; } - - if ( _(u3a_is_pom(dog)) ) { - u3a_cell* god_u = (u3a_cell *)(void *)dog_u; - - _me_wash_south_in(god_u->hed); - _me_wash_south_in(god_u->tel); - } - } -} - -/* u3a_wash(): wash all lazy mugs. RETAIN. -*/ -void -u3a_wash(u3_noun som) -{ - if ( _(u3a_is_cat(som)) ) { - return; - } - if ( _(u3a_is_north(u3R)) ) { - if ( _(u3a_north_is_junior(u3R, som)) ) { - _me_wash_north(som); - } - } - else { - if ( _(u3a_south_is_junior(u3R, som)) ) { - _me_wash_south(som); - } - } -} - -/* _me_gain_use(): increment use count. -*/ -static void -_me_gain_use(u3_noun dog) -{ - c3_w* dog_w = u3a_to_ptr(dog); - u3a_box* box_u = u3a_botox(dog_w); - - if ( 0x7fffffff == box_u->use_w ) { - u3l_log("fail in _me_gain_use"); - u3m_bail(c3__fail); - } - else { - if ( box_u->use_w == 0 ) { - u3m_bail(c3__foul); - } - box_u->use_w += 1; - -#ifdef U3_MEMORY_DEBUG - // enable to (maybe) help track down leaks - // - // if ( u3_Code && !box_u->cod_w ) { box_u->cod_w = u3_Code; } -#endif - } -} - -#undef VERBOSE_TAKE - -/* _ca_take_atom(): reallocate an indirect atom off the stack. -*/ -static inline u3_atom -_ca_take_atom(u3a_atom* old_u) -{ - c3_w* new_w = u3a_walloc(old_u->len_w + c3_wiseof(u3a_atom)); - u3a_atom* new_u = (u3a_atom*)(void *)new_w; - u3_noun new = u3a_to_pug(u3a_outa(new_u)); - -#ifdef VERBOSE_TAKE - u3l_log("%s: atom %p to %p", ( c3y == u3a_is_north(u3R) ) - ? "north" - : "south", - old_u, - new_u); -#endif - - // XX use memcpy? - // - new_u->mug_w = old_u->mug_w; - new_u->len_w = old_u->len_w; - { - c3_w i_w; - - for ( i_w=0; i_w < old_u->len_w; i_w++ ) { - new_u->buf_w[i_w] = old_u->buf_w[i_w]; - } - } - - // borrow mug slot to record new destination in [old_u] - // - old_u->mug_w = new; - - return new; -} - -/* _ca_take_cell(): reallocate a cell off the stack. -*/ -static inline u3_cell -_ca_take_cell(u3a_cell* old_u, u3_noun hed, u3_noun tel) -{ - // XX use u3a_celloc? - // - c3_w* new_w = u3a_walloc(c3_wiseof(u3a_cell)); - u3a_cell* new_u = (u3a_cell*)(void *)new_w; - u3_cell new = u3a_to_pom(u3a_outa(new_u)); - -#ifdef VERBOSE_TAKE - u3l_log("%s: cell %p to %p", ( c3y == u3a_is_north(u3R) ) - ? "north" - : "south", - old_u, - new_u); -#endif - - new_u->mug_w = old_u->mug_w; - new_u->hed = hed; - new_u->tel = tel; - - // borrow mug slot to record new destination in [old_u] - // - old_u->mug_w = new; - - return new; -} - -/* _ca_take: stack frame for recording cell travesal -** (u3_none == hed) == head-frame -*/ -typedef struct _ca_take -{ - u3_weak hed; // taken head - u3_cell old; // old cell -} _ca_take; - -/* _ca_take_next_south: take next noun, pushing cells on stack. -*/ -static inline u3_noun -_ca_take_next_north(u3a_pile* pil_u, u3_noun veb) -{ - while ( 1 ) { - // direct atoms and senior refs are not counted. - // - if ( (c3y == u3a_is_cat(veb)) - || (c3y == u3a_north_is_senior(u3R, veb)) ) - { - return veb; - } - // not junior; normal (heap) refs on our road are counted. - // - else if ( c3n == u3a_north_is_junior(u3R, veb) ) { - _me_gain_use(veb); // bypass branches in u3k() - return veb; - } - // junior (stack) refs are copied. - // - else { - u3a_noun* veb_u = u3a_to_ptr(veb); - - // 32-bit mug_w: already copied [veb] and [mug_w] is the new ref. - // - if ( veb_u->mug_w >> 31 ) { - u3_noun nov = (u3_noun)veb_u->mug_w; - - c3_assert( c3y == u3a_north_is_normal(u3R, nov) ); - -#ifdef VERBOSE_TAKE - u3l_log("north: %p is already %p", veb_u, u3a_to_ptr(nov)); -#endif - - _me_gain_use(nov); // bypass branches in u3k() - return nov; - } - else if ( c3y == u3a_is_atom(veb) ) { - return _ca_take_atom((u3a_atom*)veb_u); - } - else { - u3a_cell* old_u = (u3a_cell*)veb_u; - _ca_take* fam_u = u3a_push(pil_u); - - fam_u->hed = u3_none; - fam_u->old = veb; - - veb = old_u->hed; - continue; - } - } - } -} - -/* _ca_take_next_south: take next noun, pushing cells on stack. -*/ -static inline u3_noun -_ca_take_next_south(u3a_pile* pil_u, u3_noun veb) -{ - while ( 1 ) { - // direct atoms and senior refs are not counted. - // - if ( (c3y == u3a_is_cat(veb)) - || (c3y == u3a_south_is_senior(u3R, veb)) ) - { - return veb; - } - // not junior; a normal pointer in our road -- refcounted - // - else if ( c3n == u3a_south_is_junior(u3R, veb) ) { - _me_gain_use(veb); // bypass branches in u3k() - return veb; - } - // junior (stack) refs are copied. - // - else { - u3a_noun* veb_u = u3a_to_ptr(veb); - - // 32-bit mug_w: already copied [veb] and [mug_w] is the new ref. - // - if ( veb_u->mug_w >> 31 ) { - u3_noun nov = (u3_noun)veb_u->mug_w; - - c3_assert( c3y == u3a_south_is_normal(u3R, nov) ); - -#ifdef VERBOSE_TAKE - u3l_log("south: %p is already %p", veb_u, u3a_to_ptr(nov)); -#endif - - _me_gain_use(nov); // bypass branches in u3k() - return nov; - } - else if ( c3y == u3a_is_atom(veb) ) { - return _ca_take_atom((u3a_atom*)veb_u); - } - else { - u3a_cell* old_u = (u3a_cell*)veb_u; - _ca_take* fam_u = u3a_push(pil_u); - - fam_u->hed = u3_none; - fam_u->old = veb; - - veb = old_u->hed; - continue; - } - } - } -} - -/* _ca_take_north(): in a north road, gain, copying juniors (from stack). -*/ -static u3_noun -_ca_take_north(u3_noun veb) -{ - u3_noun pro; - _ca_take* fam_u; - u3a_pile pil_u; - u3a_pile_prep(&pil_u, sizeof(*fam_u)); - - // commence taking - // - pro = _ca_take_next_north(&pil_u, veb); - - // process cell results - // - if ( c3n == u3a_pile_done(&pil_u) ) { - fam_u = u3a_peek(&pil_u); - - do { - // head-frame: stash copy and continue into the tail - // - if ( u3_none == fam_u->hed ) { - u3a_cell* old_u = u3a_to_ptr(fam_u->old); - fam_u->hed = pro; - pro = _ca_take_next_north(&pil_u, old_u->tel); - fam_u = u3a_peek(&pil_u); - } - // tail-frame: copy cell and pop the stack - // - else { - u3a_cell* old_u = u3a_to_ptr(fam_u->old); - pro = _ca_take_cell(old_u, fam_u->hed, pro); - fam_u = u3a_pop(&pil_u); - } - } while ( c3n == u3a_pile_done(&pil_u) ); - } - - return pro; -} -/* _ca_take_south(): in a south road, gain, copying juniors (from stack). -*/ -static u3_noun -_ca_take_south(u3_noun veb) -{ - u3_noun pro; - _ca_take* fam_u; - u3a_pile pil_u; - u3a_pile_prep(&pil_u, sizeof(*fam_u)); - - // commence taking - // - pro = _ca_take_next_south(&pil_u, veb); - - // process cell results - // - if ( c3n == u3a_pile_done(&pil_u) ) { - fam_u = u3a_peek(&pil_u); - - do { - // head-frame: stash copy and continue into the tail - // - if ( u3_none == fam_u->hed ) { - u3a_cell* old_u = u3a_to_ptr(fam_u->old); - fam_u->hed = pro; - pro = _ca_take_next_south(&pil_u, old_u->tel); - fam_u = u3a_peek(&pil_u); - } - // tail-frame: copy cell and pop the stack - // - else { - u3a_cell* old_u = u3a_to_ptr(fam_u->old); - pro = _ca_take_cell(old_u, fam_u->hed, pro); - fam_u = u3a_pop(&pil_u); - } - } while ( c3n == u3a_pile_done(&pil_u) ); - } - - return pro; -} - -/* u3a_take(): gain, copying juniors. -*/ -u3_noun -u3a_take(u3_noun veb) -{ - u3_noun pro; - u3t_on(coy_o); - - c3_assert(u3_none != veb); - - pro = ( c3y == u3a_is_north(u3R) ) - ? _ca_take_north(veb) - : _ca_take_south(veb); - - u3t_off(coy_o); - return pro; -} - -/* u3a_left(): true of junior if preserved. -*/ -c3_o -u3a_left(u3_noun som) -{ - if ( _(u3a_is_cat(som)) || - !_(u3a_is_junior(u3R, som)) ) - { - return c3y; - } - else { - u3a_noun* dog_u = u3a_to_ptr(som); - - return __(0 != (dog_u->mug_w >> 31)); - } -} - -/* _me_gain_north(): gain on a north road. -*/ -static u3_noun -_me_gain_north(u3_noun dog) -{ - if ( c3y == u3a_north_is_senior(u3R, dog) ) { - /* senior pointers are not refcounted - */ - return dog; - } - else { - /* junior nouns are disallowed - */ - c3_assert(!_(u3a_north_is_junior(u3R, dog))); - - /* normal pointers are refcounted - */ - _me_gain_use(dog); - return dog; - } -} - -/* _me_gain_south(): gain on a south road. -*/ -static u3_noun -_me_gain_south(u3_noun dog) -{ - if ( c3y == u3a_south_is_senior(u3R, dog) ) { - /* senior pointers are not refcounted - */ - return dog; - } - else { - /* junior nouns are disallowed - */ - c3_assert(!_(u3a_south_is_junior(u3R, dog))); - - /* normal nouns are refcounted - */ - _me_gain_use(dog); - return dog; - } -} - -/* _me_lose_north(): lose on a north road. -*/ -static void -_me_lose_north(u3_noun dog) -{ -top: - if ( c3y == u3a_north_is_normal(u3R, dog) ) { - c3_w* dog_w = u3a_to_ptr(dog); - u3a_box* box_u = u3a_botox(dog_w); - - if ( box_u->use_w > 1 ) { - box_u->use_w -= 1; - } - else { - if ( 0 == box_u->use_w ) { - u3m_bail(c3__foul); - } - else { - if ( _(u3a_is_pom(dog)) ) { - u3a_cell* dog_u = (void *)dog_w; - u3_noun h_dog = dog_u->hed; - u3_noun t_dog = dog_u->tel; - - if ( !_(u3a_is_cat(h_dog)) ) { - _me_lose_north(h_dog); - } - u3a_cfree(dog_w); - if ( !_(u3a_is_cat(t_dog)) ) { - dog = t_dog; - goto top; - } - } - else { - u3a_wfree(dog_w); - } - } - } - } -} - -/* _me_lose_south(): lose on a south road. -*/ -static void -_me_lose_south(u3_noun dog) -{ -top: - if ( c3y == u3a_south_is_normal(u3R, dog) ) { - c3_w* dog_w = u3a_to_ptr(dog); - u3a_box* box_u = u3a_botox(dog_w); - - if ( box_u->use_w > 1 ) { - box_u->use_w -= 1; - } - else { - if ( 0 == box_u->use_w ) { - u3m_bail(c3__foul); - } - else { - if ( _(u3a_is_pom(dog)) ) { - u3a_cell* dog_u = (void *)dog_w; - u3_noun h_dog = dog_u->hed; - u3_noun t_dog = dog_u->tel; - - if ( !_(u3a_is_cat(h_dog)) ) { - _me_lose_south(h_dog); - } - u3a_cfree(dog_w); - if ( !_(u3a_is_cat(t_dog)) ) { - dog = t_dog; - goto top; - } - } - else { - u3a_wfree(dog_w); - } - } - } - } -} - -/* u3a_gain(): gain a reference count in normal space. -*/ -u3_noun -u3a_gain(u3_noun som) -{ - u3t_on(mal_o); - c3_assert(u3_none != som); - - if ( !_(u3a_is_cat(som)) ) { - som = _(u3a_is_north(u3R)) - ? _me_gain_north(som) - : _me_gain_south(som); - } - u3t_off(mal_o); - - return som; -} - -/* u3a_lose(): lose a reference count. -*/ -void -u3a_lose(u3_noun som) -{ - u3t_on(mal_o); - if ( !_(u3a_is_cat(som)) ) { - if ( _(u3a_is_north(u3R)) ) { - _me_lose_north(som); - } else { - _me_lose_south(som); - } - } - u3t_off(mal_o); -} - -/* u3a_use(): reference count. -*/ -c3_w -u3a_use(u3_noun som) -{ - if ( _(u3a_is_cat(som)) ) { - return 1; - } - else { - c3_w* dog_w = u3a_to_ptr(som); - u3a_box* box_u = u3a_botox(dog_w); - - return box_u->use_w; - } -} - -/* _ca_wed_who(): unify [a] and [b] on [rod_u], keeping the senior -** -** NB: this leaks a reference when it unifies in a senior road -*/ -static c3_o -_ca_wed_who(u3a_road* rod_u, u3_noun* a, u3_noun* b) -{ - c3_t asr_t = ( c3y == u3a_is_senior(rod_u, *a) ); - c3_t bsr_t = ( c3y == u3a_is_senior(rod_u, *b) ); - c3_t nor_t = ( c3y == u3a_is_north(rod_u) ); - c3_t own_t = ( rod_u == u3R ); - - // both are on [rod_u]; gain a reference to whichever we keep - // - if ( !asr_t && !bsr_t ) { - // keep [a]; it's deeper in the heap - // - // (N && >) || (S && <) - // - if ( (*a > *b) == nor_t ) { - _me_gain_use(*a); - if ( own_t ) { u3z(*b); } - *b = *a; - } - // keep [b]; it's deeper in the heap - // - else { - _me_gain_use(*b); - if ( own_t ) { u3z(*a); } - *a = *b; - } - - return c3y; - } - // keep [a]; it's senior - // - else if ( asr_t && !bsr_t ) { - if ( own_t ) { u3z(*b); } - *b = *a; - return c3y; - } - // keep [b]; it's senior - // - else if ( !asr_t && bsr_t ) { - if ( own_t ) { u3z(*a); } - *a = *b; - return c3y; - } - - // both [a] and [b] are senior; we can't unify on [rod_u] - // - return c3n; -} - -/* u3a_wed(): unify noun references. -*/ -void -u3a_wed(u3_noun* a, u3_noun* b) -{ - if ( *a != *b ) { - u3_road* rod_u = u3R; - - // while not at home, attempt to unify - // - // we try to unify on our road, and retry on senior roads - // until we succeed or reach the home road. - // - // we can't perform this kind of butchery on the home road, - // where asynchronous things can allocate. - // (XX anything besides u3t_samp?) - // - // when unifying on a higher road, we can't free nouns, - // because we can't track junior nouns that point into - // that road. - // - // this is just an implementation issue -- we could set use - // counts to 0 without actually freeing. but the allocator - // would have to be actually designed for this. - // (alternately, we could keep a deferred free-list) - // - // not freeing may generate spurious leaks, so we disable - // senior unification when debugging memory. this will - // cause a very slow boot process as the compiler compiles - // itself, constantly running into duplicates. - // - while ( (rod_u != &u3H->rod_u) && - (c3n == _ca_wed_who(rod_u, a, b)) ) - { -#ifdef U3_MEMORY_DEBUG - break; -#else - rod_u = u3to(u3_road, rod_u->par_p); -#endif - } - } -} - -/* u3a_luse(): check refcount sanity. -*/ -void -u3a_luse(u3_noun som) -{ - if ( 0 == u3a_use(som) ) { - fprintf(stderr, "loom: insane %d 0x%x\r\n", som, som); - abort(); - } - if ( _(u3du(som)) ) { - u3a_luse(u3h(som)); - u3a_luse(u3t(som)); - } -} - -/* u3a_mark_ptr(): mark a pointer for gc. Produce size if first mark. -*/ -c3_w -u3a_mark_ptr(void* ptr_v) -{ - if ( _(u3a_is_north(u3R)) ) { - if ( !((ptr_v >= u3a_into(u3R->rut_p)) && - (ptr_v < u3a_into(u3R->hat_p))) ) - { - return 0; - } - } - else { - if ( !((ptr_v >= u3a_into(u3R->hat_p)) && - (ptr_v < u3a_into(u3R->rut_p))) ) - { - return 0; - } - } - { - u3a_box* box_u = u3a_botox(ptr_v); - c3_w siz_w; - -#ifdef U3_MEMORY_DEBUG - if ( 0 == box_u->eus_w ) { - siz_w = box_u->siz_w; - } - else if ( 0xffffffff == box_u->eus_w ) { // see _raft_prof() - siz_w = 0xffffffff; - box_u->eus_w = 0; - } - else { - siz_w = 0; - } - box_u->eus_w += 1; -#else - c3_ws use_ws = (c3_ws)box_u->use_w; - - if ( use_ws == 0 ) { - fprintf(stderr, "%p is bogus\r\n", ptr_v); - siz_w = 0; - } - else { - c3_assert(use_ws != 0); - - if ( 0x80000000 == (c3_w)use_ws ) { // see _raft_prof() - use_ws = -1; - siz_w = 0xffffffff; - } - else if ( use_ws < 0 ) { - use_ws -= 1; - siz_w = 0; - } - else { - use_ws = -1; - siz_w = box_u->siz_w; - } - box_u->use_w = (c3_w)use_ws; - } -#endif - return siz_w; - } -} - -u3_post -u3a_rewritten(u3_post ptr_v) -{ - u3a_box* box_u = u3a_botox(u3a_into(ptr_v)); - c3_w* box_w = (c3_w*) box_u; - return (u3_post)box_w[box_u->siz_w - 1]; -} - -u3_noun -u3a_rewritten_noun(u3_noun som) -{ - if ( c3y == u3a_is_cat(som) ) { - return som; - } - u3_post som_p = u3a_rewritten(u3a_to_off(som)); - if ( c3y == u3a_is_pug(som) ) { - return u3a_to_pug(som_p); - } - else { - return u3a_to_pom(som_p); - } -} - -/* u3a_mark_mptr(): mark a malloc-allocated ptr for gc. -*/ -c3_w -u3a_mark_mptr(void* ptr_v) -{ - c3_w* ptr_w = ptr_v; - c3_w pad_w = ptr_w[-1]; - c3_w* org_w = ptr_w - (pad_w + 1); - - return u3a_mark_ptr(org_w); -} - -/* u3a_mark_noun(): mark a noun for gc. Produce size. -*/ -c3_w -u3a_mark_noun(u3_noun som) -{ - c3_w siz_w = 0; - - while ( 1 ) { - if ( _(u3a_is_senior(u3R, som)) ) { - return siz_w; - } - else { - c3_w* dog_w = u3a_to_ptr(som); - c3_w new_w = u3a_mark_ptr(dog_w); - - if ( 0 == new_w || 0xffffffff == new_w ) { // see u3a_mark_ptr() - return siz_w; - } - else { - siz_w += new_w; - if ( _(u3du(som)) ) { - siz_w += u3a_mark_noun(u3h(som)); - som = u3t(som); - } - else return siz_w; - } - } - } -} - -/* u3a_count_noun(): count size of pointer. -*/ -c3_w -u3a_count_ptr(void* ptr_v) -{ - if ( _(u3a_is_north(u3R)) ) { - if ( !((ptr_v >= u3a_into(u3R->rut_p)) && - (ptr_v < u3a_into(u3R->hat_p))) ) - { - return 0; - } - } - else { - if ( !((ptr_v >= u3a_into(u3R->hat_p)) && - (ptr_v < u3a_into(u3R->rut_p))) ) - { - return 0; - } - } - { - u3a_box* box_u = u3a_botox(ptr_v); - c3_w siz_w; - - c3_ws use_ws = (c3_ws)box_u->use_w; - - if ( use_ws == 0 ) { - fprintf(stderr, "%p is bogus\r\n", ptr_v); - siz_w = 0; - } - else { - c3_assert(use_ws != 0); - - if ( use_ws < 0 ) { - siz_w = 0; - } - else { - use_ws = -use_ws; - siz_w = box_u->siz_w; - } - box_u->use_w = (c3_w)use_ws; - } - return siz_w; - } -} - -/* u3a_count_noun(): count size of noun. -*/ -c3_w -u3a_count_noun(u3_noun som) -{ - c3_w siz_w = 0; - - while ( 1 ) { - if ( _(u3a_is_senior(u3R, som)) ) { - return siz_w; - } - else { - c3_w* dog_w = u3a_to_ptr(som); - c3_w new_w = u3a_count_ptr(dog_w); - - if ( 0 == new_w ) { - return siz_w; - } - else { - siz_w += new_w; - if ( _(u3du(som)) ) { - siz_w += u3a_count_noun(u3h(som)); - som = u3t(som); - } - else return siz_w; - } - } - } -} - -/* u3a_discount_ptr(): clean up after counting a pointer. -*/ -c3_w -u3a_discount_ptr(void* ptr_v) -{ - if ( _(u3a_is_north(u3R)) ) { - if ( !((ptr_v >= u3a_into(u3R->rut_p)) && - (ptr_v < u3a_into(u3R->hat_p))) ) - { - return 0; - } - } - else { - if ( !((ptr_v >= u3a_into(u3R->hat_p)) && - (ptr_v < u3a_into(u3R->rut_p))) ) - { - return 0; - } - } - u3a_box* box_u = u3a_botox(ptr_v); - c3_w siz_w; - - c3_ws use_ws = (c3_ws)box_u->use_w; - - if ( use_ws == 0 ) { - fprintf(stderr, "%p is bogus\r\n", ptr_v); - siz_w = 0; - } - else { - c3_assert(use_ws != 0); - - if ( use_ws < 0 ) { - use_ws = -use_ws; - siz_w = box_u->siz_w; - } - else { - siz_w = 0; - } - box_u->use_w = (c3_w)use_ws; - } - - return siz_w; -} - -/* u3a_discount_noun(): clean up after counting a noun. -*/ -c3_w -u3a_discount_noun(u3_noun som) -{ - c3_w siz_w = 0; - - while ( 1 ) { - if ( _(u3a_is_senior(u3R, som)) ) { - return siz_w; - } - else { - c3_w* dog_w = u3a_to_ptr(som); - c3_w new_w = u3a_discount_ptr(dog_w); - - if ( 0 == new_w ) { - return siz_w; - } - else { - siz_w += new_w; - if ( _(u3du(som)) ) { - siz_w += u3a_discount_noun(u3h(som)); - som = u3t(som); - } - else return siz_w; - } - } - } -} - -/* u3a_print_time: print microsecond time. -*/ -void -u3a_print_time(c3_c* str_c, c3_c* cap_c, c3_d mic_d) -{ - c3_assert( 0 != str_c ); - - c3_w sec_w = (mic_d / 1000000); - c3_w mec_w = (mic_d % 1000000) / 1000; - c3_w mic_w = (mic_d % 1000); - - if ( sec_w ) { - sprintf(str_c, "%s s/%d.%03d.%03d", cap_c, sec_w, mec_w, mic_w); - } - else if ( mec_w ) { - sprintf(str_c, "%s ms/%d.%03d", cap_c, mec_w, mic_w); - } - else { - sprintf(str_c, "%s \xc2\xb5s/%d", cap_c, mic_w); - } -} - -/* u3a_print_memory: print memory amount. -*/ -void -u3a_print_memory(FILE* fil_u, c3_c* cap_c, c3_w wor_w) -{ - c3_assert( 0 != fil_u ); - - c3_w byt_w = (wor_w * 4); - c3_w gib_w = (byt_w / 1000000000); - c3_w mib_w = (byt_w % 1000000000) / 1000000; - c3_w kib_w = (byt_w % 1000000) / 1000; - c3_w bib_w = (byt_w % 1000); - - if ( byt_w ) { - if ( gib_w ) { - fprintf(fil_u, "%s: GB/%d.%03d.%03d.%03d\r\n", - cap_c, gib_w, mib_w, kib_w, bib_w); - } - else if ( mib_w ) { - fprintf(fil_u, "%s: MB/%d.%03d.%03d\r\n", cap_c, mib_w, kib_w, bib_w); - } - else if ( kib_w ) { - fprintf(fil_u, "%s: KB/%d.%03d\r\n", cap_c, kib_w, bib_w); - } - else if ( bib_w ) { - fprintf(fil_u, "%s: B/%d\r\n", cap_c, bib_w); - } - } -} - -/* u3a_maid(): maybe print memory. -*/ -c3_w -u3a_maid(FILE* fil_u, c3_c* cap_c, c3_w wor_w) -{ - if ( 0 != fil_u ) { - u3a_print_memory(fil_u, cap_c, wor_w); - } - return wor_w; -} - -/* u3a_mark_road(): mark ad-hoc persistent road structures. -*/ -c3_w -u3a_mark_road(FILE* fil_u) -{ - c3_w tot_w = 0; - tot_w += u3a_maid(fil_u, " namespace", u3a_mark_noun(u3R->ski.gul)); - tot_w += u3a_maid(fil_u, " trace stack", u3a_mark_noun(u3R->bug.tax)); - tot_w += u3a_maid(fil_u, " trace buffer", u3a_mark_noun(u3R->bug.mer)); - tot_w += u3a_maid(fil_u, " profile batteries", u3a_mark_noun(u3R->pro.don)); - tot_w += u3a_maid(fil_u, " profile doss", u3a_mark_noun(u3R->pro.day)); - tot_w += u3a_maid(fil_u, " new profile trace", u3a_mark_noun(u3R->pro.trace)); - tot_w += u3a_maid(fil_u, " memoization cache", u3h_mark(u3R->cax.har_p)); - return u3a_maid(fil_u, "total road stuff", tot_w); -} - -/* u3a_reclaim(): clear ad-hoc persistent caches to reclaim memory. -*/ -void -u3a_reclaim(void) -{ - // clear the memoization cache - // - u3h_free(u3R->cax.har_p); - u3R->cax.har_p = u3h_new(); -} - -/* u3a_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures. -*/ -void -u3a_rewrite_compact(void) -{ - u3a_rewrite_noun(u3R->ski.gul); - u3a_rewrite_noun(u3R->bug.tax); - u3a_rewrite_noun(u3R->bug.mer); - u3a_rewrite_noun(u3R->pro.don); - u3a_rewrite_noun(u3R->pro.day); - u3a_rewrite_noun(u3R->pro.trace); - u3h_rewrite(u3R->cax.har_p); - - u3R->ski.gul = u3a_rewritten_noun(u3R->ski.gul); - u3R->bug.tax = u3a_rewritten_noun(u3R->bug.tax); - u3R->bug.mer = u3a_rewritten_noun(u3R->bug.mer); - u3R->pro.don = u3a_rewritten_noun(u3R->pro.don); - u3R->pro.day = u3a_rewritten_noun(u3R->pro.day); - u3R->pro.trace = u3a_rewritten_noun(u3R->pro.trace); - u3R->cax.har_p = u3a_rewritten(u3R->cax.har_p); -} - -/* _ca_print_box(): heuristically print the contents of an allocation box. -*/ -static c3_c* -_ca_print_box(u3a_box* box_u) -{ - // the loom offset pointing to the contents of box_u - // - c3_w box_w = u3a_outa(u3a_boxto(box_u)); - // box_u might not be a cell, we use the struct to inspect further - // - u3a_cell* cel_u = (u3a_cell*)box_u; - - if ( // a cell will never be bigger than the minimum allocation size - // - (u3a_minimum < box_u->siz_w) || - // this condition being true potentially corresponds to - // box_u containing an indirect atom of only one word. - // if the condition is false, we know box_u contains a cell. - // - ( (1 == (c3_w)cel_u->hed) && - (0x80000000 & (c3_w)cel_u->tel) ) ) - { - // box_u might not be an indirect atom, - // but it's always safe to print it as if it is one - // - u3a_atom* vat_u = (u3a_atom*)box_u; - u3_atom veb = u3a_to_pug(box_w); - - // skip atoms larger than 10 words - // XX print mugs or something - // - if ( 10 > vat_u->len_w ) { -#if 0 - /* For those times when you've really just got to crack open - * the box and see what's inside - */ - { - int i; - for ( i = 0; i < box_u->siz_w; i++ ) { - fprintf(stderr, "%08x ", (unsigned int)(((c3_w*)box_u)[i])); - } - fprintf(stderr, "\r\n"); - } -#endif - return 0; - } - - return u3m_pretty(veb); - } - else { - // box_u is definitely a cell - // - return u3m_pretty(u3a_to_pom(box_w)); - } -} - -/* _ca_print_leak(): print the details of a leaked allocation box. -*/ -#ifdef U3_MEMORY_DEBUG - -static void -_ca_print_leak(c3_c* cap_c, u3a_box* box_u, c3_w eus_w, c3_w use_w) -{ - fprintf(stderr, "%s: %p mug=%x (marked=%u swept=%u)\r\n", - cap_c, - box_u, - ((u3a_noun *)(u3a_boxto(box_u)))->mug_w, - eus_w, - use_w); - - if ( box_u->cod_w ) { - c3_c* cod_c = u3m_pretty(box_u->cod_w); - fprintf(stderr, "code: %s\r\n", cod_c); - c3_free(cod_c); - } - - u3a_print_memory(stderr, " size", box_u->siz_w); - - { - c3_c* dat_c = _ca_print_box(box_u); - fprintf(stderr, " data: %s\r\n", dat_c); - c3_free(dat_c); - } -} - -#else - -static void -_ca_print_leak(c3_c* cap_c, u3a_box* box_u, c3_ws use_ws) -{ - fprintf(stderr, "%s: %p mug=%x swept=%d\r\n", - cap_c, - box_u, - ((u3a_noun *)(u3a_boxto(box_u)))->mug_w, - use_ws); - - u3a_print_memory(stderr, " size", box_u->siz_w); - - { - c3_c* dat_c = _ca_print_box(box_u); - fprintf(stderr, " data: %s\r\n", dat_c); - c3_free(dat_c); - } -} - -#endif - -/* u3a_idle(): measure free-lists in [rod_u] -*/ -c3_w -u3a_idle(u3a_road* rod_u) -{ - u3a_fbox* fox_u; - c3_w i_w, fre_w = 0; - - for ( i_w = 0; i_w < u3a_fbox_no; i_w++ ) { - u3p(u3a_fbox) fre_p = rod_u->all.fre_p[i_w]; - - while ( fre_p ) { - u3a_fbox* fox_u = u3to(u3a_fbox, fre_p); - - fre_w += fox_u->box_u.siz_w; - fre_p = fox_u->nex_p; - } - } - - return fre_w; -} - -/* u3a_sweep(): sweep a fully marked road. -*/ -c3_w -u3a_sweep(void) -{ - c3_w neg_w, pos_w, leq_w, weq_w; - - /* Measure allocated memory by counting the free list. - */ - { - c3_w end_w = u3a_heap(u3R); - c3_w fre_w = u3a_idle(u3R); - -#ifdef U3_CPU_DEBUG - if ( fre_w != u3R->all.fre_w ) { - fprintf(stderr, "fre discrepancy (%x): %x, %x, %x\r\n", u3R->par_p, - fre_w, u3R->all.fre_w, (u3R->all.fre_w - fre_w)); - } -#endif - neg_w = (end_w - fre_w); - } - - /* Sweep through the arena, repairing and counting leaks. - */ - pos_w = leq_w = weq_w = 0; - { - u3_post box_p = _(u3a_is_north(u3R)) ? u3R->rut_p : u3R->hat_p; - u3_post end_p = _(u3a_is_north(u3R)) ? u3R->hat_p : u3R->rut_p; - c3_w* box_w = u3a_into(box_p); - c3_w* end_w = u3a_into(end_p); - - while ( box_w < end_w ) { - u3a_box* box_u = (void *)box_w; - -#ifdef U3_MEMORY_DEBUG - /* I suspect these printfs fail hilariously in the case - * of non-direct atoms. We shouldn't unconditionally run - * u3a_to_pom(). In general, the condition - * box_u->siz_w > u3a_minimum is sufficient, but not necessary, - * for the box to represent an atom. The atoms between - * 2^31 and 2^32 are the exceptions. - * - * Update: so, apparently u3.md is incorrect, and a pug is just - * an indirect atom. This code should be altered to handle - * that. - */ - if ( box_u->use_w != box_u->eus_w ) { - if ( box_u->eus_w != 0 ) { - if ( box_u->use_w == 0 ) { - _ca_print_leak("dank", box_u, box_u->eus_w, box_u->use_w); - } - else { - _ca_print_leak("weak", box_u, box_u->eus_w, box_u->use_w); - } - - weq_w += box_u->siz_w; - } - else { - _ca_print_leak("leak", box_u, box_u->eus_w, box_u->use_w); - - leq_w += box_u->siz_w; - } - - box_u->use_w = box_u->eus_w; - } - else { - if ( box_u->use_w ) { - pos_w += box_u->siz_w; - } - } - box_u->eus_w = 0; -#else - c3_ws use_ws = (c3_ws)box_u->use_w; - - if ( use_ws > 0 ) { - _ca_print_leak("leak", box_u, use_ws); - - leq_w += box_u->siz_w; - box_u->use_w = 0; - - _box_attach(box_u); - } - else if ( use_ws < 0 ) { - pos_w += box_u->siz_w; - box_u->use_w = (c3_w)(0 - use_ws); - } -#endif - box_w += box_u->siz_w; - } - } - -#ifdef U3_MEMORY_DEBUG - { - c3_w tot_w = u3a_full(u3R); - c3_w caf_w = u3a_temp(u3R); - -#ifdef U3_CPU_DEBUG - if ( (0 != u3R->par_p) && (u3R->all.max_w > 1000000) ) { - u3a_print_memory(stderr, "available", (tot_w - pos_w)); - u3a_print_memory(stderr, "allocated", pos_w); - u3a_print_memory(stderr, "volatile", caf_w); - - u3a_print_memory(stderr, "maximum", u3R->all.max_w); - } -#endif - -#if 0 - u3a_print_memory(stderr, "available", (tot_w - pos_w)); - u3a_print_memory(stderr, "allocated", pos_w); - u3a_print_memory(stderr, "volatile", caf_w); -#endif - } -#endif - - u3a_print_memory(stderr, "leaked", leq_w); - u3a_print_memory(stderr, "weaked", weq_w); - - c3_assert( (pos_w + leq_w + weq_w) == neg_w ); - c3_assert( (0 == leq_w) && (0 == weq_w) ); - - return neg_w; -} - -/* u3a_pack_seek(): sweep the heap, modifying boxes to record new addresses. -*/ -void -u3a_pack_seek(u3a_road* rod_u) -{ - // the heap in [rod_u] is swept from "front" to "back". - // new locations are calculated for each in-use allocation box - // (simply the "deepest" linearly-available location), - // and stored in the box itself - // - // box_w: front of the heap - // end_w: back of the heap - // new_p: initial new location (data of first box) - // - c3_w* box_w = u3a_into(rod_u->rut_p); - c3_w* end_w = u3a_into(rod_u->hat_p); - u3_post new_p = (rod_u->rut_p + c3_wiseof(u3a_box)); - u3a_box* box_u; - c3_w siz_w; - - if ( c3y == u3a_is_north(rod_u) ) { - // north roads are swept low to high - // - // new locations are recorded in the trailing size word - // - while ( box_w < end_w ) { - box_u = (void *)box_w; - siz_w = box_u->siz_w; - - if ( box_u->use_w ) { - box_w[siz_w - 1] = new_p; - new_p += siz_w; - } - - box_w += siz_w; - } - } - // XX untested! - // - else { - // south roads are swept high to low - // - // new locations are recorded in the leading size word - // - // since we traverse backward, [siz_w] holds the size of the next box, - // and we must initially offset to point to the head of the first box - // - siz_w = box_w[-1]; - box_w -= siz_w; - new_p -= siz_w; - - while ( end_w < box_w ) { - box_u = (void *)box_w; - siz_w = box_w[-1]; - - if ( box_u->use_w ) { - box_u->siz_w = new_p; - new_p -= siz_w; - } - - box_w -= siz_w; - } - } -} -static u3_post -_ca_pack_move_north(c3_w* box_w, c3_w* end_w, u3_post new_p) -{ - u3a_box* old_u; - c3_w siz_w; - - // relocate allocation boxes - // - // new locations have been recorded in the trailing size word, - // and are recalculated and asserted to ensure sanity - // - while ( box_w < end_w ) { - old_u = (void *)box_w; - siz_w = old_u->siz_w; - - old_u->use_w &= 0x7fffffff; - - if ( old_u->use_w ) { - c3_w* new_w = (void*)u3a_botox(u3a_into(new_p)); - - c3_assert( box_w[siz_w - 1] == new_p ); - - // note: includes leading size - // - if ( new_w < box_w ) { - c3_w i_w; - - for ( i_w = 0; i_w < siz_w - 1; i_w++ ) { - new_w[i_w] = box_w[i_w]; - } - } - else { - c3_assert( new_w == box_w ); - } - - // restore trailing size - // - new_w[siz_w - 1] = siz_w; - - new_p += siz_w; - } - - box_w += siz_w; - } - - return new_p; -} - -// XX untested! -// -static u3_post -_ca_pack_move_south(c3_w* box_w, c3_w* end_w, u3_post new_p) -{ - u3a_box* old_u; - c3_w siz_w; - c3_o yuz_o; - - // offset initial addresses (point to the head of the first box) - // - siz_w = box_w[-1]; - box_w -= siz_w; - new_p -= siz_w; - - // relocate allocation boxes - // - // new locations have been recorded in the leading size word, - // and are recalculated and asserted to ensure sanity - // - while ( 1 ) { - old_u = (void *)box_w; - - old_u->use_w &= 0x7fffffff; - - if ( old_u->use_w ) { - c3_w* new_w = (void*)u3a_botox(u3a_into(new_p)); - - c3_assert( old_u->siz_w == new_p ); - - // note: includes trailing size - // - if ( new_w > box_w ) { - c3_w i_w; - - for ( i_w = 1; i_w < siz_w; i_w++ ) { - new_w[i_w] = box_w[i_w]; - } - } - else { - c3_assert( new_w == box_w ); - } - - // restore leading size - // - new_w[0] = siz_w; - - yuz_o = c3y; - } - else { - yuz_o = c3n; - } - - // move backwards only if there is more work to be done - // - if ( box_w > end_w ) { - siz_w = box_w[-1]; - box_w -= siz_w; - - if ( c3y == yuz_o ) { - new_p -= siz_w; - } - } - else { - c3_assert( end_w == box_w ); - break; - } - } - - return new_p; -} - -/* u3a_pack_move(): sweep the heap, moving boxes to new addresses. -*/ -void -u3a_pack_move(u3a_road* rod_u) -{ - // box_w: front of the heap - // end_w: back of the heap - // new_p: initial new location (data of first box) - // las_p: newly calculated last location - // - c3_w* box_w = u3a_into(rod_u->rut_p); - c3_w* end_w = u3a_into(rod_u->hat_p); - u3_post new_p = (rod_u->rut_p + c3_wiseof(u3a_box)); - u3_post las_p = ( c3y == u3a_is_north(rod_u) ) - ? _ca_pack_move_north(box_w, end_w, new_p) - : _ca_pack_move_south(box_w, end_w, new_p); - - rod_u->hat_p = (las_p - c3_wiseof(u3a_box)); - - // clear free lists and cell allocator - // - { - c3_w i_w; - for ( i_w = 0; i_w < u3a_fbox_no; i_w++ ) { - u3R->all.fre_p[i_w] = 0; - } - - u3R->all.fre_w = 0; - u3R->all.cel_p = 0; - } -} - -/* u3a_rewrite_ptr(): mark a pointer as already having been rewritten -*/ -c3_o -u3a_rewrite_ptr(void* ptr_v) -{ - u3a_box* box_u = u3a_botox(ptr_v); - if ( box_u->use_w & 0x80000000 ) { - /* Already rewritten. - */ - return c3n; - } - box_u->use_w |= 0x80000000; - return c3y; -} - -void -u3a_rewrite_noun(u3_noun som) -{ - if ( c3n == u3a_is_cell(som) ) { - return; - } - - if ( c3n == u3a_rewrite_ptr(u3a_to_ptr((som))) ) return; - - u3a_cell* cel = u3a_to_ptr(som); - - u3a_rewrite_noun(cel->hed); - u3a_rewrite_noun(cel->tel); - - cel->hed = u3a_rewritten_noun(cel->hed); - cel->tel = u3a_rewritten_noun(cel->tel); -} - -#if 0 -/* _ca_detect(): in u3a_detect(). -*/ -static c3_d -_ca_detect(u3p(u3h_root) har_p, u3_noun fum, u3_noun som, c3_d axe_d) -{ - while ( 1 ) { - if ( som == fum ) { - return axe_d; - } - else if ( !_(u3du(fum)) || (u3_none != u3h_get(har_p, fum)) ) { - return 0; - } - else { - c3_d eax_d; - - u3h_put(har_p, fum, 0); - - if ( 0 != (eax_d = _ca_detect(har_p, u3h(fum), som, 2ULL * axe_d)) ) { - return c3y; - } - else { - fum = u3t(fum); - axe_d = (2ULL * axe_d) + 1; - } - } - } -} - -/* u3a_detect(): for debugging, check if (som) is referenced from (fum). -** -** (som) and (fum) are both RETAINED. -*/ -c3_d -u3a_detect(u3_noun fum, u3_noun som) -{ - u3p(u3h_root) har_p = u3h_new(); - c3_o ret_o; - - ret_o = _ca_detect(har_p, fum, som, 1); - u3h_free(har_p); - - return ret_o; -} -#endif - -#ifdef U3_MEMORY_DEBUG -/* u3a_lush(): leak push. -*/ -c3_w -u3a_lush(c3_w lab_w) -{ - c3_w cod_w = u3_Code; - - u3_Code = lab_w; - return cod_w; -} - -/* u3a_lop(): leak pop. -*/ -void -u3a_lop(c3_w lab_w) -{ - u3_Code = lab_w; -} -#else -/* u3a_lush(): leak push. -*/ -c3_w -u3a_lush(c3_w lab_w) -{ - return 0; -} - -/* u3a_lop(): leak pop. -*/ -void -u3a_lop(c3_w lab_w) -{ -} -#endif - -/* u3a_walk_fore(): preorder traversal, visits ever limb of a noun. -** -** cells are visited *before* their heads and tails -** and can shortcircuit traversal by returning [c3n] -*/ -void -u3a_walk_fore(u3_noun a, - void* ptr_v, - void (*pat_f)(u3_atom, void*), - c3_o (*cel_f)(u3_noun, void*)) -{ - u3_noun* top; - u3a_pile pil_u; - - // initialize stack control; push argument - // - u3a_pile_prep(&pil_u, sizeof(u3_noun)); - top = u3a_push(&pil_u); - *top = a; - - while ( c3n == u3a_pile_done(&pil_u) ) { - // visit an atom, then pop the stack - // - if ( c3y == u3a_is_atom(a) ) { - pat_f(a, ptr_v); - top = u3a_pop(&pil_u); - } - // vist a cell, if c3n, pop the stack - // - else if ( c3n == cel_f(a, ptr_v) ) { - top = u3a_pop(&pil_u); - } - // otherwise, push the tail and continue into the head - // - else { - *top = u3t(a); - top = u3a_push(&pil_u); - *top = u3h(a); - } - - a = *top; - } -} - -/* u3a_string(): `a` as an on-loom c-string. -*/ -c3_c* -u3a_string(u3_atom a) -{ - c3_w met_w = u3r_met(3, a); - c3_c* str_c = u3a_malloc(met_w + 1); - - u3r_bytes(0, met_w, (c3_y*)str_c, a); - str_c[met_w] = 0; - return str_c; -} diff --git a/pkg/urbit/noun/events.c b/pkg/urbit/noun/events.c deleted file mode 100644 index d277213c0..000000000 --- a/pkg/urbit/noun/events.c +++ /dev/null @@ -1,1247 +0,0 @@ -//! @file events.c -//! -//! incremental, orthogonal, paginated loom snapshots -//! -//! ### components -//! -//! - page: 16KB chunk of the loom. -//! - north segment (u3e_image, north.bin): low contiguous loom pages, -//! (in practice, the home road heap). indexed from low to high: -//! in-order on disk. -//! - south segment (u3e_image, south.bin): high contiguous loom pages, -//! (in practice, the home road stack). indexed from high to low: -//! reversed on disk. -//! - patch memory (memory.bin): new or changed pages since the last snapshot -//! - patch control (u3e_control control.bin): patch metadata, watermarks, -//! and indices/mugs for pages in patch memory. -//! -//! ### initialization (u3e_live()) -//! -//! - with the loom already mapped, all pages are marked dirty in a bitmap. -//! - if snapshot is missing or partial, empty segments are created. -//! - if a patch is present, it's applied (crash recovery). -//! - snapshot segments are copied onto the loom; all included pages -//! are marked clean and protected (read-only). -//! -//! #### page faults (u3e_fault()) -//! -//! - stores into protected pages generate faults (currently SIGSEGV, -//! handled outside this module). -//! - faults are handled by dirtying the page and switching protections to -//! read/write. -//! - a guard page is initially placed in the approximate middle of the free -//! space between the heap and stack at the time of the first page fault. -//! when a fault is detected in the guard page, the guard page is recentered -//! in the free space of the current road. if the guard page cannot be -//! recentered, then memory exhaustion has occurred. -//! -//! ### updates (u3e_save()) -//! -//! - all updates to a snapshot are made through a patch. -//! - high/low watermarks for the north/south segments are established, -//! and dirty pages below/above them are added to the patch. -//! - modifications have been caught by the fault handler. -//! - newly-used pages are automatically included (preemptively dirtied). -//! - unused, innermost pages are reclaimed (segments are truncated to the -//! high/low watermarks; the last page in each is always adjacent to the -//! contiguous free space). -//! - patch pages are written to memory.bin, metadata to control.bin. -//! - the patch is applied to the snapshot segments, in-place. -//! - patch files are deleted. -//! -//! ### limitations -//! -//! - loom page size is fixed (16 KB), and must be a multiple of the -//! system page size. (can the size vary at runtime give south.bin's -//! reversed order? alternately, if system page size > ours, the fault -//! handler could dirty N pages at a time.) -//! - update atomicity is suspect: patch application must either -//! completely succeed or leave on-disk segments intact. unapplied -//! patches can be discarded (triggering event replay), but once -//! patch application begins it must succeed (can fail if disk is full). -//! may require integration into the overall signal-handling regime. -//! - any errors are handled with assertions; failed/partial writes are not -//! retried. -//! -//! ### enhancements -//! -//! - use platform specific page fault mechanism (mach rpc, userfaultfd, &c). -//! - implement demand paging / heuristic page-out. -//! - add a guard page in the middle of the loom to reactively handle stack overflow. -//! - parallelism -//! - -#include "all.h" -#include -#include -#include - -// Base loom offset of the guard page. -static u3p(c3_w) gar_pag_p; - -//! Urbit page size in 4-byte words. -static const size_t pag_wiz_i = 1 << u3a_page; - -//! Urbit page size in bytes. -static const size_t pag_siz_i = sizeof(c3_w) * pag_wiz_i; - -#ifdef U3_SNAPSHOT_VALIDATION -/* Image check. -*/ -struct { - c3_w nor_w; - c3_w sou_w; - c3_w mug_w[u3a_pages]; -} u3K; - -/* _ce_check_page(): checksum page. -*/ -static c3_w -_ce_check_page(c3_w pag_w) -{ - c3_w* mem_w = u3_Loom + (pag_w << u3a_page); - c3_w mug_w = u3r_mug_words(mem_w, (1 << u3a_page)); - - return mug_w; -} - -/* u3e_check(): compute a checksum on all memory within the watermarks. -*/ -void -u3e_check(c3_c* cap_c) -{ - c3_w nor_w = 0; - c3_w sou_w = 0; - - { - c3_w nwr_w, swu_w; - - u3m_water(&nwr_w, &swu_w); - - nor_w = (nwr_w + ((1 << u3a_page) - 1)) >> u3a_page; - sou_w = (swu_w + ((1 << u3a_page) - 1)) >> u3a_page; - } - - /* Count dirty pages. - */ - { - c3_w i_w, sum_w, mug_w; - - sum_w = 0; - for ( i_w = 0; i_w < nor_w; i_w++ ) { - mug_w = _ce_check_page(i_w); - if ( strcmp(cap_c, "boot") ) { - c3_assert(mug_w == u3K.mug_w[i_w]); - } - sum_w += mug_w; - } - for ( i_w = 0; i_w < sou_w; i_w++ ) { - mug_w = _ce_check_page((u3P.pag_w - (i_w + 1))); - if ( strcmp(cap_c, "boot") ) { - c3_assert(mug_w == u3K.mug_w[(u3P.pag_w - (i_w + 1))]); - } - sum_w += mug_w; - } - u3l_log("%s: sum %x (%x, %x)", cap_c, sum_w, nor_w, sou_w); - } -} - -/* _ce_maplloc(): crude off-loom allocator. -*/ -static void* -_ce_maplloc(c3_w len_w) -{ - void* map_v; - - map_v = mmap(0, - len_w, - (PROT_READ | PROT_WRITE), - (MAP_ANON | MAP_PRIVATE), - -1, 0); - - if ( -1 == (c3_ps)map_v ) { - c3_assert(0); - } - else { - c3_w* map_w = map_v; - - map_w[0] = len_w; - - return map_w + 1; - } -} - -/* _ce_mapfree(): crude off-loom allocator. -*/ -static void -_ce_mapfree(void* map_v) -{ - c3_w* map_w = map_v; - c3_i res_i; - - map_w -= 1; - res_i = munmap(map_w, map_w[0]); - - c3_assert(0 == res_i); -} -#endif - -#ifdef U3_GUARD_PAGE -//! Place a guard page at the (approximate) middle of the free space between -//! the heap and stack of the current road, bailing if memory has been -//! exhausted. -static c3_i -_ce_center_guard_page(void) -{ - u3p(c3_w) bot_p, top_p; - if ( !u3R ) { - top_p = u3a_outa(u3_Loom + u3C.wor_i); - bot_p = u3a_outa(u3_Loom); - } - else if ( c3y == u3a_is_north(u3R) ) { - top_p = c3_rod(u3R->cap_p, pag_wiz_i); - bot_p = c3_rop(u3R->hat_p, pag_wiz_i); - } - else { - top_p = c3_rod(u3R->hat_p, pag_wiz_i); - bot_p = c3_rop(u3R->cap_p, pag_wiz_i); - } - - if ( top_p < bot_p + pag_wiz_i ) { - fprintf(stderr, - "loom: not enough memory to recenter the guard page\r\n"); - goto bail; - } - const u3p(c3_w) old_gar_p = gar_pag_p; - const c3_w mid_p = (top_p - bot_p) / 2; - gar_pag_p = bot_p + c3_rod(mid_p, pag_wiz_i); - if ( old_gar_p == gar_pag_p ) { - fprintf(stderr, - "loom: can't move the guard page to the same location" - " (base address %p)\r\n", - u3a_into(gar_pag_p)); - goto bail; - } - - if ( -1 == mprotect(u3a_into(gar_pag_p), pag_siz_i, PROT_NONE) ) { - fprintf(stderr, - "loom: failed to protect the guard page " - "(base address %p): %s\r\n", - u3a_into(gar_pag_p), - strerror(errno)); - goto fail; - } - - return 1; - -bail: - u3m_signal(c3__meme); -fail: - return 0; -} -#endif /* ifdef U3_GUARD_PAGE */ - -/* u3e_fault(): handle a memory event with libsigsegv protocol. -*/ -c3_i -u3e_fault(void* adr_v, c3_i ser_i) -{ - // Let the stack overflow handler run. - if ( 0 == ser_i ) { - return 0; - } - - // XX u3l_log avoid here, as it can - // cause problems when handling errors - - c3_w* adr_w = (c3_w*) adr_v; - - if ( (adr_w < u3_Loom) || (adr_w >= (u3_Loom + u3C.wor_i)) ) { - fprintf(stderr, "address %p out of loom!\r\n", adr_w); - fprintf(stderr, "loom: [%p : %p)\r\n", u3_Loom, u3_Loom + u3C.wor_i); - c3_assert(0); - return 0; - } - - u3p(c3_w) adr_p = u3a_outa(adr_w); - c3_w pag_w = adr_p >> u3a_page; - c3_w blk_w = (pag_w >> 5); - c3_w bit_w = (pag_w & 31); - -#ifdef U3_GUARD_PAGE - // The fault happened in the guard page. - if ( gar_pag_p <= adr_p && adr_p < gar_pag_p + pag_wiz_i ) { - if ( 0 == _ce_center_guard_page() ) { - return 0; - } - } - else -#endif /* ifdef U3_GUARD_PAGE */ - if ( 0 != (u3P.dit_w[blk_w] & (1 << bit_w)) ) { - fprintf(stderr, "strange page: %d, at %p, off %x\r\n", pag_w, adr_w, adr_p); - c3_assert(0); - return 0; - } - - u3P.dit_w[blk_w] |= (1 << bit_w); - - if ( -1 == mprotect((void *)(u3_Loom + (pag_w << u3a_page)), - pag_siz_i, - (PROT_READ | PROT_WRITE)) ) - { - fprintf(stderr, "loom: fault mprotect: %s\r\n", strerror(errno)); - c3_assert(0); - return 0; - } - - return 1; -} - -/* _ce_image_open(): open or create image. -*/ -static c3_o -_ce_image_open(u3e_image* img_u) -{ - c3_i mod_i = O_RDWR | O_CREAT; - c3_c ful_c[8193]; - - snprintf(ful_c, 8192, "%s", u3P.dir_c); - c3_mkdir(ful_c, 0700); - - snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c); - c3_mkdir(ful_c, 0700); - - snprintf(ful_c, 8192, "%s/.urb/chk", u3P.dir_c); - c3_mkdir(ful_c, 0700); - - snprintf(ful_c, 8192, "%s/.urb/chk/%s.bin", u3P.dir_c, img_u->nam_c); - if ( -1 == (img_u->fid_i = c3_open(ful_c, mod_i, 0666)) ) { - fprintf(stderr, "loom: c3_open %s: %s\r\n", ful_c, strerror(errno)); - return c3n; - } - else { - struct stat buf_u; - - if ( -1 == fstat(img_u->fid_i, &buf_u) ) { - fprintf(stderr, "loom: stat %s: %s\r\n", ful_c, strerror(errno)); - c3_assert(0); - return c3n; - } - else { - c3_d siz_d = buf_u.st_size; - c3_d pgs_d = (siz_d + (c3_d)(pag_siz_i - 1)) >> - (c3_d)(u3a_page + 2); - - if ( !siz_d ) { - return c3y; - } - else { - if ( siz_d != (pgs_d << (c3_d)(u3a_page + 2)) ) { - fprintf(stderr, "%s: corrupt size %" PRIx64 "\r\n", ful_c, siz_d); - return c3n; - } - img_u->pgs_w = (c3_w) pgs_d; - c3_assert(pgs_d == (c3_d)img_u->pgs_w); - - return c3y; - } - } - } -} - -/* _ce_patch_write_control(): write control block file. -*/ -static void -_ce_patch_write_control(u3_ce_patch* pat_u) -{ - ssize_t ret_i; - c3_w len_w = sizeof(u3e_control) + - (pat_u->con_u->pgs_w * sizeof(u3e_line)); - - if ( len_w != (ret_i = write(pat_u->ctl_i, pat_u->con_u, len_w)) ) { - if ( 0 < ret_i ) { - fprintf(stderr, "loom: patch ctl partial write: %zu\r\n", (size_t)ret_i); - } - else { - fprintf(stderr, "loom: patch ctl write: %s\r\n", strerror(errno)); - } - c3_assert(0); - } -} - -/* _ce_patch_read_control(): read control block file. -*/ -static c3_o -_ce_patch_read_control(u3_ce_patch* pat_u) -{ - c3_w len_w; - - c3_assert(0 == pat_u->con_u); - { - struct stat buf_u; - - if ( -1 == fstat(pat_u->ctl_i, &buf_u) ) { - c3_assert(0); - return c3n; - } - len_w = (c3_w) buf_u.st_size; - } - - pat_u->con_u = c3_malloc(len_w); - if ( (len_w != read(pat_u->ctl_i, pat_u->con_u, len_w)) || - (len_w != sizeof(u3e_control) + - (pat_u->con_u->pgs_w * sizeof(u3e_line))) ) - { - c3_free(pat_u->con_u); - pat_u->con_u = 0; - return c3n; - } - return c3y; -} - -/* _ce_patch_create(): create patch files. -*/ -static void -_ce_patch_create(u3_ce_patch* pat_u) -{ - c3_c ful_c[8193]; - - snprintf(ful_c, 8192, "%s", u3P.dir_c); - c3_mkdir(ful_c, 0700); - - snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c); - c3_mkdir(ful_c, 0700); - - snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c); - if ( -1 == (pat_u->ctl_i = c3_open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) { - fprintf(stderr, "loom: patch c3_open control.bin: %s\r\n", strerror(errno)); - c3_assert(0); - } - - snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c); - if ( -1 == (pat_u->mem_i = c3_open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) { - fprintf(stderr, "loom: patch c3_open memory.bin: %s\r\n", strerror(errno)); - c3_assert(0); - } -} - -/* _ce_patch_delete(): delete a patch. -*/ -static void -_ce_patch_delete(void) -{ - c3_c ful_c[8193]; - - snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c); - if ( unlink(ful_c) ) { - fprintf(stderr, "loom: failed to delete control.bin: %s\r\n", - strerror(errno)); - } - - snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c); - if ( unlink(ful_c) ) { - fprintf(stderr, "loom: failed to remove memory.bin: %s\r\n", - strerror(errno)); - } -} - -/* _ce_patch_verify(): check patch data mug. -*/ -static c3_o -_ce_patch_verify(u3_ce_patch* pat_u) -{ - ssize_t ret_i; - c3_w i_w; - - if ( u3e_version != pat_u->con_u->ver_y ) { - fprintf(stderr, "loom: patch version mismatch: have %u, need %u\r\n", - pat_u->con_u->ver_y, - u3e_version); - return c3n; - } - - for ( i_w = 0; i_w < pat_u->con_u->pgs_w; i_w++ ) { - c3_w pag_w = pat_u->con_u->mem_u[i_w].pag_w; - c3_w mug_w = pat_u->con_u->mem_u[i_w].mug_w; - c3_w mem_w[1 << u3a_page]; - - if ( -1 == lseek(pat_u->mem_i, (i_w << (u3a_page + 2)), SEEK_SET) ) { - fprintf(stderr, "loom: patch seek: %s\r\n", strerror(errno)); - return c3n; - } - if ( pag_siz_i != (ret_i = read(pat_u->mem_i, mem_w, pag_siz_i)) ) { - if ( 0 < ret_i ) { - fprintf(stderr, "loom: patch partial read: %zu\r\n", (size_t)ret_i); - } - else { - fprintf(stderr, "loom: patch read fail: %s\r\n", strerror(errno)); - } - return c3n; - } - { - c3_w nug_w = u3r_mug_words(mem_w, pag_wiz_i); - - if ( mug_w != nug_w ) { - fprintf(stderr, "loom: patch mug mismatch %d/%d; (%x, %x)\r\n", - pag_w, i_w, mug_w, nug_w); - return c3n; - } -#if 0 - else { - u3l_log("verify: patch %d/%d, %x", pag_w, i_w, mug_w); - } -#endif - } - } - return c3y; -} - -/* _ce_patch_free(): free a patch. -*/ -static void -_ce_patch_free(u3_ce_patch* pat_u) -{ - c3_free(pat_u->con_u); - close(pat_u->ctl_i); - close(pat_u->mem_i); - c3_free(pat_u); -} - -/* _ce_patch_open(): open patch, if any. -*/ -static u3_ce_patch* -_ce_patch_open(void) -{ - u3_ce_patch* pat_u; - c3_c ful_c[8193]; - c3_i ctl_i, mem_i; - - snprintf(ful_c, 8192, "%s", u3P.dir_c); - c3_mkdir(ful_c, 0700); - - snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c); - c3_mkdir(ful_c, 0700); - - snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c); - if ( -1 == (ctl_i = c3_open(ful_c, O_RDWR)) ) { - return 0; - } - - snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c); - if ( -1 == (mem_i = c3_open(ful_c, O_RDWR)) ) { - close(ctl_i); - - _ce_patch_delete(); - return 0; - } - pat_u = c3_malloc(sizeof(u3_ce_patch)); - pat_u->ctl_i = ctl_i; - pat_u->mem_i = mem_i; - pat_u->con_u = 0; - - if ( c3n == _ce_patch_read_control(pat_u) ) { - close(pat_u->ctl_i); - close(pat_u->mem_i); - c3_free(pat_u); - - _ce_patch_delete(); - return 0; - } - if ( c3n == _ce_patch_verify(pat_u) ) { - _ce_patch_free(pat_u); - _ce_patch_delete(); - return 0; - } - return pat_u; -} - -/* _ce_patch_write_page(): write a page of patch memory. -*/ -static void -_ce_patch_write_page(u3_ce_patch* pat_u, - c3_w pgc_w, - c3_w* mem_w) -{ - ssize_t ret_i; - - if ( -1 == lseek(pat_u->mem_i, pgc_w * pag_siz_i, SEEK_SET) ) { - fprintf(stderr, "loom: patch page seek: %s\r\n", strerror(errno)); - c3_assert(0); - } - - if ( pag_siz_i != (ret_i = write(pat_u->mem_i, mem_w, pag_siz_i)) ) { - if ( 0 < ret_i ) { - fprintf(stderr, "loom: patch page partial write: %zu\r\n", - (size_t)ret_i); - } - else { - fprintf(stderr, "loom: patch page write: %s\r\n", strerror(errno)); - } - c3_assert(0); - } -} - -/* _ce_patch_count_page(): count a page, producing new counter. -*/ -static c3_w -_ce_patch_count_page(c3_w pag_w, - c3_w pgc_w) -{ - c3_w blk_w = (pag_w >> 5); - c3_w bit_w = (pag_w & 31); - - if ( u3P.dit_w[blk_w] & (1 << bit_w) ) { - pgc_w += 1; - } - return pgc_w; -} - -/* _ce_patch_save_page(): save a page, producing new page counter. -*/ -static c3_w -_ce_patch_save_page(u3_ce_patch* pat_u, - c3_w pag_w, - c3_w pgc_w) -{ - c3_w blk_w = (pag_w >> 5); - c3_w bit_w = (pag_w & 31); - - if ( u3P.dit_w[blk_w] & (1 << bit_w) ) { - c3_w* mem_w = u3_Loom + (pag_w << u3a_page); - - pat_u->con_u->mem_u[pgc_w].pag_w = pag_w; - pat_u->con_u->mem_u[pgc_w].mug_w = u3r_mug_words(mem_w, pag_wiz_i); - -#if 0 - u3l_log("protect a: page %d\r\n", pag_w); -#endif - _ce_patch_write_page(pat_u, pgc_w, mem_w); - - if ( -1 == mprotect(u3_Loom + (pag_w << u3a_page), - pag_siz_i, - PROT_READ) ) - { - fprintf(stderr, "loom: patch mprotect: %s\r\n", strerror(errno)); - c3_assert(0); - } - - u3P.dit_w[blk_w] &= ~(1 << bit_w); - pgc_w += 1; - } - return pgc_w; -} - -/* _ce_patch_compose(): make and write current patch. -*/ -static u3_ce_patch* -_ce_patch_compose(void) -{ - c3_w pgs_w = 0; - c3_w nor_w = 0; - c3_w sou_w = 0; - - /* Calculate number of saved pages, north and south. - */ - { - c3_w nwr_w, swu_w; - - u3m_water(&nwr_w, &swu_w); - - nor_w = (nwr_w + (pag_wiz_i - 1)) >> u3a_page; - sou_w = (swu_w + (pag_wiz_i - 1)) >> u3a_page; - - c3_assert( ((gar_pag_p >> u3a_page) >= nor_w) - && ((gar_pag_p >> u3a_page) <= (u3a_pages - (sou_w + 1))) ); - } - -#ifdef U3_SNAPSHOT_VALIDATION - u3K.nor_w = nor_w; - u3K.sou_w = sou_w; -#endif - - /* Count dirty pages. - */ - { - c3_w i_w; - - for ( i_w = 0; i_w < nor_w; i_w++ ) { - pgs_w = _ce_patch_count_page(i_w, pgs_w); - } - for ( i_w = 0; i_w < sou_w; i_w++ ) { - pgs_w = _ce_patch_count_page((u3P.pag_w - (i_w + 1)), pgs_w); - } - } - - if ( !pgs_w ) { - return 0; - } - else { - u3_ce_patch* pat_u = c3_malloc(sizeof(u3_ce_patch)); - c3_w i_w, pgc_w; - - _ce_patch_create(pat_u); - pat_u->con_u = c3_malloc(sizeof(u3e_control) + (pgs_w * sizeof(u3e_line))); - pat_u->con_u->ver_y = u3e_version; - pgc_w = 0; - - for ( i_w = 0; i_w < nor_w; i_w++ ) { - pgc_w = _ce_patch_save_page(pat_u, i_w, pgc_w); - } - for ( i_w = 0; i_w < sou_w; i_w++ ) { - pgc_w = _ce_patch_save_page(pat_u, (u3P.pag_w - (i_w + 1)), pgc_w); - } - - pat_u->con_u->nor_w = nor_w; - pat_u->con_u->sou_w = sou_w; - pat_u->con_u->pgs_w = pgc_w; - - _ce_patch_write_control(pat_u); - return pat_u; - } -} - -/* _ce_patch_sync(): make sure patch is synced to disk. -*/ -static void -_ce_patch_sync(u3_ce_patch* pat_u) -{ - if ( -1 == c3_sync(pat_u->ctl_i) ) { - fprintf(stderr, "loom: control file sync failed: %s\r\n", - strerror(errno)); - c3_assert(!"loom: control sync"); - } - - if ( -1 == c3_sync(pat_u->mem_i) ) { - fprintf(stderr, "loom: patch file sync failed: %s\r\n", - strerror(errno)); - c3_assert(!"loom: patch sync"); - } -} - -/* _ce_image_sync(): make sure image is synced to disk. -*/ -static void -_ce_image_sync(u3e_image* img_u) -{ - if ( -1 == c3_sync(img_u->fid_i) ) { - fprintf(stderr, "loom: image (%s) sync failed: %s\r\n", - img_u->nam_c, - strerror(errno)); - c3_assert(!"loom: image sync"); - } -} - -/* _ce_image_resize(): resize image, truncating if it shrunk. -*/ -static void -_ce_image_resize(u3e_image* img_u, c3_w pgs_w) -{ - if ( img_u->pgs_w > pgs_w ) { - if ( ftruncate(img_u->fid_i, pgs_w << (u3a_page + 2)) ) { - fprintf(stderr, "loom: image (%s) truncate: %s\r\n", - img_u->nam_c, - strerror(errno)); - c3_assert(0); - } - } - - img_u->pgs_w = pgs_w; -} - -/* _ce_patch_apply(): apply patch to images. -*/ -static void -_ce_patch_apply(u3_ce_patch* pat_u) -{ - ssize_t ret_i; - c3_w i_w; - - // resize images - // - _ce_image_resize(&u3P.nor_u, pat_u->con_u->nor_w); - _ce_image_resize(&u3P.sou_u, pat_u->con_u->sou_w); - - // seek to begining of patch and images - // - if ( (-1 == lseek(pat_u->mem_i, 0, SEEK_SET)) - || (-1 == lseek(u3P.nor_u.fid_i, 0, SEEK_SET)) - || (-1 == lseek(u3P.sou_u.fid_i, 0, SEEK_SET)) ) - { - fprintf(stderr, "loom: patch apply seek 0: %s\r\n", strerror(errno)); - c3_assert(0); - } - - // write patch pages into the appropriate image - // - for ( i_w = 0; i_w < pat_u->con_u->pgs_w; i_w++ ) { - c3_w pag_w = pat_u->con_u->mem_u[i_w].pag_w; - c3_w mem_w[pag_wiz_i]; - c3_i fid_i; - c3_w off_w; - - if ( pag_w < pat_u->con_u->nor_w ) { - fid_i = u3P.nor_u.fid_i; - off_w = pag_w; - } - else { - fid_i = u3P.sou_u.fid_i; - off_w = (u3P.pag_w - (pag_w + 1)); - } - - if ( pag_siz_i != (ret_i = read(pat_u->mem_i, mem_w, pag_siz_i)) ) { - if ( 0 < ret_i ) { - fprintf(stderr, "loom: patch apply partial read: %zu\r\n", - (size_t)ret_i); - } - else { - fprintf(stderr, "loom: patch apply read: %s\r\n", strerror(errno)); - } - c3_assert(0); - } - else { - if ( -1 == lseek(fid_i, (off_w << (u3a_page + 2)), SEEK_SET) ) { - fprintf(stderr, "loom: patch apply seek: %s\r\n", strerror(errno)); - c3_assert(0); - } - if ( pag_siz_i != (ret_i = write(fid_i, mem_w, pag_siz_i)) ) { - if ( 0 < ret_i ) { - fprintf(stderr, "loom: patch apply partial write: %zu\r\n", - (size_t)ret_i); - } - else { - fprintf(stderr, "loom: patch apply write: %s\r\n", strerror(errno)); - } - c3_assert(0); - } - } -#if 0 - u3l_log("apply: %d, %x", pag_w, u3r_mug_words(mem_w, pag_wiz_i)); -#endif - } -} - -/* _ce_image_blit(): apply image to memory. -*/ -static void -_ce_image_blit(u3e_image* img_u, - c3_w* ptr_w, - c3_ws stp_ws) -{ - if ( 0 == img_u->pgs_w ) { - return; - } - - ssize_t ret_i; - c3_w i_w; - c3_w siz_w = pag_siz_i; - - if ( -1 == lseek(img_u->fid_i, 0, SEEK_SET) ) { - fprintf(stderr, "loom: image (%s) blit seek 0: %s\r\n", - img_u->nam_c, strerror(errno)); - c3_assert(0); - } - - for ( i_w = 0; i_w < img_u->pgs_w; i_w++ ) { - if ( siz_w != (ret_i = read(img_u->fid_i, ptr_w, siz_w)) ) { - if ( 0 < ret_i ) { - fprintf(stderr, "loom: image (%s) blit partial read: %zu\r\n", - img_u->nam_c, (size_t)ret_i); - } - else { - fprintf(stderr, "loom: image (%s) blit read: %s\r\n", - img_u->nam_c, strerror(errno)); - } - c3_assert(0); - } - - if ( 0 != mprotect(ptr_w, siz_w, PROT_READ) ) { - fprintf(stderr, "loom: live mprotect: %s\r\n", strerror(errno)); - c3_assert(0); - } - - c3_w pag_w = u3a_outa(ptr_w) >> u3a_page; - c3_w blk_w = pag_w >> 5; - c3_w bit_w = pag_w & 31; - u3P.dit_w[blk_w] &= ~(1 << bit_w); - - ptr_w += stp_ws; - } -} - -#ifdef U3_SNAPSHOT_VALIDATION -/* _ce_image_fine(): compare image to memory. -*/ -static void -_ce_image_fine(u3e_image* img_u, - c3_w* ptr_w, - c3_ws stp_ws) -{ - ssize_t ret_i; - c3_w i_w; - c3_w buf_w[pag_wiz_i]; - - if ( -1 == lseek(img_u->fid_i, 0, SEEK_SET) ) { - fprintf(stderr, "loom: image fine seek 0: %s\r\n", strerror(errno)); - c3_assert(0); - } - - for ( i_w=0; i_w < img_u->pgs_w; i_w++ ) { - c3_w mem_w, fil_w; - - if ( pag_siz_i != (ret_i = read(img_u->fid_i, buf_w, pag_siz_i)) ) { - if ( 0 < ret_i ) { - fprintf(stderr, "loom: image (%s) fine partial read: %zu\r\n", - img_u->nam_c, (size_t)ret_i); - } - else { - fprintf(stderr, "loom: image (%s) fine read: %s\r\n", - img_u->nam_c, strerror(errno)); - } - c3_assert(0); - } - mem_w = u3r_mug_words(ptr_w, pag_wiz_i); - fil_w = u3r_mug_words(buf_w, pag_wiz_i); - - if ( mem_w != fil_w ) { - c3_w pag_w = (ptr_w - u3_Loom) >> u3a_page; - - fprintf(stderr, "loom: image (%s) mismatch: " - "page %d, mem_w %x, fil_w %x, K %x\r\n", - img_u->nam_c, - pag_w, - mem_w, - fil_w, - u3K.mug_w[pag_w]); - abort(); - } - ptr_w += stp_ws; - } -} -#endif - -/* _ce_image_copy(): -*/ -static c3_o -_ce_image_copy(u3e_image* fom_u, u3e_image* tou_u) -{ - ssize_t ret_i; - c3_w i_w; - - // resize images - // - _ce_image_resize(tou_u, fom_u->pgs_w); - - // seek to begining of patch and images - // - if ( (-1 == lseek(fom_u->fid_i, 0, SEEK_SET)) - || (-1 == lseek(tou_u->fid_i, 0, SEEK_SET)) ) - { - fprintf(stderr, "loom: image (%s) copy seek: %s\r\n", - fom_u->nam_c, - strerror(errno)); - return c3n; - } - - // copy pages into destination image - // - for ( i_w = 0; i_w < fom_u->pgs_w; i_w++ ) { - c3_w mem_w[pag_wiz_i]; - c3_w off_w = i_w; - - if ( pag_siz_i != (ret_i = read(fom_u->fid_i, mem_w, pag_siz_i)) ) { - if ( 0 < ret_i ) { - fprintf(stderr, "loom: image (%s) copy partial read: %zu\r\n", - fom_u->nam_c, (size_t)ret_i); - } - else { - fprintf(stderr, "loom: image (%s) copy read: %s\r\n", - fom_u->nam_c, strerror(errno)); - } - return c3n; - } - else { - if ( -1 == lseek(tou_u->fid_i, (off_w << (u3a_page + 2)), SEEK_SET) ) { - fprintf(stderr, "loom: image (%s) copy seek: %s\r\n", - tou_u->nam_c, strerror(errno)); - return c3n; - } - if ( pag_siz_i != (ret_i = write(tou_u->fid_i, mem_w, pag_siz_i)) ) { - if ( 0 < ret_i ) { - fprintf(stderr, "loom: image (%s) copy partial write: %zu\r\n", - tou_u->nam_c, (size_t)ret_i); - } - else { - fprintf(stderr, "loom: image (%s) copy write: %s\r\n", - tou_u->nam_c, strerror(errno)); - } - return c3n; - } - } - } - - return c3y; -} - -/* _ce_backup(); -*/ -static void -_ce_backup(void) -{ - u3e_image nop_u = { .nam_c = "north", .pgs_w = 0 }; - u3e_image sop_u = { .nam_c = "south", .pgs_w = 0 }; - c3_i mod_i = O_RDWR | O_CREAT; - c3_c ful_c[8193]; - - snprintf(ful_c, 8192, "%s/.urb/bhk", u3P.dir_c); - - if ( c3_mkdir(ful_c, 0700) ) { - if ( EEXIST != errno ) { - fprintf(stderr, "loom: image backup: %s\r\n", strerror(errno)); - } - return; - } - - snprintf(ful_c, 8192, "%s/.urb/bhk/%s.bin", u3P.dir_c, nop_u.nam_c); - - if ( -1 == (nop_u.fid_i = c3_open(ful_c, mod_i, 0666)) ) { - fprintf(stderr, "loom: c3_open %s: %s\r\n", ful_c, strerror(errno)); - return; - } - - snprintf(ful_c, 8192, "%s/.urb/bhk/%s.bin", u3P.dir_c, sop_u.nam_c); - - if ( -1 == (sop_u.fid_i = c3_open(ful_c, mod_i, 0666)) ) { - fprintf(stderr, "loom: c3_open %s: %s\r\n", ful_c, strerror(errno)); - return; - } - - if ( (c3n == _ce_image_copy(&u3P.nor_u, &nop_u)) - || (c3n == _ce_image_copy(&u3P.sou_u, &sop_u)) ) - { - - c3_unlink(ful_c); - snprintf(ful_c, 8192, "%s/.urb/bhk/%s.bin", u3P.dir_c, nop_u.nam_c); - c3_unlink(ful_c); - snprintf(ful_c, 8192, "%s/.urb/bhk", u3P.dir_c); - c3_rmdir(ful_c); - } - - close(nop_u.fid_i); - close(sop_u.fid_i); -} - -/* - u3e_save(): save current changes. - - If we are in dry-run mode, do nothing. - - First, call `_ce_patch_compose` to write all dirty pages to disk and - clear protection and dirty bits. If there were no dirty pages to write, - then we're done. - - - Sync the patch files to disk. - - Verify the patch (because why not?) - - Write the patch data into the image file (This is idempotent.). - - Sync the image file. - - Delete the patchfile and free it. - - Once we've written the dirty pages to disk (and have reset their dirty bits - and protection flags), we *could* handle the rest of the checkpointing - process in a separate thread, but we'd need to wait until that finishes - before we try to make another snapshot. -*/ -void -u3e_save(void) -{ - u3_ce_patch* pat_u; - - if ( u3C.wag_w & u3o_dryrun ) { - return; - } - - if ( !(pat_u = _ce_patch_compose()) ) { - return; - } - - // u3a_print_memory(stderr, "sync: save", 4096 * pat_u->con_u->pgs_w); - - _ce_patch_sync(pat_u); - - if ( c3n == _ce_patch_verify(pat_u) ) { - c3_assert(!"loom: save failed"); - } - - _ce_patch_apply(pat_u); - -#ifdef U3_SNAPSHOT_VALIDATION - { - _ce_image_fine(&u3P.nor_u, - u3_Loom, - pag_wiz_i); - - _ce_image_fine(&u3P.sou_u, - (u3_Loom + u3C.wor_i) - pag_wiz_i, - -(ssize_t)pag_wiz_i); - - c3_assert(u3P.nor_u.pgs_w == u3K.nor_w); - c3_assert(u3P.sou_u.pgs_w == u3K.sou_w); - } -#endif - - _ce_image_sync(&u3P.nor_u); - _ce_image_sync(&u3P.sou_u); - _ce_patch_free(pat_u); - _ce_patch_delete(); - - _ce_backup(); -} - -/* u3e_live(): start the checkpointing system. -*/ -c3_o -u3e_live(c3_o nuu_o, c3_c* dir_c) -{ - // require that our page size is a multiple of the system page size. - // - { - size_t sys_i = sysconf(_SC_PAGESIZE); - - if ( pag_siz_i % sys_i ) { - fprintf(stderr, "loom: incompatible system page size (%zuKB)\r\n", - sys_i >> 10); - exit(1); - } - } - - u3P.dir_c = dir_c; - u3P.nor_u.nam_c = "north"; - u3P.sou_u.nam_c = "south"; - u3P.pag_w = u3C.wor_i >> u3a_page; - - // XX review dryrun requirements, enable or remove - // -#if 0 - if ( u3C.wag_w & u3o_dryrun ) { - return c3y; - } else -#endif - { - // Open image files. - // - if ( (c3n == _ce_image_open(&u3P.nor_u)) || - (c3n == _ce_image_open(&u3P.sou_u)) ) - { - fprintf(stderr, "boot: image failed\r\n"); - exit(1); - } - else { - u3_ce_patch* pat_u; - - /* Load any patch files; apply them to images. - */ - if ( 0 != (pat_u = _ce_patch_open()) ) { - _ce_patch_apply(pat_u); - _ce_image_sync(&u3P.nor_u); - _ce_image_sync(&u3P.sou_u); - _ce_patch_free(pat_u); - _ce_patch_delete(); - } - - // detect snapshots from a larger loom - // - if ( (u3P.nor_u.pgs_w + u3P.sou_u.pgs_w + 1) >= u3a_pages ) { - fprintf(stderr, "boot: snapshot too big for loom\r\n"); - exit(1); - } - - // mark all pages dirty (pages in the snapshot will be marked clean) - // - u3e_foul(); - - /* Write image files to memory; reinstate protection. - */ - { - _ce_image_blit(&u3P.nor_u, - u3_Loom, - pag_wiz_i); - - _ce_image_blit(&u3P.sou_u, - (u3_Loom + u3C.wor_i) - pag_wiz_i, - -(ssize_t)pag_wiz_i); - - u3l_log("boot: protected loom"); - } - - /* If the images were empty, we are logically booting. - */ - if ( (0 == u3P.nor_u.pgs_w) && (0 == u3P.sou_u.pgs_w) ) { - u3l_log("live: logical boot"); - nuu_o = c3y; - } - else { - u3a_print_memory(stderr, "live: loaded", - (u3P.nor_u.pgs_w + u3P.sou_u.pgs_w) << u3a_page); - } - } - } - - return nuu_o; -} - -/* u3e_yolo(): disable dirty page tracking, read/write whole loom. -*/ -c3_o -u3e_yolo(void) -{ - // NB: u3e_save() will reinstate protection flags - // - if ( 0 != mprotect((void *)u3_Loom, - u3C.wor_i << 2, - (PROT_READ | PROT_WRITE)) ) - { - // XX confirm recoverable errors - // - fprintf(stderr, "loom: yolo: %s\r\n", strerror(errno)); - return c3n; - } - - if ( 0 != mprotect(u3a_into(gar_pag_p), pag_siz_i, PROT_NONE) ) { - fprintf(stderr, "loom: failed to protect guard page: %s\r\n", - strerror(errno)); - c3_assert(0); - } - - return c3y; -} - -/* u3e_foul(): dirty all the pages of the loom. -*/ -void -u3e_foul(void) -{ - memset((void*)u3P.dit_w, 0xff, sizeof(u3P.dit_w)); -} - -/* u3e_init(): initialize guard page tracking. -*/ -void -u3e_init(void) -{ - u3P.pag_w = u3C.wor_i >> u3a_page; - -#ifdef U3_GUARD_PAGE - _ce_center_guard_page(); -#endif -} - -/* u3e_ward(): reposition guard page if needed. -*/ -void -u3e_ward(u3_post low_p, u3_post hig_p) -{ -#ifdef U3_GUARD_PAGE - if ( (low_p > gar_pag_p) || (hig_p < gar_pag_p) ) { - _ce_center_guard_page(); - } -#endif -} diff --git a/pkg/urbit/noun/hashtable.c b/pkg/urbit/noun/hashtable.c deleted file mode 100644 index 63b3df87f..000000000 --- a/pkg/urbit/noun/hashtable.c +++ /dev/null @@ -1,1223 +0,0 @@ -/* g/h.c -** -*/ -#include "all.h" - -/* CUT_END(): extract [b_w] low bits from [a_w] -*/ -#define CUT_END(a_w, b_w) (a_w & ((1 << b_w) - 1)) - -/* BIT_SET(): [1] if bit [b_w] is set in [a_w] -*/ -#define BIT_SET(a_w, b_w) (a_w & (1 << b_w)) - -static c3_o -_ch_trim_slot(u3h_root* har_u, u3h_slot *sot_w, c3_w lef_w, c3_w rem_w); - -c3_w -_ch_skip_slot(c3_w mug_w, c3_w lef_w); - -/* u3h_new_cache(): create hashtable with bounded size. -*/ -u3p(u3h_root) -u3h_new_cache(c3_w max_w) -{ - u3h_root* har_u = u3a_walloc(c3_wiseof(u3h_root)); - u3p(u3h_root) har_p = u3of(u3h_root, har_u); - c3_w i_w; - - har_u->max_w = max_w; - har_u->use_w = 0; - har_u->arm_u.mug_w = 0; - har_u->arm_u.inx_w = 0; - - for ( i_w = 0; i_w < 64; i_w++ ) { - har_u->sot_w[i_w] = 0; - } - return har_p; -} - -/* u3h_new(): create hashtable. -*/ -u3p(u3h_root) -u3h_new(void) -{ - return u3h_new_cache(0); -} - -/* _ch_popcount(): number of bits set in word. A standard intrinsic. -*/ -static c3_w -_ch_popcount(c3_w num_w) -{ - return __builtin_popcount(num_w); -} - -/* _ch_buck_new(): create new bucket. -*/ -static u3h_buck* -_ch_buck_new(c3_w len_w) -{ - u3h_buck* hab_u = u3a_walloc(c3_wiseof(u3h_buck) + - (len_w * c3_wiseof(u3h_slot))); - hab_u->len_w = len_w; - return hab_u; -} - -/* _ch_node_new(): create new node. -*/ -static u3h_node* -_ch_node_new(c3_w len_w) -{ - u3h_node* han_u = u3a_walloc(c3_wiseof(u3h_node) + - (len_w * c3_wiseof(u3h_slot))); - han_u->map_w = 0; - return han_u; -} - -static void _ch_slot_put(u3h_slot*, u3_noun, c3_w, c3_w, c3_w*); - -/* _ch_node_add(): add to node. -*/ -static u3h_node* -_ch_node_add(u3h_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun kev, c3_w *use_w) -{ - c3_w bit_w, inx_w, map_w, i_w; - - lef_w -= 5; - bit_w = (rem_w >> lef_w); - rem_w = CUT_END(rem_w, lef_w); - map_w = han_u->map_w; - inx_w = _ch_popcount(CUT_END(map_w, bit_w)); - - if ( BIT_SET(map_w, bit_w) ) { - _ch_slot_put(&(han_u->sot_w[inx_w]), kev, lef_w, rem_w, use_w); - return han_u; - } - else { - // nothing was at this slot. - // Optimize: use u3a_wealloc. - // - c3_w len_w = _ch_popcount(map_w); - u3h_node* nah_u = _ch_node_new(1 + len_w); - nah_u->map_w = han_u->map_w | (1 << bit_w); - - for ( i_w = 0; i_w < inx_w; i_w++ ) { - nah_u->sot_w[i_w] = han_u->sot_w[i_w]; - } - nah_u->sot_w[inx_w] = u3h_noun_be_warm(u3h_noun_to_slot(kev)); - for ( i_w = inx_w; i_w < len_w; i_w++ ) { - nah_u->sot_w[i_w + 1] = han_u->sot_w[i_w]; - } - - u3a_wfree(han_u); - *use_w += 1; - return nah_u; - } -} - -/* ch_buck_add(): add to bucket. -*/ -static u3h_buck* -_ch_buck_add(u3h_buck* hab_u, u3_noun kev, c3_w *use_w) -{ - c3_w i_w; - - // if our key is equal to any of the existing keys in the bucket, - // then replace that key-value pair with kev. - // - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - u3_noun kov = u3h_slot_to_noun(hab_u->sot_w[i_w]); - if ( c3y == u3r_sing(u3h(kev), u3h(kov)) ) { - hab_u->sot_w[i_w] = u3h_noun_to_slot(kev); - u3z(kov); - return hab_u; - } - } - - // create mutant bucket with added key-value pair. - // Optimize: use u3a_wealloc(). - { - u3h_buck* bah_u = _ch_buck_new(1 + hab_u->len_w); - bah_u->sot_w[0] = u3h_noun_be_warm(u3h_noun_to_slot(kev)); - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - bah_u->sot_w[i_w + 1] = hab_u->sot_w[i_w]; - } - - u3a_wfree(hab_u); - *use_w += 1; - return bah_u; - } -} - -/* _ch_some_add(): add to node or bucket. -*/ -static void* -_ch_some_add(void* han_v, c3_w lef_w, c3_w rem_w, u3_noun kev, c3_w *use_w) -{ - if ( 0 == lef_w ) { - return _ch_buck_add((u3h_buck*)han_v, kev, use_w); - } - else return _ch_node_add((u3h_node*)han_v, lef_w, rem_w, kev, use_w); -} - -/* _ch_two(): create a new node with two leaves underneath -*/ -u3h_slot -_ch_two(u3h_slot had_w, u3h_slot add_w, c3_w lef_w, c3_w ham_w, c3_w mad_w) -{ - void* ret; - - if ( 0 == lef_w ) { - u3h_buck* hab_u = _ch_buck_new(2); - ret = hab_u; - hab_u->sot_w[0] = had_w; - hab_u->sot_w[1] = add_w; - } - else { - c3_w hop_w, tad_w; - lef_w -= 5; - hop_w = ham_w >> lef_w; - tad_w = mad_w >> lef_w; - if ( hop_w == tad_w ) { - // fragments collide: store in a child node. - u3h_node* han_u = _ch_node_new(1); - ret = han_u; - han_u->map_w = 1 << hop_w; - ham_w = CUT_END(ham_w, lef_w); - mad_w = CUT_END(mad_w, lef_w); - han_u->sot_w[0] = _ch_two(had_w, add_w, lef_w, ham_w, mad_w); - } - else { - u3h_node* han_u = _ch_node_new(2); - ret = han_u; - han_u->map_w = (1 << hop_w) | (1 << tad_w); - // smaller mug fragments go in earlier slots - if ( hop_w < tad_w ) { - han_u->sot_w[0] = had_w; - han_u->sot_w[1] = add_w; - } - else { - han_u->sot_w[0] = add_w; - han_u->sot_w[1] = had_w; - } - } - } - - return u3h_node_to_slot(ret); -} - -/* _ch_slot_put(): store a key-value pair in a non-null slot -*/ -static void -_ch_slot_put(u3h_slot* sot_w, u3_noun kev, c3_w lef_w, c3_w rem_w, c3_w* use_w) -{ - if ( c3n == u3h_slot_is_noun(*sot_w) ) { - void* hav_v = _ch_some_add(u3h_slot_to_node(*sot_w), - lef_w, - rem_w, - kev, - use_w); - - c3_assert( c3y == u3h_slot_is_node(*sot_w) ); - *sot_w = u3h_node_to_slot(hav_v); - } - else { - u3_noun kov = u3h_slot_to_noun(*sot_w); - u3h_slot add_w = u3h_noun_be_warm(u3h_noun_to_slot(kev)); - if ( c3y == u3r_sing(u3h(kev), u3h(kov)) ) { - // replace old value - u3z(kov); - *sot_w = add_w; - } - else { - c3_w ham_w = CUT_END(u3r_mug(u3h(kov)), lef_w); - *sot_w = _ch_two(*sot_w, add_w, lef_w, ham_w, rem_w); - *use_w += 1; - } - } -} - -/* u3h_put(): insert in hashtable. -** -** `key` is RETAINED; `val` is transferred. -*/ -void -u3h_put(u3p(u3h_root) har_p, u3_noun key, u3_noun val) -{ - u3h_root* har_u = u3to(u3h_root, har_p); - u3_noun kev = u3nc(u3k(key), val); - c3_w mug_w = u3r_mug(key); - c3_w inx_w = (mug_w >> 25); // 6 bits - c3_w rem_w = CUT_END(mug_w, 25); - u3h_slot* sot_w = &(har_u->sot_w[inx_w]); - - if ( c3y == u3h_slot_is_null(*sot_w) ) { - *sot_w = u3h_noun_be_warm(u3h_noun_to_slot(kev)); - har_u->use_w += 1; - } - else { - _ch_slot_put(sot_w, kev, 25, rem_w, &(har_u->use_w)); - } - - if ( har_u->max_w > 0 ) { - u3h_trim_to(har_p, har_u->max_w); - } -} - -/* _ch_uni_with(): key/value callback, put into [*wit] -*/ -static void -_ch_uni_with(u3_noun kev, void* wit) -{ - u3p(u3h_root) har_p = *(u3p(u3h_root)*)wit; - u3_noun key, val; - u3x_cell(kev, &key, &val); - - u3h_put(har_p, key, u3k(val)); -} - -/* u3h_uni(): unify hashtables, copying [rah_p] into [har_p] -*/ -void -u3h_uni(u3p(u3h_root) har_p, u3p(u3h_root) rah_p) -{ - u3h_walk_with(rah_p, _ch_uni_with, &har_p); -} - -/* _ch_trim_node(): trim one entry from a node slot or its children -*/ -static c3_o -_ch_trim_node(u3h_root* har_u, u3h_slot* sot_w, c3_w lef_w, c3_w rem_w) -{ - c3_w bit_w, map_w, inx_w; - u3h_slot* tos_w; - u3h_node* han_u = (u3h_node*) u3h_slot_to_node(*sot_w); - - lef_w -= 5; - bit_w = (rem_w >> lef_w); - map_w = han_u->map_w; - - if ( !BIT_SET(map_w, bit_w) ) { - har_u->arm_u.mug_w = _ch_skip_slot(har_u->arm_u.mug_w, lef_w); - return c3n; - } - - rem_w = CUT_END(rem_w, lef_w); - inx_w = _ch_popcount(CUT_END(map_w, bit_w)); - tos_w = &(han_u->sot_w[inx_w]); - - if ( c3n == _ch_trim_slot(har_u, tos_w, lef_w, rem_w) ) { - // nothing trimmed - return c3n; - } - else if ( 0 != *tos_w ) { - // something trimmed, but slot still has value - return c3y; - } - else { - // shrink! - c3_w i_w, ken_w, len_w = _ch_popcount(map_w); - u3h_slot kes_w; - - if ( 2 == len_w && ((ken_w = (0 == inx_w) ? 1 : 0), - (kes_w = han_u->sot_w[ken_w]), - (c3y == u3h_slot_is_noun(kes_w))) ) { - // only one side left, and the other is a noun. debucketize. - *sot_w = kes_w; - u3a_wfree(han_u); - } - else { - // shrink node in place; don't reallocate, we could be low on memory - // - han_u->map_w &= ~(1 << bit_w); - --len_w; - - for ( i_w = inx_w; i_w < len_w; i_w++ ) { - han_u->sot_w[i_w] = han_u->sot_w[i_w + 1]; - } - } - return c3y; - } -} - -/* _ch_trim_kev(): trim a single entry slot -*/ -static c3_o -_ch_trim_kev(u3h_slot *sot_w) -{ - if ( _(u3h_slot_is_warm(*sot_w)) ) { - *sot_w = u3h_noun_be_cold(*sot_w); - return c3n; - } - else { - u3_noun kev = u3h_slot_to_noun(*sot_w); - *sot_w = 0; - u3z(kev); - return c3y; - } -} - -/* _ch_trim_node(): trim one entry from a bucket slot -*/ -static c3_o -_ch_trim_buck(u3h_root* har_u, u3h_slot* sot_w) -{ - c3_w i_w, len_w; - u3h_buck* hab_u = u3h_slot_to_node(*sot_w); - - for ( len_w = hab_u->len_w; - har_u->arm_u.inx_w < len_w; - har_u->arm_u.inx_w += 1 ) - { - if ( c3y == _ch_trim_kev(&(hab_u->sot_w[har_u->arm_u.inx_w])) ) { - if ( 2 == len_w ) { - // 2 things in bucket: debucketize to key-value pair, the next - // run will point at this pair (same mug_w, no longer in bucket) - *sot_w = hab_u->sot_w[ (0 == har_u->arm_u.inx_w) ? 1 : 0 ]; - u3a_wfree(hab_u); - har_u->arm_u.inx_w = 0; - } - else { - // shrink bucket in place; don't reallocate, we could be low on memory - hab_u->len_w = --len_w; - - for ( i_w = har_u->arm_u.inx_w; i_w < len_w; ++i_w ) { - hab_u->sot_w[i_w] = hab_u->sot_w[i_w + 1]; - } - // leave the arm pointing at the next index in the bucket - ++(har_u->arm_u.inx_w); - } - return c3y; - } - } - - har_u->arm_u.mug_w = (har_u->arm_u.mug_w + 1) & 0x7FFFFFFF; // modulo 2^31 - har_u->arm_u.inx_w = 0; - return c3n; -} - -/* _ch_trim_some(): trim one entry from a bucket or node slot -*/ -static c3_o -_ch_trim_some(u3h_root* har_u, u3h_slot* sot_w, c3_w lef_w, c3_w rem_w) -{ - if ( 0 == lef_w ) { - return _ch_trim_buck(har_u, sot_w); - } - else { - return _ch_trim_node(har_u, sot_w, lef_w, rem_w); - } -} - -/* _ch_skip_slot(): increment arm over hash prefix. -*/ -c3_w -_ch_skip_slot(c3_w mug_w, c3_w lef_w) -{ - c3_w hig_w = mug_w >> lef_w; - c3_w new_w = CUT_END(hig_w + 1, (31 - lef_w)); // modulo 2^(31 - lef_w) - return new_w << lef_w; -} - -/* _ch_trim_slot(): trim one entry from a non-bucket slot -*/ -static c3_o -_ch_trim_slot(u3h_root* har_u, u3h_slot *sot_w, c3_w lef_w, c3_w rem_w) -{ - if ( c3y == u3h_slot_is_noun(*sot_w) ) { - har_u->arm_u.mug_w = _ch_skip_slot(har_u->arm_u.mug_w, lef_w); - return _ch_trim_kev(sot_w); - } - else { - return _ch_trim_some(har_u, sot_w, lef_w, rem_w); - } -} - -/* _ch_trim_root(): trim one entry from a hashtable -*/ -static c3_o -_ch_trim_root(u3h_root* har_u) -{ - c3_w mug_w = har_u->arm_u.mug_w; - c3_w inx_w = mug_w >> 25; // 6 bits - u3h_slot* sot_w = &(har_u->sot_w[inx_w]); - - if ( c3y == u3h_slot_is_null(*sot_w) ) { - har_u->arm_u.mug_w = _ch_skip_slot(har_u->arm_u.mug_w, 25); - return c3n; - } - - return _ch_trim_slot(har_u, sot_w, 25, CUT_END(mug_w, 25)); -} - -/* u3h_trim_to(): trim to n key-value pairs -*/ -void -u3h_trim_to(u3p(u3h_root) har_p, c3_w n_w) -{ - u3h_root* har_u = u3to(u3h_root, har_p); - - while ( har_u->use_w > n_w ) { - if ( c3y == _ch_trim_root(har_u) ) { - har_u->use_w -= 1; - } - } -} - -/* _ch_buck_hum(): read in bucket. -*/ -static c3_o -_ch_buck_hum(u3h_buck* hab_u, c3_w mug_w) -{ - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - if ( mug_w == u3r_mug(u3h(u3h_slot_to_noun(hab_u->sot_w[i_w]))) ) { - return c3y; - } - } - return c3n; -} - -/* _ch_node_hum(): read in node. -*/ -static c3_o -_ch_node_hum(u3h_node* han_u, c3_w lef_w, c3_w rem_w, c3_w mug_w) -{ - c3_w bit_w, map_w; - - lef_w -= 5; - bit_w = (rem_w >> lef_w); - rem_w = CUT_END(rem_w, lef_w); - map_w = han_u->map_w; - - if ( !BIT_SET(map_w, bit_w) ) { - return c3n; - } - else { - c3_w inx_w = _ch_popcount(CUT_END(map_w, bit_w)); - c3_w sot_w = han_u->sot_w[inx_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_slot_to_noun(sot_w); - - if ( mug_w == u3r_mug(u3h(kev)) ) { - return c3y; - } - else { - return c3n; - } - } - else { - void* hav_v = u3h_slot_to_node(sot_w); - - if ( 0 == lef_w ) { - return _ch_buck_hum(hav_v, mug_w); - } - else return _ch_node_hum(hav_v, lef_w, rem_w, mug_w); - } - } -} - -/* u3h_hum(): check presence in hashtable. -** -** `key` is RETAINED. -*/ -c3_o -u3h_hum(u3p(u3h_root) har_p, c3_w mug_w) -{ - u3h_root* har_u = u3to(u3h_root, har_p); - c3_w inx_w = (mug_w >> 25); - c3_w rem_w = CUT_END(mug_w, 25); - c3_w sot_w = har_u->sot_w[inx_w]; - - if ( _(u3h_slot_is_null(sot_w)) ) { - return c3n; - } - else if ( _(u3h_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_slot_to_noun(sot_w); - - if ( mug_w == u3r_mug(u3h(kev)) ) { - return c3y; - } - else { - return c3n; - } - } - else { - u3h_node* han_u = u3h_slot_to_node(sot_w); - - return _ch_node_hum(han_u, 25, rem_w, mug_w); - } -} - -/* _ch_buck_git(): read in bucket. -*/ -static u3_weak -_ch_buck_git(u3h_buck* hab_u, u3_noun key) -{ - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - u3_noun kev = u3h_slot_to_noun(hab_u->sot_w[i_w]); - if ( _(u3r_sing(key, u3h(kev))) ) { - return u3t(kev); - } - } - return u3_none; -} - -/* _ch_node_git(): read in node. -*/ -static u3_weak -_ch_node_git(u3h_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun key) -{ - c3_w bit_w, map_w; - - lef_w -= 5; - bit_w = (rem_w >> lef_w); - rem_w = CUT_END(rem_w, lef_w); - map_w = han_u->map_w; - - if ( !BIT_SET(map_w, bit_w) ) { - return u3_none; - } - else { - c3_w inx_w = _ch_popcount(CUT_END(map_w, bit_w)); - c3_w sot_w = han_u->sot_w[inx_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_slot_to_noun(sot_w); - - if ( _(u3r_sing(key, u3h(kev))) ) { - return u3t(kev); - } - else { - return u3_none; - } - } - else { - void* hav_v = u3h_slot_to_node(sot_w); - - if ( 0 == lef_w ) { - return _ch_buck_git(hav_v, key); - } - else return _ch_node_git(hav_v, lef_w, rem_w, key); - } - } -} - -/* u3h_git(): read from hashtable. -** -** `key` is RETAINED; result is RETAINED. -*/ -u3_weak -u3h_git(u3p(u3h_root) har_p, u3_noun key) -{ - u3h_root* har_u = u3to(u3h_root, har_p); - c3_w mug_w = u3r_mug(key); - c3_w inx_w = (mug_w >> 25); - c3_w rem_w = CUT_END(mug_w, 25); - c3_w sot_w = har_u->sot_w[inx_w]; - - if ( _(u3h_slot_is_null(sot_w)) ) { - return u3_none; - } - else if ( _(u3h_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_slot_to_noun(sot_w); - - if ( _(u3r_sing(key, u3h(kev))) ) { - har_u->sot_w[inx_w] = u3h_noun_be_warm(sot_w); - return u3t(kev); - } - else { - return u3_none; - } - } - else { - u3h_node* han_u = u3h_slot_to_node(sot_w); - - return _ch_node_git(han_u, 25, rem_w, key); - } -} - -/* u3h_get(): read from hashtable, incrementing refcount. -** -** `key` is RETAINED; result is PRODUCED. -*/ -u3_weak -u3h_get(u3p(u3h_root) har_p, u3_noun key) -{ - u3_noun pro = u3h_git(har_p, key); - - if ( u3_none != pro ) { - u3k(pro); - } - return pro; -} - -/* _ch_free_buck(): free bucket -*/ -static void -_ch_free_buck(u3h_buck* hab_u) -{ - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - u3z(u3h_slot_to_noun(hab_u->sot_w[i_w])); - } - u3a_wfree(hab_u); -} - -/* _ch_free_node(): free node. -*/ -static void -_ch_free_node(u3h_node* han_u, c3_w lef_w) -{ - c3_w len_w = _ch_popcount(han_u->map_w); - c3_w i_w; - - lef_w -= 5; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_w sot_w = han_u->sot_w[i_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { - u3z(u3h_slot_to_noun(sot_w)); - } - else { - void* hav_v = u3h_slot_to_node(sot_w); - - if ( 0 == lef_w ) { - _ch_free_buck(hav_v); - } else { - _ch_free_node(hav_v, lef_w); - } - } - } - u3a_wfree(han_u); -} - -/* u3h_free(): free hashtable. -*/ -void -u3h_free(u3p(u3h_root) har_p) -{ - u3h_root* har_u = u3to(u3h_root, har_p); - c3_w i_w; - - for ( i_w = 0; i_w < 64; i_w++ ) { - c3_w sot_w = har_u->sot_w[i_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { - u3z(u3h_slot_to_noun(sot_w)); - } - else if ( _(u3h_slot_is_node(sot_w)) ) { - u3h_node* han_u = u3h_slot_to_node(sot_w); - - _ch_free_node(han_u, 25); - } - } - u3a_wfree(har_u); -} - -/* _ch_walk_buck(): walk bucket for gc. -*/ -static void -_ch_walk_buck(u3h_buck* hab_u, void (*fun_f)(u3_noun, void*), void* wit) -{ - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - fun_f(u3h_slot_to_noun(hab_u->sot_w[i_w]), wit); - } -} - -/* _ch_walk_node(): walk node for gc. -*/ -static void -_ch_walk_node(u3h_node* han_u, c3_w lef_w, void (*fun_f)(u3_noun, void*), void* wit) -{ - c3_w len_w = _ch_popcount(han_u->map_w); - c3_w i_w; - - lef_w -= 5; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_w sot_w = han_u->sot_w[i_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_slot_to_noun(sot_w); - - fun_f(kev, wit); - } - else { - void* hav_v = u3h_slot_to_node(sot_w); - - if ( 0 == lef_w ) { - _ch_walk_buck(hav_v, fun_f, wit); - } else { - _ch_walk_node(hav_v, lef_w, fun_f, wit); - } - } - } -} - -/* u3h_walk_with(): traverse hashtable with key, value fn and data - * argument; RETAINS. -*/ -void -u3h_walk_with(u3p(u3h_root) har_p, - void (*fun_f)(u3_noun, void*), - void* wit) -{ - u3h_root* har_u = u3to(u3h_root, har_p); - c3_w i_w; - - for ( i_w = 0; i_w < 64; i_w++ ) { - c3_w sot_w = har_u->sot_w[i_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_slot_to_noun(sot_w); - - fun_f(kev, wit); - } - else if ( _(u3h_slot_is_node(sot_w)) ) { - u3h_node* han_u = u3h_slot_to_node(sot_w); - - _ch_walk_node(han_u, 25, fun_f, wit); - } - } -} - -/* _ch_walk_plain(): use plain u3_noun fun_f for each node - */ -static void -_ch_walk_plain(u3_noun kev, void* wit) -{ - void (*fun_f)(u3_noun) = wit; - fun_f(kev); -} - -/* u3h_walk(): u3h_walk_with, but with no data argument -*/ -void -u3h_walk(u3p(u3h_root) har_p, void (*fun_f)(u3_noun)) -{ - u3h_walk_with(har_p, _ch_walk_plain, fun_f); -} - -/* _ch_take_noun(): take key and call [fun_f] on val. -*/ -static u3h_slot -_ch_take_noun(u3h_slot sot_w, u3_funk fun_f) -{ - u3_noun kov = u3h_slot_to_noun(sot_w); - u3_noun kev = u3nc(u3a_take(u3h(kov)), - fun_f(u3t(kov))); - - return u3h_noun_to_slot(kev); -} - -/* _ch_take_buck(): take bucket and contents -*/ -static u3h_slot -_ch_take_buck(u3h_slot sot_w, u3_funk fun_f) -{ - u3h_buck* hab_u = u3h_slot_to_node(sot_w); - u3h_buck* bah_u = _ch_buck_new(hab_u->len_w); - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - bah_u->sot_w[i_w] = _ch_take_noun(hab_u->sot_w[i_w], fun_f); - } - - return u3h_node_to_slot(bah_u); -} - -/* _ch_take_node(): take node and contents -*/ -static u3h_slot -_ch_take_node(u3h_slot sot_w, c3_w lef_w, u3_funk fun_f) -{ - u3h_node* han_u = u3h_slot_to_node(sot_w); - c3_w len_w = _ch_popcount(han_u->map_w); - u3h_node* nah_u = _ch_node_new(len_w); - c3_w i_w; - - nah_u->map_w = han_u->map_w; - lef_w -= 5; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_w tos_w = han_u->sot_w[i_w]; - nah_u->sot_w[i_w] = ( c3y == u3h_slot_is_noun(tos_w) ) - ? _ch_take_noun(tos_w, fun_f) - : ( 0 == lef_w ) - ? _ch_take_buck(tos_w, fun_f) - : _ch_take_node(tos_w, lef_w, fun_f); - } - - return u3h_node_to_slot(nah_u); -} - -/* u3h_take_with(): gain hashtable, copying junior keys -** and calling [fun_f] on values -*/ -u3p(u3h_root) -u3h_take_with(u3p(u3h_root) har_p, u3_funk fun_f) -{ - u3h_root* har_u = u3to(u3h_root, har_p); - u3p(u3h_root) rah_p = u3h_new_cache(har_u->max_w); - u3h_root* rah_u = u3to(u3h_root, rah_p); - c3_w i_w; - - rah_u->use_w = har_u->use_w; - rah_u->arm_u = har_u->arm_u; - - for ( i_w = 0; i_w < 64; i_w++ ) { - c3_w sot_w = har_u->sot_w[i_w]; - rah_u->sot_w[i_w] = ( c3y == u3h_slot_is_noun(sot_w) ) - ? _ch_take_noun(sot_w, fun_f) - : _ch_take_node(sot_w, 25, fun_f); - } - - return rah_p; -} - -/* u3h_take(): gain hashtable, copying junior nouns -*/ -u3p(u3h_root) -u3h_take(u3p(u3h_root) har_p) -{ - return u3h_take_with(har_p, u3a_take); -} - -/* _ch_mark_buck(): mark bucket for gc. -*/ -c3_w -_ch_mark_buck(u3h_buck* hab_u) -{ - c3_w tot_w = 0; - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - tot_w += u3a_mark_noun(u3h_slot_to_noun(hab_u->sot_w[i_w])); - } - tot_w += u3a_mark_ptr(hab_u); - - return tot_w; -} - -/* _ch_mark_node(): mark node for gc. -*/ -c3_w -_ch_mark_node(u3h_node* han_u, c3_w lef_w) -{ - c3_w tot_w = 0; - c3_w len_w = _ch_popcount(han_u->map_w); - c3_w i_w; - - lef_w -= 5; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_w sot_w = han_u->sot_w[i_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_slot_to_noun(sot_w); - - tot_w += u3a_mark_noun(kev); - } - else { - void* hav_v = u3h_slot_to_node(sot_w); - - if ( 0 == lef_w ) { - tot_w += _ch_mark_buck(hav_v); - } else { - tot_w += _ch_mark_node(hav_v, lef_w); - } - } - } - - tot_w += u3a_mark_ptr(han_u); - - return tot_w; -} - -/* u3h_mark(): mark hashtable for gc. -*/ -c3_w -u3h_mark(u3p(u3h_root) har_p) -{ - c3_w tot_w = 0; - u3h_root* har_u = u3to(u3h_root, har_p); - c3_w i_w; - - for ( i_w = 0; i_w < 64; i_w++ ) { - c3_w sot_w = har_u->sot_w[i_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_slot_to_noun(sot_w); - - tot_w += u3a_mark_noun(kev); - } - else if ( _(u3h_slot_is_node(sot_w)) ) { - u3h_node* han_u = u3h_slot_to_node(sot_w); - - tot_w += _ch_mark_node(han_u, 25); - } - } - - tot_w += u3a_mark_ptr(har_u); - - return tot_w; -} - -/* _ch_rewrite_buck(): rewrite buck for compaction. -*/ -void -_ch_rewrite_buck(u3h_buck* hab_u) -{ - if ( c3n == u3a_rewrite_ptr(hab_u) ) return; - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - u3_noun som = u3h_slot_to_noun(hab_u->sot_w[i_w]); - hab_u->sot_w[i_w] = u3h_noun_to_slot(u3a_rewritten_noun(som)); - u3a_rewrite_noun(som); - } -} - -/* _ch_rewrite_node(): rewrite node for compaction. -*/ -void -_ch_rewrite_node(u3h_node* han_u, c3_w lef_w) -{ - if ( c3n == u3a_rewrite_ptr(han_u) ) return; - - c3_w len_w = _ch_popcount(han_u->map_w); - c3_w i_w; - - lef_w -= 5; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_w sot_w = han_u->sot_w[i_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_slot_to_noun(sot_w); - han_u->sot_w[i_w] = u3h_noun_to_slot(u3a_rewritten_noun(kev)); - - u3a_rewrite_noun(kev); - } - else { - void* hav_v = u3h_slot_to_node(sot_w); - u3h_node* nod_u = u3to(u3h_node,u3a_rewritten(u3of(u3h_node,hav_v))); - han_u->sot_w[i_w] = u3h_node_to_slot(nod_u); - - if ( 0 == lef_w ) { - _ch_rewrite_buck(hav_v); - } else { - _ch_rewrite_node(hav_v, lef_w); - } - } - } -} - -/* u3h_rewrite(): rewrite pointers during compaction. -*/ -void -u3h_rewrite(u3p(u3h_root) har_p) -{ - u3h_root* har_u = u3to(u3h_root, har_p); - c3_w i_w; - - if ( c3n == u3a_rewrite_ptr(har_u) ) return; - - for ( i_w = 0; i_w < 64; i_w++ ) { - c3_w sot_w = har_u->sot_w[i_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_slot_to_noun(sot_w); - har_u->sot_w[i_w] = u3h_noun_to_slot(u3a_rewritten_noun(kev)); - - u3a_rewrite_noun(kev); - } - else if ( _(u3h_slot_is_node(sot_w)) ) { - u3h_node* han_u = u3h_slot_to_node(sot_w); - u3h_node* nod_u = u3to(u3h_node,u3a_rewritten(u3of(u3h_node,han_u))); - har_u->sot_w[i_w] = u3h_node_to_slot(nod_u); - - _ch_rewrite_node(han_u, 25); - } - } -} - -/* _ch_count_buck(): count bucket for gc. -*/ -c3_w -_ch_count_buck(u3h_buck* hab_u) -{ - c3_w tot_w = 0; - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - tot_w += u3a_count_noun(u3h_slot_to_noun(hab_u->sot_w[i_w])); - } - tot_w += u3a_count_ptr(hab_u); - - return tot_w; -} - -/* _ch_count_node(): count node for gc. -*/ -c3_w -_ch_count_node(u3h_node* han_u, c3_w lef_w) -{ - c3_w tot_w = 0; - c3_w len_w = _ch_popcount(han_u->map_w); - c3_w i_w; - - lef_w -= 5; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_w sot_w = han_u->sot_w[i_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_slot_to_noun(sot_w); - - tot_w += u3a_count_noun(kev); - } - else { - void* hav_v = u3h_slot_to_node(sot_w); - - if ( 0 == lef_w ) { - tot_w += _ch_count_buck(hav_v); - } else { - tot_w += _ch_count_node(hav_v, lef_w); - } - } - } - - tot_w += u3a_count_ptr(han_u); - - return tot_w; -} - -/* u3h_count(): count hashtable for gc. -*/ -c3_w -u3h_count(u3p(u3h_root) har_p) -{ - c3_w tot_w = 0; - u3h_root* har_u = u3to(u3h_root, har_p); - c3_w i_w; - - for ( i_w = 0; i_w < 64; i_w++ ) { - c3_w sot_w = har_u->sot_w[i_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_slot_to_noun(sot_w); - - tot_w += u3a_count_noun(kev); - } - else if ( _(u3h_slot_is_node(sot_w)) ) { - u3h_node* han_u = u3h_slot_to_node(sot_w); - - tot_w += _ch_count_node(han_u, 25); - } - } - - tot_w += u3a_count_ptr(har_u); - - return tot_w; -} - -/* _ch_discount_buck(): discount bucket for gc. -*/ -c3_w -_ch_discount_buck(u3h_buck* hab_u) -{ - c3_w tot_w = 0; - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - tot_w += u3a_discount_noun(u3h_slot_to_noun(hab_u->sot_w[i_w])); - } - tot_w += u3a_discount_ptr(hab_u); - - return tot_w; -} - -/* _ch_discount_node(): discount node for gc. -*/ -c3_w -_ch_discount_node(u3h_node* han_u, c3_w lef_w) -{ - c3_w tot_w = 0; - c3_w len_w = _ch_popcount(han_u->map_w); - c3_w i_w; - - lef_w -= 5; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_w sot_w = han_u->sot_w[i_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_slot_to_noun(sot_w); - - tot_w += u3a_discount_noun(kev); - } - else { - void* hav_v = u3h_slot_to_node(sot_w); - - if ( 0 == lef_w ) { - tot_w += _ch_discount_buck(hav_v); - } else { - tot_w += _ch_discount_node(hav_v, lef_w); - } - } - } - - tot_w += u3a_discount_ptr(han_u); - - return tot_w; -} - -/* u3h_discount(): discount hashtable for gc. -*/ -c3_w -u3h_discount(u3p(u3h_root) har_p) -{ - c3_w tot_w = 0; - u3h_root* har_u = u3to(u3h_root, har_p); - c3_w i_w; - - for ( i_w = 0; i_w < 64; i_w++ ) { - c3_w sot_w = har_u->sot_w[i_w]; - - if ( _(u3h_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_slot_to_noun(sot_w); - - tot_w += u3a_discount_noun(kev); - } - else if ( _(u3h_slot_is_node(sot_w)) ) { - u3h_node* han_u = u3h_slot_to_node(sot_w); - - tot_w += _ch_discount_node(han_u, 25); - } - } - - tot_w += u3a_discount_ptr(har_u); - - return tot_w; -} - -/* u3h_wyt(): number of entries -*/ -c3_w -u3h_wyt(u3p(u3h_root) har_p) -{ - u3h_root* har_u = u3to(u3h_root, har_p); - return har_u->use_w; -} diff --git a/pkg/urbit/noun/imprison.c b/pkg/urbit/noun/imprison.c deleted file mode 100644 index b34b9d884..000000000 --- a/pkg/urbit/noun/imprison.c +++ /dev/null @@ -1,838 +0,0 @@ -/* noun/imprison.c -** -*/ -#include "all.h" - -/* _ci_slab_size(): calculate slab bloq-size, checking for overflow. -*/ -static c3_w -_ci_slab_size(c3_g met_g, c3_d len_d) -{ - c3_d bit_d = len_d << met_g; - c3_d wor_d = (bit_d + 0x1f) >> 5; - c3_w wor_w = (c3_w)wor_d; - - if ( (wor_w != wor_d) - || (len_d != (bit_d >> met_g)) ) - { - return (c3_w)u3m_bail(c3__fail); - } - - return wor_w; -} - -/* _ci_slab_init(): initialize slab with heap allocation. -** NB: callers must ensure [len_w] >0 -*/ -static void -_ci_slab_init(u3i_slab* sab_u, c3_w len_w) -{ - c3_w* nov_w = u3a_walloc(len_w + c3_wiseof(u3a_atom)); - u3a_atom* vat_u = (void *)nov_w; - - vat_u->mug_w = 0; - vat_u->len_w = len_w; - -#ifdef U3_MEMORY_DEBUG - c3_assert( len_w ); -#endif - - sab_u->_._vat_u = vat_u; - sab_u->buf_w = vat_u->buf_w; - sab_u->len_w = len_w; -} - -/* _ci_slab_grow(): update slab with heap reallocation. -*/ -static void -_ci_slab_grow(u3i_slab* sab_u, c3_w len_w) -{ - c3_w* old_w = (void*)sab_u->_._vat_u; - // XX implement a more efficient u3a_wealloc() - // - c3_w* nov_w = u3a_wealloc(old_w, len_w + c3_wiseof(u3a_atom)); - u3a_atom* vat_u = (void *)nov_w; - - vat_u->len_w = len_w; - - sab_u->_._vat_u = vat_u; - sab_u->buf_w = vat_u->buf_w; - sab_u->len_w = len_w; -} - -/* _ci_atom_mint(): finalize a heap-allocated atom at specified length. -*/ -static u3_atom -_ci_atom_mint(u3a_atom* vat_u, c3_w len_w) -{ - c3_w* nov_w = (void*)vat_u; - - if ( 0 == len_w ) { - u3a_wfree(nov_w); - return (u3_atom)0; - } - else if ( 1 == len_w ) { - c3_w dat_w = *vat_u->buf_w; - - if ( c3y == u3a_is_cat(dat_w) ) { - u3a_wfree(nov_w); - return (u3_atom)dat_w; - } - } - - // try to strip a block off the end - // - { - c3_w old_w = vat_u->len_w; - - if ( old_w > len_w ) { - c3_y wiz_y = c3_wiseof(u3a_atom); - u3a_wtrim(nov_w, old_w + wiz_y, len_w + wiz_y); - } - } - - vat_u->len_w = len_w; - - return u3a_to_pug(u3a_outa(nov_w)); -} - -/* u3i_slab_init(): configure bloq-length slab, zero-initialize. -*/ -void -u3i_slab_init(u3i_slab* sab_u, c3_g met_g, c3_d len_d) -{ - u3i_slab_bare(sab_u, met_g, len_d); - - u3t_on(mal_o); - memset(sab_u->buf_y, 0, (size_t)sab_u->len_w * 4); - u3t_off(mal_o); -} - -/* u3i_slab_bare(): configure bloq-length slab, uninitialized. -*/ -void -u3i_slab_bare(u3i_slab* sab_u, c3_g met_g, c3_d len_d) -{ - u3t_on(mal_o); - { - c3_w wor_w = _ci_slab_size(met_g, len_d); - - // if we only need one word, use the static storage in [sab_u] - // - if ( (0 == wor_w) || (1 == wor_w) ) { - sab_u->_._vat_u = 0; - sab_u->buf_w = &sab_u->_._sat_w; - sab_u->len_w = 1; - } - // allocate an indirect atom - // - else { - _ci_slab_init(sab_u, wor_w); - } - } - u3t_off(mal_o); -} - -/* u3i_slab_from(): configure bloq-length slab, initialize with [a]. -*/ -void -u3i_slab_from(u3i_slab* sab_u, u3_atom a, c3_g met_g, c3_d len_d) -{ - u3i_slab_bare(sab_u, met_g, len_d); - - // copies [a], zero-initializes any additional space - // - u3r_words(0, sab_u->len_w, sab_u->buf_w, a); -} - -/* u3i_slab_grow(): resize slab, zero-initializing new space. -*/ -void -u3i_slab_grow(u3i_slab* sab_u, c3_g met_g, c3_d len_d) -{ - c3_w old_w = sab_u->len_w; - - u3t_on(mal_o); - { - c3_w wor_w = _ci_slab_size(met_g, len_d); - - // XX actually shrink? - // - if ( wor_w <= old_w ) { - sab_u->len_w = wor_w; - } - else { - // upgrade from static storage - // - if ( 1 == old_w ) { - c3_w dat_w = *sab_u->buf_w; - - _ci_slab_init(sab_u, wor_w); - sab_u->buf_w[0] = dat_w; - } - // reallocate - // - else { - _ci_slab_grow(sab_u, wor_w); - } - - { - c3_y* buf_y = (void*)(sab_u->buf_w + old_w); - size_t dif_i = wor_w - old_w; - memset(buf_y, 0, dif_i * 4); - } - } - } - u3t_off(mal_o); -} - -/* u3i_slab_free(): dispose memory backing slab. -*/ -void -u3i_slab_free(u3i_slab* sab_u) -{ - c3_w len_w = sab_u->len_w; - u3a_atom* vat_u = sab_u->_._vat_u; - - u3t_on(mal_o); - - if ( 1 == len_w ) { - c3_assert( !vat_u ); - } - else { - c3_w* tav_w = (sab_u->buf_w - c3_wiseof(u3a_atom)); - c3_assert( tav_w == (c3_w*)vat_u ); - u3a_wfree(vat_u); - } - - u3t_off(mal_o); -} - -/* u3i_slab_mint(): produce atom from slab, trimming. -*/ -u3_atom -u3i_slab_mint(u3i_slab* sab_u) -{ - c3_w len_w = sab_u->len_w; - u3a_atom* vat_u = sab_u->_._vat_u; - u3_atom pro; - - u3t_on(mal_o); - - if ( 1 == len_w ) { - c3_w dat_w = *sab_u->buf_w; - - c3_assert( !vat_u ); - - u3t_off(mal_o); - pro = u3i_word(dat_w); - u3t_on(mal_o); - } - else { - u3a_atom* vat_u = sab_u->_._vat_u; - c3_w* tav_w = (sab_u->buf_w - c3_wiseof(u3a_atom)); - c3_assert( tav_w == (c3_w*)vat_u ); - - // trim trailing zeros - // - while ( len_w && !(sab_u->buf_w[len_w - 1]) ) { - len_w--; - } - - pro = _ci_atom_mint(vat_u, len_w); - } - - u3t_off(mal_o); - - return pro; -} - -/* u3i_slab_moot(): produce atom from slab, no trimming. -*/ -u3_atom -u3i_slab_moot(u3i_slab* sab_u) -{ - c3_w len_w = sab_u->len_w; - u3a_atom* vat_u = sab_u->_._vat_u; - u3_atom pro; - - u3t_on(mal_o); - - if ( 1 == len_w) { - c3_w dat_w = *sab_u->buf_w; - - c3_assert( !sab_u->_._vat_u ); - - u3t_off(mal_o); - pro = u3i_word(dat_w); - u3t_on(mal_o); - } - else { - u3a_atom* vat_u = sab_u->_._vat_u; - c3_w* tav_w = (sab_u->buf_w - c3_wiseof(u3a_atom)); - c3_assert( tav_w == (c3_w*)vat_u ); - - pro = _ci_atom_mint(vat_u, len_w); - } - - u3t_off(mal_o); - - return pro; -} - -/* u3i_word(): construct u3_atom from c3_w. -*/ -u3_atom -u3i_word(c3_w dat_w) -{ - u3_atom pro; - - u3t_on(mal_o); - - if ( c3y == u3a_is_cat(dat_w) ) { - pro = (u3_atom)dat_w; - } - else { - c3_w* nov_w = u3a_walloc(1 + c3_wiseof(u3a_atom)); - u3a_atom* vat_u = (void *)nov_w; - - vat_u->mug_w = 0; - vat_u->len_w = 1; - vat_u->buf_w[0] = dat_w; - - pro = u3a_to_pug(u3a_outa(nov_w)); - } - - u3t_off(mal_o); - - return pro; -} - -/* u3i_chub(): construct u3_atom from c3_d. -*/ -u3_atom -u3i_chub(c3_d dat_d) -{ - if ( c3y == u3a_is_cat(dat_d) ) { - return (u3_atom)dat_d; - } - else { - c3_w dat_w[2] = { - dat_d & 0xffffffffULL, - dat_d >> 32 - }; - - return u3i_words(2, dat_w); - } -} - -/* u3i_bytes(): Copy [a] bytes from [b] to an LSB first atom. -*/ -u3_atom -u3i_bytes(c3_w a_w, - const c3_y* b_y) -{ - // strip trailing zeroes. - // - while ( a_w && !b_y[a_w - 1] ) { - a_w--; - } - - if ( !a_w ) { - return (u3_atom)0; - } - else { - u3i_slab sab_u; - - u3i_slab_bare(&sab_u, 3, a_w); - - u3t_on(mal_o); - { - // zero-initialize last word - // - sab_u.buf_w[sab_u.len_w - 1] = 0; - memcpy(sab_u.buf_y, b_y, a_w); - } - u3t_off(mal_o); - - return u3i_slab_moot_bytes(&sab_u); - } -} - -/* u3i_words(): Copy [a] words from [b] into an atom. -*/ -u3_atom -u3i_words(c3_w a_w, - const c3_w* b_w) -{ - // strip trailing zeroes. - // - while ( a_w && !b_w[a_w - 1] ) { - a_w--; - } - - if ( !a_w ) { - return (u3_atom)0; - } - else { - u3i_slab sab_u; - u3i_slab_bare(&sab_u, 5, a_w); - - u3t_on(mal_o); - memcpy(sab_u.buf_w, b_w, (size_t)4 * a_w); - u3t_off(mal_o); - - return u3i_slab_moot(&sab_u); - } -} - -/* u3i_chubs(): Copy [a] chubs from [b] into an atom. -*/ -u3_atom -u3i_chubs(c3_w a_w, - const c3_d* b_d) -{ - // strip trailing zeroes. - // - while ( a_w && !b_d[a_w - 1] ) { - a_w--; - } - - if ( !a_w ) { - return (u3_atom)0; - } - else if ( 1 == a_w ) { - return u3i_chub(b_d[0]); - } - else { - u3i_slab sab_u; - u3i_slab_bare(&sab_u, 6, a_w); - - u3t_on(mal_o); - { - c3_w* buf_w = sab_u.buf_w; - c3_w i_w; - c3_d i_d; - - for ( i_w = 0; i_w < a_w; i_w++ ) { - i_d = b_d[i_w]; - *buf_w++ = i_d & 0xffffffffULL; - *buf_w++ = i_d >> 32; - } - } - u3t_off(mal_o); - - return u3i_slab_mint(&sab_u); - } -} - -/* u3i_mp(): Copy the GMP integer [a] into an atom, and clear it. -*/ -u3_atom -u3i_mp(mpz_t a_mp) -{ - size_t siz_i = mpz_sizeinbase(a_mp, 2); - u3i_slab sab_u; - u3i_slab_init(&sab_u, 0, siz_i); - - mpz_export(sab_u.buf_w, 0, -1, sizeof(c3_w), 0, 0, a_mp); - mpz_clear(a_mp); - - // per the mpz_export() docs: - // - // > If op is non-zero then the most significant word produced - // > will be non-zero. - // - return u3i_slab_moot(&sab_u); -} - -/* u3i_vint(): increment [a]. -*/ -u3_atom -u3i_vint(u3_noun a) -{ - c3_assert(u3_none != a); - - if ( _(u3a_is_cat(a)) ) { - return ( a == 0x7fffffff ) ? u3i_word(a + 1) : (a + 1); - } - else if ( _(u3a_is_cell(a)) ) { - return u3m_bail(c3__exit); - } - else { - mpz_t a_mp; - - u3r_mp(a_mp, a); - u3z(a); - - mpz_add_ui(a_mp, a_mp, 1); - return u3i_mp(a_mp); - } -} - -/* u3i_defcons(): allocate cell for deferred construction. -** NB: [hed] and [tel] pointers MUST be filled. -*/ -u3_cell -u3i_defcons(u3_noun** hed, u3_noun** tel) -{ - u3_noun pro; - - u3t_on(mal_o); - { - c3_w* nov_w = u3a_celloc(); - u3a_cell* nov_u = (void *)nov_w; - - nov_u->mug_w = 0; - -#ifdef U3_MEMORY_DEBUG - nov_u->hed = u3_none; - nov_u->tel = u3_none; -#endif - - *hed = &nov_u->hed; - *tel = &nov_u->tel; - - pro = u3a_to_pom(u3a_outa(nov_w)); - } - u3t_off(mal_o); - - return pro; -} - -/* u3i_cell(): Produce the cell `[a b]`. -*/ -u3_noun -u3i_cell(u3_noun a, u3_noun b) -{ - u3_noun pro; - - u3t_on(mal_o); - { - c3_w* nov_w = u3a_celloc(); - u3a_cell* nov_u = (void *)nov_w; - - nov_u->mug_w = 0; - nov_u->hed = a; - nov_u->tel = b; - - pro = u3a_to_pom(u3a_outa(nov_w)); - } - u3t_off(mal_o); - - return pro; -} - -/* u3i_trel(): Produce the triple `[a b c]`. -*/ -u3_noun -u3i_trel(u3_noun a, u3_noun b, u3_noun c) -{ - return u3i_cell(a, u3i_cell(b, c)); -} - -/* u3i_qual(): Produce the cell `[a b c d]`. -*/ -u3_noun -u3i_qual(u3_noun a, u3_noun b, u3_noun c, u3_noun d) -{ - return u3i_cell(a, u3i_trel(b, c, d)); -} - -/* u3i_string(): Produce an LSB-first atom from the C string [a]. -*/ -u3_atom -u3i_string(const c3_c* a_c) -{ - return u3i_bytes(strlen(a_c), (c3_y *)a_c); -} - -/* u3i_tape(): from a C string, to a list of bytes. -*/ -u3_noun -u3i_tape(const c3_c* txt_c) -{ - if ( !*txt_c ) { - return u3_nul; - } else return u3i_cell(*txt_c, u3i_tape(txt_c + 1)); -} - -/* u3i_list(): list from `u3_none`-terminated varargs. -*/ -u3_noun -u3i_list(u3_weak som, ...) -{ - u3_noun lit = u3_nul; - va_list ap; - - if ( u3_none == som ) { - return lit; - } - else { - lit = u3nc(som, lit); - } - - { - u3_noun tem; - - va_start(ap, som); - while ( 1 ) { - if ( u3_none == (tem = va_arg(ap, u3_weak)) ) { - break; - } - else { - lit = u3nc(tem, lit); - } - } - va_end(ap); - } - - return u3kb_flop(lit); -} - -static u3_noun -_edit_cat(u3_noun big, c3_l axe_l, u3_noun som) -{ - if ( c3n == u3du(big) ) { - return u3m_bail(c3__exit); - } - else { - u3_noun pro; - switch ( axe_l ) { - case 2: - pro = u3nc(som, u3k(u3t(big))); - break; - case 3: - pro = u3nc(u3k(u3h(big)), som); - break; - default: { - c3_l mor_l = u3x_mas(axe_l); - pro = ( 2 == u3x_cap(axe_l) ) - ? u3nc(_edit_cat(u3k(u3h(big)), mor_l, som), u3k(u3t(big))) - : u3nc(u3k(u3h(big)), _edit_cat(u3k(u3t(big)), mor_l, som)); - break; - } - } - u3z(big); - return pro; - } -} - -static u3_noun -_edit(u3_noun big, u3_noun axe, u3_noun som) -{ - if ( c3y == u3a_is_cat(axe) ) { - return _edit_cat(big, (c3_l) axe, som); - } - else if ( c3n == u3du(big) ) { - return u3m_bail(c3__exit); - } - else { - u3_noun mor = u3qc_mas(axe), - pro = ( 2 == u3qc_cap(axe) ) - ? u3nc(_edit(u3k(u3h(big)), mor, som), u3k(u3t(big))) - : u3nc(u3k(u3h(big)), _edit(u3k(u3t(big)), mor, som)); - u3z(mor); - u3z(big); - return pro; - } -} - -static u3_noun _edit_or_mutate_cat(u3_noun, c3_l, u3_noun); -static u3_noun _edit_or_mutate(u3_noun, u3_noun, u3_noun); - -static void -_mutate_cat(u3_noun big, c3_l axe_l, u3_noun som) -{ - if ( c3n == u3du(big) ) { - u3m_bail(c3__exit); - } - else { - u3a_cell* cel_u = (void*) u3a_to_ptr(big); - switch ( axe_l ) { - case 2: - u3z(cel_u->hed); - cel_u->hed = som; - break; - case 3: - u3z(cel_u->tel); - cel_u->tel = som; - break; - default: { - u3_noun* tar = ( 2 == u3x_cap(axe_l) ) - ? &(cel_u->hed) - : &(cel_u->tel); - *tar = _edit_or_mutate_cat(*tar, u3x_mas(axe_l), som); - } - } - cel_u->mug_w = 0; - } -} - -static void -_mutate(u3_noun big, u3_noun axe, u3_noun som) -{ - if ( c3y == u3a_is_cat(axe) ) { - _mutate_cat(big, (c3_l) axe, som); - } - else if ( c3n == u3du(big) ) { - u3m_bail(c3__exit); - } - else { - u3a_cell* cel_u = (void*) u3a_to_ptr(big); - u3_noun mor = u3qc_mas(axe); - u3_noun* tar = ( 2 == u3qc_cap(axe) ) - ? &(cel_u->hed) - : &(cel_u->tel); - *tar = _edit_or_mutate(*tar, mor, som); - cel_u->mug_w = 0; - u3z(mor); - } -} - -static u3_noun -_edit_or_mutate_cat(u3_noun big, c3_l axe_l, u3_noun som) -{ - if ( c3y == u3a_is_mutable(u3R, big) ) { - _mutate_cat(big, axe_l, som); - return big; - } - else { - return _edit_cat(big, axe_l, som); - } -} - -static u3_noun -_edit_or_mutate(u3_noun big, u3_noun axe, u3_noun som) -{ - if ( c3y == u3a_is_cat(axe) ) { - return _edit_or_mutate_cat(big, (c3_l) axe, som); - } - else if ( c3y == u3a_is_mutable(u3R, big) ) { - _mutate(big, axe, som); - return big; - } - else { - return _edit(big, axe, som); - } -} - -/* u3i_edit(): -** -** Mutate `big` at axis `axe` with new value `som`. -** `axe` is RETAINED. -*/ -u3_noun -u3i_edit(u3_noun big, u3_noun axe, u3_noun som) -{ - switch ( axe ) { - case 0: - return u3m_bail(c3__exit); - case 1: - u3z(big); - return som; - default: - return _edit_or_mutate(big, axe, som); - } -} - -/* u3i_molt(): -** -** Mutate `som` with a 0-terminated list of axis, noun pairs. -** Axes must be cats (31 bit). -*/ - struct _molt_pair { - c3_w axe_w; - u3_noun som; - }; - - static c3_w - _molt_cut(c3_w len_w, - struct _molt_pair* pms_m) - { - c3_w i_w, cut_t, cut_w; - - cut_t = 0; - cut_w = 0; - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_w axe_w = pms_m[i_w].axe_w; - - if ( (cut_t == 0) && (3 == u3x_cap(axe_w)) ) { - cut_t = 1; - cut_w = i_w; - } - pms_m[i_w].axe_w = u3x_mas(axe_w); - } - return cut_t ? cut_w : i_w; - } - - static u3_noun // transfer - _molt_apply(u3_noun som, // retain - c3_w len_w, - struct _molt_pair* pms_m) // transfer - { - if ( len_w == 0 ) { - return u3k(som); - } - else if ( (len_w == 1) && (1 == pms_m[0].axe_w) ) { - return pms_m[0].som; - } - else { - c3_w cut_w = _molt_cut(len_w, pms_m); - - if ( c3n == u3a_is_cell(som) ) { - return u3m_bail(c3__exit); - } - else { - return u3i_cell - (_molt_apply(u3a_h(som), cut_w, pms_m), - _molt_apply(u3a_t(som), (len_w - cut_w), (pms_m + cut_w))); - } - } - } - -u3_noun -u3i_molt(u3_noun som, ...) -{ - va_list ap; - c3_w len_w; - struct _molt_pair* pms_m; - u3_noun pro; - - // Count. - // - len_w = 0; - { - va_start(ap, som); - while ( 1 ) { - if ( 0 == va_arg(ap, c3_w) ) { - break; - } - va_arg(ap, u3_weak*); - len_w++; - } - va_end(ap); - } - - c3_assert( 0 != len_w ); - pms_m = alloca(len_w * sizeof(struct _molt_pair)); - - // Install. - // - { - c3_w i_w; - - va_start(ap, som); - for ( i_w = 0; i_w < len_w; i_w++ ) { - pms_m[i_w].axe_w = va_arg(ap, c3_w); - pms_m[i_w].som = va_arg(ap, u3_noun); - } - va_end(ap); - } - - // Apply. - // - pro = _molt_apply(som, len_w, pms_m); - u3z(som); - return pro; -} diff --git a/pkg/urbit/noun/jets.c b/pkg/urbit/noun/jets.c deleted file mode 100644 index c60badf5d..000000000 --- a/pkg/urbit/noun/jets.c +++ /dev/null @@ -1,2399 +0,0 @@ -/* g/j.c -** -*/ -#include "all.h" -#include - -/** Data structures. -**/ - -/* _cj_hank: cached hook information. - */ -typedef struct { - u3_weak hax; // axis of hooked inner core - u3j_site sit_u; // call-site data -} _cj_hank; - -/** Functions. -**/ - -/* _cj_count(): count and link dashboard entries. -*/ -static c3_w -_cj_count(u3j_core* par_u, u3j_core* dev_u) -{ - c3_w len_l = 0; - c3_w i_w; - - if ( dev_u ) { - for ( i_w = 0; 0 != dev_u[i_w].cos_c; i_w++ ) { - u3j_core* kid_u = &dev_u[i_w]; - - if ( par_u ) { - kid_u->par_u = par_u; - } - len_l += _cj_count(kid_u, kid_u->dev_u); - } - } - return 1 + len_l; -} - -/* _cj_core_loc(): location noun from u3j_core. - */ -static u3_noun -_cj_core_loc(u3_noun pel, u3j_core* cop_u) -{ - c3_w i_w; - u3_noun nam = u3i_string(cop_u->cos_c), - huc = u3_nul, - pat; - - if ( cop_u->huc_u ) { - for ( i_w = 0; 0 != cop_u->huc_u[i_w].nam_c; ++i_w ) { - u3j_hood* huc_u = &(cop_u->huc_u[i_w]); - u3_noun fol = ( c3n == huc_u->kic_o ) - ? u3nc(0, huc_u->axe_l) - : u3nt(9, huc_u->axe_l, u3nc(0, - (0 == huc_u->sax_l) ? 1 : huc_u->sax_l)); - huc = u3kdb_put(huc, u3i_string(huc_u->nam_c), fol); - } - } - - pat = ( 0 == cop_u->axe_l ) - ? u3nt(c3y, c3y, pel) - : ( (3 == cop_u->axe_l) && (c3y == u3h(u3h(pel))) ) - ? u3nt(c3y, c3n, pel) - : u3nt(c3n, cop_u->axe_l, pel); - - return u3nt(pat, nam, huc); -} - -/* _cj_hash(): noun from pasted-in battery hash - */ -static u3_noun -_cj_hash(c3_c* has_c) -{ - c3_w i_w, len_w = strlen(has_c); - if ( 64 != len_w ) { - u3l_log("bash not 64 characters: %s", has_c); - c3_assert(0); - } - c3_assert( 64 == len_w ); - c3_y dig_y[32]; - for ( i_w = 0; i_w < 64; ) { - c3_y hi_y = has_c[i_w++], - lo_y = has_c[i_w++], - hid_y = hi_y >= 'a' ? (hi_y - 'a') + 10 : hi_y - '0', - lod_y = lo_y >= 'a' ? (lo_y - 'a') + 10 : lo_y - '0'; - dig_y[32-(i_w>>1)] = hid_y << 4 | lod_y; - } - u3_noun pro = u3i_bytes(32, dig_y); - return pro; -} - -// in the jam jet file -c3_w* u3qe_jam_buf(u3_noun, c3_w* bit_w); - -/* _cj_bash(): battery hash. RETAIN. - */ -static u3_noun -_cj_bash(u3_noun bat) -{ - if ( u3C.wag_w & u3o_hashless ) { - return u3_nul; - } - - u3_weak pro; - u3a_road* rod_u = u3R; - while ( 1 ) { - pro = u3h_get(rod_u->jed.bas_p, bat); - - if ( u3_none != pro ) { - break; - } - - if ( rod_u->par_p ) { - rod_u = u3to(u3_road, rod_u->par_p); - } - else { - u3i_slab sab_u; - c3_w bit_w = u3s_jam_fib(&sab_u, bat); - c3_w met_w = (bit_w + 0x7) >> 3; - // XX assumes little-endian - // - c3_y* fat_y = sab_u.buf_y; - c3_y dig_y[32]; - urcrypt_shay(fat_y, met_w, dig_y); - - pro = u3i_bytes(32, dig_y); - u3h_put(u3R->jed.bas_p, bat, u3k(pro)); - u3i_slab_free(&sab_u); - break; - } - } - return pro; -} - -/* _cj_mine_par_old(): register hooks and parent location within existing - * axis in ancestor list or u3_none. - */ -static u3_weak -_cj_mine_par_old(u3_noun lan, u3_noun axe, u3_noun pel, u3_noun loc) -{ - u3_noun par; - u3_weak pro; - - if ( u3_nul == lan ) { - pro = u3_none; - u3z(axe); u3z(pel); u3z(loc); - } - else if ( c3y == u3r_sing(axe, u3h(par = u3h(lan))) ) { - u3_noun lol = u3kdb_put(u3k(u3t(par)), pel, loc), - rap = u3nc(axe, lol); - pro = u3nc(rap, u3k(u3t(lan))); - } - else { - u3_weak nex = _cj_mine_par_old(u3k(u3t(lan)), axe, pel, loc); - if ( u3_none == nex ) { - pro = u3_none; - } - else { - pro = u3nc(u3k(par), nex); - } - } - - u3z(lan); - return pro; -} - -/* _cj_mine_par_new(): insert ancestor within lan at sorted index. - */ -static u3_noun -_cj_mine_par_new(u3_noun lan, u3_noun axe, u3_noun pel, u3_noun loc) -{ - u3_weak pro; - - if ( (u3_nul == lan) || (c3y == u3qa_lth(axe, u3h(u3h(lan)))) ) { - u3_noun par = u3nc(axe, u3kdb_put(u3_nul, pel, loc)); - pro = u3nc(par, lan); - } - else { - pro = u3nc(u3k(u3h(lan)), - _cj_mine_par_new(u3k(u3t(lan)), axe, pel, loc)); - u3z(lan); - } - - return pro; -} - -/* _cj_mine_par(): register a location as an ancestor - * in a list of ancestors. - */ -static u3_noun -_cj_mine_par(u3_noun lan, u3_noun axe, u3_noun pel, u3_noun loc) -{ - u3_weak old = _cj_mine_par_old(u3k(lan), u3k(axe), u3k(pel), u3k(loc)); - if ( u3_none != old ) { - u3z(lan); u3z(axe); u3z(pel); u3z(loc); - return old; - } - else { - return _cj_mine_par_new(lan, axe, pel, loc); - } -} - - -/* _cj_gust(): add location to registry. -*/ -static u3_noun -_cj_gust(u3_weak reg, u3_noun axe, u3_noun pel, u3_noun loc) -{ - u3_noun ger; - if ( u3_none == reg ) { - reg = u3nc(u3_nul, u3_nul); - } - - ger = ( 0 == axe ) - ? u3nc(u3kdb_put(u3k(u3h(reg)), pel, loc), u3k(u3t(reg))) - : u3nc(u3k(u3h(reg)), _cj_mine_par(u3k(u3t(reg)), axe, pel, loc)); - - u3z(reg); - return ger; -} - -/* _cj_axis(): axis from formula, or 0. `fol` is RETAINED. -*/ -static c3_l -_cj_axis(u3_noun fol) -{ - u3_noun p_fol, q_fol, r_fol; - - while ( _(u3du(fol)) && (11 == u3h(fol)) ) - { fol = u3t(u3t(fol)); } - - if ( !_(u3r_trel(fol, &p_fol, &q_fol, &r_fol)) ) { - if ( !_(u3r_cell(fol, &p_fol, &q_fol)) || - (0 != p_fol) || - (!_(u3a_is_cat(q_fol))) ) - { - u3l_log("axis: bad a"); - return 0; - } - return q_fol; - } - else { - if ( 9 != p_fol ) - { u3l_log("axis: bad b"); return 0; } - if ( !_(u3a_is_cat(q_fol)) ) - { u3l_log("axis: bad c"); return 0; } - if ( !_(u3du(r_fol)) || (0 != u3h(r_fol)) || (1 != u3t(r_fol)) ) - { u3l_log("axis: bad d"); return 0; } - - return q_fol; - } -} - -/* _cj_warm_hump(): generate axis-to-arm map. RETAIN. -*/ -static u3_noun -_cj_warm_hump(c3_l jax_l, u3_noun huc) -{ - u3_noun hap = u3_nul; - u3j_core* cop_u; - - /* Compute axes of all correctly declared arms. - */ - if ( jax_l && (cop_u = &u3D.ray_u[jax_l])->arm_u ) { - u3j_harm* jet_u; - c3_l i_l; - - for ( i_l = 0; (jet_u = &cop_u->arm_u[i_l])->fcs_c; i_l++ ) { - c3_l axe_l = 0; - - if ( '.' == *(jet_u->fcs_c) ) { - c3_d axe_d = 0; - - if ( (1 != sscanf(jet_u->fcs_c+1, "%" SCNu64, &axe_d)) || - axe_d >> 32ULL || - ((1 << 31) & (axe_l = (c3_w)axe_d)) || - (axe_l < 2) ) - { - u3l_log("jets: activate: bad fcs %s", jet_u->fcs_c); - } - } - else { - u3_noun nam = u3i_string(jet_u->fcs_c); - u3_noun fol = u3kdb_get(u3k(huc), nam); - - if ( u3_none == fol ) { - u3l_log("jets: activate: bad fcs %s", jet_u->fcs_c); - } - else { - axe_l = _cj_axis(fol); - u3z(fol); - } - } - if ( 0 != axe_l ) { - hap = u3kdb_put(hap, axe_l, i_l); - } - } - } - return hap; -} - -/* _cj_install(): install dashboard entries. -*/ -static c3_w -_cj_install(u3j_core* ray_u, c3_w jax_l, u3_noun pel, u3_noun lab, u3j_core* dev_u) -{ - c3_w i_w; - c3_assert(u3R == &(u3H->rod_u)); - - if ( dev_u ) { - for ( i_w = 0; 0 != dev_u[i_w].cos_c; i_w++ ) { - u3j_core* kid_u = &dev_u[i_w]; - u3_noun loc = _cj_core_loc(u3k(pel), kid_u), - bal = u3nc(u3k(u3h(u3t(loc))), u3k(lab)); - - kid_u->jax_l = jax_l; - ray_u[jax_l] = *kid_u; - - if ( kid_u->bas_u ) { - c3_w j_w; - for ( j_w = 0; 0 != kid_u->bas_u[j_w]; j_w++ ) { - u3_noun key = _cj_hash(kid_u->bas_u[j_w]), - hot = u3h_get(u3R->jed.hot_p, key), - old = ( u3_none == hot ) ? u3_none : u3k(u3h(hot)), - reg = _cj_gust(old, kid_u->axe_l, u3k(pel), u3k(loc)), - huc = u3t(u3t(loc)), - hap = _cj_warm_hump(jax_l, huc), - toh = u3nq(reg, jax_l, hap, u3k(bal)); - - u3h_put(u3R->jed.hot_p, key, toh); - u3z(key); u3z(hot); - } - } - - jax_l = _cj_install(ray_u, ++jax_l, loc, bal, kid_u->dev_u); - } - } - u3z(pel); - u3z(lab); - return jax_l; -} - -#if 0 -/* _cj_by_gut(): (~(get by a) b), unifying; RETAINS a, b, AND result. -*/ -static u3_weak -_cj_by_gut(u3_noun a, u3_noun b) -{ - if ( u3_nul == a ) { - return u3_none; - } - else { - u3_noun l_a, n_a, r_a; - u3_noun pn_a, qn_a; - - u3x_trel(a, &n_a, &l_a, &r_a); - u3x_cell(n_a, &pn_a, &qn_a); - { - if ( (c3y == u3r_sing(b, pn_a)) ) { - return qn_a; - } - else { - if ( c3y == u3qc_gor(b, pn_a) ) { - return _cj_by_gut(l_a, b); - } - else return _cj_by_gut(r_a, b); - } - } - } -} -#endif - -/* _cj_chum(): decode chum as string. -*/ -static c3_c* -_cj_chum(u3_noun chu) -{ - if ( _(u3ud(chu)) ) { - return u3r_string(chu); - } - else { - u3_noun h_chu = u3h(chu); - u3_noun t_chu = u3t(chu); - - if ( !_(u3a_is_cat(t_chu)) ) { - return 0; - } else { - c3_c* h_chu_c = u3r_string(h_chu); - c3_c buf[33]; - - memset(buf, 0, 33); - snprintf(buf, 32, "%s%d", h_chu_c, t_chu); - - c3_free(h_chu_c); - return strdup(buf); - } - } -} - -/* _cj_je_fsck: fsck:je, or none. -*/ -static u3_noun -_cj_je_fsck(u3_noun clu) -{ - u3_noun p_clu, q_clu, r_clu; - u3_noun huk; - c3_c* nam_c; - c3_l axe_l; - - if ( c3n == u3r_trel(clu, &p_clu, &q_clu, &r_clu) ) { - u3z(clu); return u3_none; - } - if ( 0 == (nam_c = _cj_chum(p_clu)) ) { - u3z(clu); return u3_none; - } - while ( _(u3du(q_clu)) && (11 == u3h(q_clu)) ) { - q_clu = u3t(u3t(q_clu)); - } - if ( !_(u3du(q_clu)) ) { - u3z(clu); c3_free(nam_c); return u3_none; - } - - if ( (1 == u3h(q_clu)) && (0 == u3t(q_clu)) ) { - axe_l = 0; - } - else { - if ( (0 != u3h(q_clu)) || !_(u3a_is_cat(axe_l = u3t(q_clu))) ) { - u3z(clu); c3_free(nam_c); return u3_none; - } - } - - { - huk = 0; - - while ( _(u3du(r_clu)) ) { - u3_noun ir_clu, tr_clu, pir_clu, qir_clu; - - if ( (c3n == u3r_cell(r_clu, &ir_clu, &tr_clu)) || - (c3n == u3r_cell(ir_clu, &pir_clu, &qir_clu)) || - (c3n == u3ud(pir_clu)) ) - { - u3z(huk); u3z(clu); c3_free(nam_c); return u3_none; - } - huk = u3kdb_put(huk, u3k(pir_clu), u3k(qir_clu)); - r_clu = tr_clu; - } - } - u3z(clu); - - { - u3_noun pro = u3nt(u3i_string(nam_c), axe_l, huk); - c3_free(nam_c); - return pro; - } -} - -/* _cj_find_cold(): search cold state for `bat`s [bash registry]. - * RETAIN. - */ -static u3_weak -_cj_find_cold(u3_noun bat) -{ - u3a_road* rod_u = u3R; - - while ( 1 ) { - u3_weak bar = u3h_get(rod_u->jed.cod_p, bat); - - if ( u3_none != bar ) { - return bar; - } - - if ( rod_u->par_p ) { - rod_u = u3to(u3_road, rod_u->par_p); - } - else return u3_none; - } -} - -/* _cj_find_warm(): search warm state for `loc`s activation. - * RETAIN. - */ -static u3_weak -_cj_find_warm(u3_noun loc) -{ - u3a_road* rod_u = u3R; - - while ( 1 ) { - u3_weak ank = u3h_get(rod_u->jed.war_p, loc); - - if ( u3_none != ank ) { - return ank; - } - - if ( rod_u->par_p ) { - rod_u = u3to(u3_road, rod_u->par_p); - } - else return u3_none; - } -} - -static u3_weak _cj_spot(u3_noun cor, u3_weak* bas); - -/* _cj_reg_find(): locate core within registry. RETAIN. - */ -static u3_weak -_cj_reg_find(u3_noun reg, u3_noun cor) -{ - u3_noun rut = u3h(reg), - pas = u3t(reg), - rum = u3qdb_get(rut, u3t(cor)); - if ( u3_nul != rum ) { - u3_noun loc = u3k(u3t(rum)); - u3z(rum); - return loc; - } - else { - while ( u3_nul != pas ) { - u3_noun pap = u3h(pas), - axe = u3h(pap), - lol = u3t(pap); - u3_weak par = u3r_at(axe, cor), - pel; - if ( u3_none != par ) { - pel = _cj_spot(par, NULL); - if ( u3_none != pel ) { - u3_noun nit = u3qdb_get(lol, pel); - u3z(pel); - if ( u3_nul != nit ) { - u3_noun loc = u3k(u3t(nit)); - u3z(nit); - return loc; - } - } - } - pas = u3t(pas); - } - return u3_none; - } -} - -/* _cj_jit(): generate arbitrary warm jet-associated data. RETAIN. -*/ -static u3_noun -_cj_jit(c3_l jax_l, u3_noun bat) -{ - return u3_nul; -} - -/* _cj_loc_axe(): axis-within-core from location (0 for root). RETAIN. - */ -static u3_noun -_cj_loc_axe(u3_noun loc) -{ - u3_noun pat = u3h(loc); - return ( c3n == u3h(pat) ) - ? u3k(u3h(u3t(pat))) - : (c3y == u3h(u3t(pat))) ? 0 : 3; -} - -/* _cj_loc_pel(): parent location (or root noun, if root) of loc. RETAIN. - */ -static u3_noun -_cj_loc_pel(u3_noun loc) -{ - return u3k(u3t(u3t(u3h(loc)))); -} - -/* _cj_spot_cold(): spot, cold dashboard only. *bar is set to - * the [bash registry] found for battery. RETAIN. - */ -static u3_weak -_cj_spot_cold(u3_noun cor, u3_weak* bar) -{ - *bar = _cj_find_cold(u3h(cor)); - if ( u3_none == *bar ) { - return u3_none; - } - else { - return _cj_reg_find(u3t(*bar), cor); - } -} - -/* _cj_spot_hot(): try to locate core by hot dashboard. if found, - * the activation (warm state) is returned and the - * location is produced at *loc. RETAIN. - */ -static u3_weak -_cj_spot_hot(u3_noun cor, u3_noun bas, u3_noun* loc) -{ - u3_noun bat = u3h(cor); - u3_weak act = u3_none, - hot = u3h_get(u3H->rod_u.jed.hot_p, bas); - if ( u3_none != hot ) { - u3_noun reg, jax, hap, bal; - c3_l jax_l; - u3x_qual(hot, ®, &jax, &hap, &bal); - jax_l = (c3_l) jax; - if ( u3_none != (*loc = _cj_reg_find(reg, cor)) ) { - act = u3nq(jax_l, u3k(hap), u3k(bal), _cj_jit(jax_l, bat)); - } - u3z(hot); - } - return act; -} - -/* _cj_spot(): find location of cor. expensive. RETAIN. - * bas is complicated to make it easy to cache bashes. - * you can safely ignore it by passing NULL. Otherwise, - * if it points to u3_none, and no location is found, - * a bash will be PRODUCED there. if it contains a bash, - * that will be used instead of calling _cj_bash. - */ -static u3_weak -_cj_spot(u3_noun cor, u3_weak* bas) -{ - u3_weak bak = u3_none, - bar = u3_none, - reg = u3_none, - loc = _cj_spot_cold(cor, &bar); - - if ( NULL == bas ) { - bas = &bak; - } - - if ( u3_none != bar ) { - if ( (u3_none == *bas) ) { - *bas = u3k(u3h(bar)); - } - reg = u3k(u3t(bar)); - u3z(bar); - } - - if ( u3_none == loc ) { - if ( u3_none == *bas ) { - *bas = _cj_bash(u3h(cor)); - } - - if ( !(u3C.wag_w & u3o_hashless) ) { - u3_weak act = _cj_spot_hot(cor, *bas, &loc); - if ( u3_none != act ) { - reg = _cj_gust(reg, _cj_loc_axe(loc), _cj_loc_pel(loc), u3k(loc)); - u3h_put(u3R->jed.cod_p, u3h(cor), u3nc(u3k(*bas), u3k(reg))); - /* caution: could overwrites old value, debug batteries etc. - ** old value contains old _cj_jit (from different - ** battery). if we change jit to (map battery *), - ** will need to merge with that map here. - */ - u3h_put(u3R->jed.war_p, loc, act); - } - } - } - if ( u3_none != bak ) { - u3z(bak); - } - if ( u3_none != reg ) { - u3z(reg); - } - return loc; -} - -/* _cj_cast(): create a u3j_fink that can be used to efficiently verify - * that another core is located where this one is. RETAIN. - */ -static u3p(u3j_fink) -_cj_cast(u3_noun cor, u3_noun loc) -{ - c3_w i_w = 0; - u3_noun j, par, bat, dyn, pax, - rev = u3_nul, - pat = u3h(loc); - u3j_fink* fin_u; - - while ( c3n == u3h(pat) ) { - bat = u3h(cor); - dyn = u3t(pat); - pax = u3h(dyn); - loc = u3t(dyn); - pat = u3h(loc); - rev = u3nc(u3nc(u3k(bat), u3k(pax)), rev); - // pax already known-valid - cor = u3r_at(pax, cor); - ++i_w; - } - - fin_u = u3a_walloc(c3_wiseof(u3j_fink) + - (i_w * c3_wiseof(u3j_fist))); - fin_u->len_w = i_w; - fin_u->sat = u3k(cor); - for ( j = rev; i_w-- > 0; j = u3t(j) ) { - u3j_fist* fis_u = &(fin_u->fis_u[i_w]); - par = u3h(j); - fis_u->bat = u3k(u3h(par)); - fis_u->pax = u3k(u3t(par)); - } - u3z(rev); - c3_assert( u3_nul == j ); - - return u3of(u3j_fink, fin_u); -} - -/* _cj_fine(): check that a core matches a u3j_fink. RETAIN. - */ -static c3_o -_cj_fine(u3_noun cor, u3p(u3j_fink) fin_p) -{ - u3j_fink* fin_u = u3to(u3j_fink, fin_p); - c3_w i_w; - for ( i_w = 0; i_w < fin_u->len_w; ++i_w ) { - u3j_fist* fis_u = &(fin_u->fis_u[i_w]); - if ( c3n == u3r_sing(fis_u->bat, u3h(cor)) ) { - return c3n; - } - else { - cor = u3r_at(fis_u->pax, cor); - } - } - return u3r_sing(fin_u->sat, cor); -} - -/* _cj_nail(): resolve hot state for arm at axis within cores located - * at loc. a label will be PRODUCED at *lab, unconditionally. - * Arguments are RETAINED. Return value is yes if a jet driver - * is present. - */ -static c3_o -_cj_nail(u3_noun loc, u3_noun axe, - u3_noun* lab, u3j_core** cop_u, u3j_harm** ham_u) -{ - c3_o ret_o; - u3_noun jax, hap, bal, jit; - u3_weak act; - act = _cj_find_warm(loc); - c3_assert(u3_none != act); - u3x_qual(act, &jax, &hap, &bal, &jit); - - *lab = u3k(bal); - if ( 0 == jax ) { - ret_o = c3n; - } - else { - u3_weak inx = u3kdb_get(u3k(hap), u3k(axe)); - if ( u3_none == inx ) { - ret_o = c3n; - } - else { - c3_l jax_l = jax, - inx_l = inx; - *cop_u = &(u3D.ray_u[jax_l]); - *ham_u = &((*cop_u)->arm_u[inx_l]); - ret_o = c3y; - } - } - - u3z(act); - return ret_o; -} - -/* _cj_hot_mean(): in parent, declare a core. RETAINS. -*/ -static c3_l -_cj_hot_mean(c3_l par_l, u3_noun nam) -{ - u3j_core* par_u; - u3j_core* dev_u; - - if ( 0 != par_l ) { - par_u = &u3D.ray_u[par_l]; - dev_u = par_u->dev_u; - } - else { - par_u = 0; - dev_u = u3D.dev_u; - } - - { - c3_w i_l = 0; - u3j_core* cop_u; - - while ( (cop_u = &dev_u[i_l])->cos_c ) { - if ( _(u3r_sing_c(cop_u->cos_c, nam)) ) { -#if 0 - u3l_log("hot: bound jet %d/%s/%s/", - cop_u->jax_l, - cop_u->cos_c, - par_u ? par_u->cos_c : "~"); -#endif - return cop_u->jax_l; - } - i_l++; - } - } - return 0; -} - -/* u3j_boot(): initialize jet system. -*/ -c3_w -u3j_boot(c3_o nuu_o) -{ - c3_assert(u3R == &(u3H->rod_u)); - - u3D.len_l =_cj_count(0, u3D.dev_u); - u3D.all_l = (2 * u3D.len_l) + 1024; // horrid heuristic - - u3D.ray_u = c3_malloc(u3D.all_l * sizeof(u3j_core)); - memset(u3D.ray_u, 0, (u3D.all_l * sizeof(u3j_core))); - - if ( c3n == nuu_o ) { - u3h_free(u3R->jed.hot_p); - } - u3R->jed.hot_p = u3h_new(); - - return _cj_install(u3D.ray_u, 1, - (c3_l) (long long) u3D.dev_u[0].par_u, - u3_nul, - u3D.dev_u); -} - -/* _cj_soft(): kick softly by arm axis. -*/ -static u3_noun -_cj_soft(u3_noun cor, u3_noun axe) -{ - u3_noun arm = u3x_at(axe, cor); - - return u3n_nock_on(cor, u3k(arm)); -} - - void - find_error(u3_noun cor, - u3_noun old, - u3_noun new); - -/* _cj_kick_z(): try to kick by jet. If no kick, produce u3_none. -** -** `cor` is RETAINED iff there is no kick, TRANSFERRED if one. -** `axe` is RETAINED. -*/ -static u3_weak -_cj_kick_z(u3_noun cor, u3j_core* cop_u, u3j_harm* ham_u, u3_atom axe) -{ - if ( 0 == ham_u->fun_f ) { - return u3_none; - } - - if ( !_(ham_u->liv) ) { - return u3_none; - } - else { -#ifdef U3_MEMORY_DEBUG - c3_w cod_w; - - { - char soc_c[5]; - - memset(soc_c, 0, 5); - strncpy(soc_c, cop_u->cos_c, 4); - soc_c[4] = 0; - cod_w = u3i_string(soc_c); - cod_w = u3a_lush(cod_w); - } -#endif - - if ( _(ham_u->ice) ) { - u3_weak pro = ham_u->fun_f(cor); - -#ifdef U3_MEMORY_DEBUG - u3a_lop(cod_w); -#endif - if ( u3_none != pro ) { - u3z(cor); - return pro; - } - } - else { - u3_weak pro, ame; - - ham_u->ice = c3y; - pro = ham_u->fun_f(cor); - ham_u->ice = c3n; - -#ifdef U3_MEMORY_DEBUG - u3a_lop(cod_w); -#endif - if ( u3_none == pro ) { - u3z(cor); - return pro; - } - ham_u->liv = c3n; - ame = _cj_soft(cor, axe); - ham_u->liv = c3y; - - if ( c3n == u3r_sing(ame, pro) ) { - u3l_log("test: %s %s: mismatch: good %x, bad %x", - cop_u->cos_c, - (!strcmp(".2", ham_u->fcs_c)) ? "$" : ham_u->fcs_c, - u3r_mug(ame), - u3r_mug(pro)); - ham_u->liv = c3n; - - return u3m_bail(c3__fail); - } - else { - -#if 0 - u3l_log("test: %s %s", - cop_u->cos_c, - (!strcmp(".2", ham_u->fcs_c)) ? "$" : ham_u->fcs_c); -#endif - u3z(ame); - return pro; - } - } - return u3_none; - } -} - -/* _cj_hook_in(): execute hook from core, or fail. -*/ -static u3_noun -_cj_hook_in(u3_noun cor, - const c3_c* tam_c, - c3_o jet_o) -{ - u3_weak loc, col; - u3_noun roc, tem, got, pat, nam, huc; - - if ( c3n == u3du(cor) ) { - u3l_log("_cj_hook_in failure: c3n == u3du(cor)"); - return u3m_bail(c3__fail); - } - - loc = _cj_spot(cor, NULL); - if ( u3_none == loc ) { - u3l_log("_cj_hook_in failure: u3_none == loc"); - return u3m_bail(c3__fail); - } - - tem = u3i_string(tam_c); - while ( 1 ) { - u3x_trel(loc, &pat, &nam, &huc); - got = u3qdb_get(huc, tem); - if ( u3_nul != got ) { - c3_l axe_l; - u3_noun pro, fol; - u3j_core* cop_u; - - u3z(tem); - fol = u3k(u3t(got)); - u3z(got); - axe_l = _cj_axis(fol); - if ( 0 == axe_l ) { - u3t_off(glu_o); - pro = u3n_nock_on(cor, fol); - u3t_on(glu_o); - } - else { - c3_l jax_l, inx_l; - u3_noun hap, act; - - u3z(fol); - act = _cj_find_warm(loc); - jax_l = u3h(act); - hap = u3h(u3t(act)); - cop_u = &u3D.ray_u[jax_l]; - - // Tricky: the above case would work here too, but would - // disable jet_o and create some infinite recursions. - // - u3t_off(glu_o); - if ( (c3n == jet_o) || - (u3_none == (inx_l = u3kdb_get(u3k(hap), axe_l))) || - (u3_none == (pro = _cj_kick_z(cor, - cop_u, - &cop_u->arm_u[inx_l], - axe_l))) ) { - pro = u3n_nock_on(cor, u3k(u3x_at(axe_l, cor))); - } - u3t_on(glu_o); - u3z(act); - } - u3z(loc); - return pro; - } - else if ( c3n == u3h(pat) ) { - u3_noun dyn = u3t(pat), - axe = u3h(dyn), - pel = u3t(dyn); - // axe already known-valid - roc = u3k(u3r_at(axe, cor)); - u3z(cor); - cor = roc; - col = u3k(pel); - u3z(loc); - loc = col; - } - else { - u3_noun sat = u3t(pat); - if ( c3y == u3h(sat) ) { - u3l_log("_cj_hook_in failure: c3y == u3h(sat)"); - return u3m_bail(c3__fail); - } - else { - col = u3k(u3t(sat)); - u3z(loc); - loc = col; - roc = u3k(u3t(cor)); - u3z(cor); - cor = roc; - } - } - } -} - -/* u3j_soft(): execute soft hook. -*/ -u3_noun -u3j_soft(u3_noun cor, - const c3_c* tam_c) -{ - u3_noun pro; - u3t_on(glu_o); - pro = _cj_hook_in(cor, tam_c, c3n); - u3t_off(glu_o); - return pro; -} - -/* u3j_hook(): execute hook from core, or fail. -*/ -u3_noun -u3j_hook(u3_noun cor, - const c3_c* tam_c) -{ - u3_noun pro; - u3t_on(glu_o); - pro = _cj_hook_in(cor, tam_c, c3y); - u3t_off(glu_o); - return pro; -} - -/* _cj_prog(): stop tracing glu and find a nock program - */ -static u3p(u3n_prog) -_cj_prog(u3_weak loc, u3_noun fol) -{ - u3p(u3n_prog) pog_p; - u3t_off(glu_o); - pog_p = u3n_find((loc == u3_none ? u3_nul : loc), fol); - u3t_on(glu_o); - return pog_p; -} - -/* cj_hank_find(): find cached hook information, keyed by arbitrary - * prefix and term cords. RETAIN. - */ -static _cj_hank* -_cj_hank_find(u3_noun pre, u3_noun tam) -{ - u3_noun key = u3nc(u3k(pre), u3k(tam)); - u3_noun got = u3h_git(u3R->jed.han_p, key); - - if ( u3_none != got ) { - u3z(key); - return u3to(_cj_hank, got); - } - else { - _cj_hank* new_u = u3a_walloc(c3_wiseof(_cj_hank)); - u3a_road* rod_u = u3R; - - while ( rod_u->par_p && u3_none == got ) { - rod_u = u3to(u3a_road, rod_u->par_p); - got = u3h_git(rod_u->jed.han_p, key); - } - - if ( u3_none == got ) { - new_u->hax = u3_none; - } - else { - _cj_hank* old_u = u3to(_cj_hank, got); - if ( u3_none != (new_u->hax = old_u->hax) ) { - // it's unusual but safe to "take" here, because - // u3a_take will no-op on senior nouns (just as u3k would) - // - u3j_site_take(&(new_u->sit_u), &(old_u->sit_u)); - } - } - - u3h_put(u3R->jed.han_p, key, u3of(_cj_hank, new_u)); - u3z(key); - return new_u; - } -} - -/* _cj_hank_fine(): check that cached hook information is valid - * for given core. *inn will point to the hooked - * core on return if valid. RETAIN. - */ -static c3_o -_cj_hank_fine(_cj_hank* han_u, u3_noun cor, u3_noun *inn) -{ - u3_noun hax = han_u->hax; - if ( u3_none == hax ) { - return c3n; - } - else { - *inn = u3r_at(hax, cor); - if ( u3_none == *inn ) { - return c3n; - } - else { - u3j_site* sit_u = &(han_u->sit_u); - c3_assert(u3_none != sit_u->loc); - return _cj_fine(*inn, sit_u->fin_p); - } - } -} - -/* _cj_hank_lose(): release memory maintained in a hook cache. -*/ -static void -_cj_hank_lose(_cj_hank* han_u) -{ - if ( u3_none != han_u->hax ) { - u3z(han_u->hax); - u3j_site_lose(&(han_u->sit_u)); - } -} - -/* _cj_hank_fill(): slow path, populate han_u. - */ -static u3_noun -_cj_hank_fill(_cj_hank* han_u, u3_noun tam, u3_noun cor) -{ - u3_weak loc, col; - u3_noun got, pat, nam, huc; - u3_noun hax = 1; - u3j_site* sit_u = &(han_u->sit_u); - - if ( c3n == u3du(cor) ) { - u3l_log("fail in _cj_hank_fill (c3n == u3du(cor))"); - return u3m_bail(c3__fail); - } - - sit_u->bas = u3_none; - if ( u3_none == (col = loc = _cj_spot(cor, NULL)) ) { - u3l_log("fail in _cj_hank_fill (_cj_spot(cor, NULL))"); - return u3m_bail(c3__fail); - } - - while ( 1 ) { - u3x_trel(loc, &pat, &nam, &huc); - got = u3qdb_get(huc, tam); - if ( u3_nul != got ) { - u3_noun fol = u3k(u3t(got)); - u3z(got); - sit_u->bat = u3k(u3h(cor)); - sit_u->loc = u3k(loc); - sit_u->fin_p = _cj_cast(cor, loc); - sit_u->fon_o = c3y; - if ( 0 == (sit_u->axe = _cj_axis(fol)) ) { - sit_u->jet_o = c3n; - sit_u->pog_p = _cj_prog(loc, fol); - } - else { - // loc already known-valid - han_u->sit_u.pog_p = _cj_prog(loc, u3r_at(sit_u->axe, cor)); - han_u->sit_u.jet_o = _cj_nail(loc, sit_u->axe, - &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u)); - } - u3z(fol); - u3z(col); - han_u->hax = hax; - return cor; - } - else if ( c3n == u3h(pat) ) { - u3_noun dyn = u3t(pat), - axe = u3h(dyn), - xah; - // axe already known-valid - cor = u3r_at(axe, cor); - loc = u3t(dyn); - xah = u3qc_peg(axe, hax); - u3z(hax); - hax = xah; - } - else { - u3_noun sat = u3t(pat); - if ( c3y == u3h(sat) ) { - u3l_log("fail in _cj_hank_fill (c3y == u3h(sat))"); - return u3m_bail(c3__fail); - } - else { - u3_noun xah; - cor = u3t(cor); - loc = u3t(sat); - xah = u3qc_peg(3, hax); - u3z(hax); - hax = xah; - } - } - } -} - -/* _cj_sink(): kick by nock. - */ -static u3_noun -_cj_sink(u3_noun cor, u3_noun axe) -{ - u3_noun fol = u3x_at(axe, cor); - u3z(axe); - return u3n_nock_on(cor, u3k(fol)); -} - -/* u3j_kick(): new kick. -** -** `axe` is RETAINED by the caller; `cor` is RETAINED iff there -** is no kick, TRANSFERRED if one. -*/ -u3_weak -u3j_kick(u3_noun cor, u3_noun axe) -{ - u3t_on(glu_o); - u3_weak loc = _cj_spot(cor, NULL); - if ( u3_none == loc ) { - u3t_off(glu_o); - return u3_none; - } - else { - u3_weak act = _cj_find_warm(loc); - u3z(loc); - if ( u3_none == act ) { - u3t_off(glu_o); - return u3_none; - } - else { - c3_l jax_l; - u3_noun hap, bal, jit, inx; - - u3x_qual(act, &jax_l, &hap, &bal, &jit); - - if ( u3_none == (inx = u3kdb_get(u3k(hap), u3k(axe))) ) { - u3t_off(glu_o); - { - c3_o pof_o = __(u3C.wag_w & u3o_debug_cpu); - c3_o trc_o = __(u3C.wag_w & u3o_trace); - - if ( _(pof_o) ) { - pof_o = u3t_come(bal); - } - if ( _(trc_o) ) { - trc_o = u3t_nock_trace_push(bal); - } - u3z(act); - if ( _(pof_o) || _(trc_o) ) { - u3_noun pro = _cj_sink(cor, u3k(axe)); - - if (_(pof_o)) { - u3t_flee(); - } - if ( _(trc_o) ) { - u3t_nock_trace_pop(); - } - return pro; - } - else { - return u3_none; - } - } - } - else { - u3j_core* cop_u = &u3D.ray_u[jax_l]; - c3_l inx_l = inx; - u3j_harm* ham_u = &cop_u->arm_u[inx_l]; - c3_o pof_o = __(u3C.wag_w & u3o_debug_cpu); - c3_o trc_o = __(u3C.wag_w & u3o_trace); - u3_noun pro; - - if ( _(pof_o) ) { - pof_o = u3t_come(bal); - } - if ( _(trc_o) ) { - trc_o = u3t_nock_trace_push(bal); - } - u3z(act); - u3t_off(glu_o); - pro = _cj_kick_z(cor, cop_u, ham_u, axe); - - if ( u3_none == pro ) { - if ( _(pof_o) || _(trc_o) ) { - pro = _cj_sink(cor, u3k(axe)); - - if (_(pof_o)) { - u3t_flee(); - } - if ( _(trc_o) ) { - u3t_nock_trace_pop(); - } - } - return pro; - } - else { - if ( _(pof_o) ) { - u3t_flee(); - } - if ( _(trc_o) ) { - u3t_nock_trace_pop(); - } - return pro; - } - } - } - } -} - -/* _cj_fink_take(): copy u3j_fink from junior road. -*/ -static u3j_fink* -_cj_fink_take(u3j_fink* jun_u) -{ - c3_w i_w, len_w = jun_u->len_w; - u3j_fink* fin_u = u3a_walloc(c3_wiseof(u3j_fink) + - (len_w * c3_wiseof(u3j_fist))); - - fin_u->len_w = len_w; - fin_u->sat = u3a_take(jun_u->sat); - for ( i_w = 0; i_w < len_w; ++i_w ) { - u3j_fist* fis_u = &(fin_u->fis_u[i_w]); - u3j_fist* sif_u = &(jun_u->fis_u[i_w]); - fis_u->bat = u3a_take(sif_u->bat); - fis_u->pax = u3a_take(sif_u->pax); - } - return fin_u; -} - -/* _cj_fink_free(): lose and free everything in a u3j_fink. -*/ -static void -_cj_fink_free(u3p(u3j_fink) fin_p) -{ - c3_w i_w; - u3j_fink* fin_u = u3to(u3j_fink, fin_p); - u3z(fin_u->sat); - for ( i_w = 0; i_w < fin_u->len_w; ++i_w ) { - u3j_fist* fis_u = &(fin_u->fis_u[i_w]); - u3z(fis_u->bat); - u3z(fis_u->pax); - } - u3a_wfree(fin_u); -} - -/* u3j_rite_take(): copy junior rite references. [dst_u] is uninitialized -*/ -void -u3j_rite_take(u3j_rite* dst_u, u3j_rite* src_u) -{ - if ( u3_none == src_u->clu ) { - dst_u->clu = u3_none; - dst_u->fin_p = 0; - dst_u->own_o = c3n; - } - else { - dst_u->clu = u3a_take(src_u->clu); - dst_u->own_o = src_u->own_o; - dst_u->fin_p = ( c3n == src_u->own_o ) - ? src_u->fin_p - : u3of(u3j_fink, _cj_fink_take(u3to(u3j_fink, src_u->fin_p))); - } -} - -/* u3j_rite_merge(): copy rite references from src_u to dst_u, -** losing old references -*/ -void -u3j_rite_merge(u3j_rite* dst_u, u3j_rite* src_u) -{ - if ( u3_none != src_u->clu ) { - if ( u3_none != dst_u->clu ) { - u3z(dst_u->clu); - } - - dst_u->clu = src_u->clu; - - if ( dst_u->fin_p != src_u->fin_p ) { - if ( c3y == dst_u->own_o ) { - _cj_fink_free(dst_u->fin_p); - } - - dst_u->fin_p = src_u->fin_p; - dst_u->own_o = src_u->own_o; - } - } -} - -/* u3j_site_take(): copy junior site references. [dst_u] is uninitialized -*/ -void -u3j_site_take(u3j_site* dst_u, u3j_site* src_u) -{ - dst_u->axe = u3a_take(src_u->axe); - dst_u->bat = u3_none; - dst_u->bas = u3_none; - dst_u->pog_p = 0; - - if ( u3_none == src_u->loc ) { - dst_u->loc = u3_none; - dst_u->lab = u3_none; - dst_u->jet_o = c3n; - dst_u->cop_u = NULL; - dst_u->ham_u = NULL; - dst_u->fin_p = 0; - dst_u->fon_o = c3n; - } - else { - dst_u->loc = u3a_take(src_u->loc); - dst_u->lab = u3a_take(src_u->lab); - dst_u->jet_o = src_u->jet_o; - dst_u->cop_u = src_u->cop_u; - dst_u->ham_u = src_u->ham_u; - - if ( c3y == src_u->fon_o ) { - dst_u->fin_p = u3of(u3j_fink, _cj_fink_take(u3to(u3j_fink, src_u->fin_p))); - dst_u->fon_o = c3y; - } - else { - dst_u->fin_p = src_u->fin_p; - dst_u->fon_o = c3n; - } - } -} - -/* u3j_site_merge(): copy site references from src_u to dst_u, -** losing old references -*/ -void -u3j_site_merge(u3j_site* dst_u, u3j_site* src_u) -{ - u3z(dst_u->axe); - dst_u->axe = src_u->axe; - - if ( u3_none != src_u->loc ) { - u3z(dst_u->loc); - u3z(dst_u->lab); - dst_u->loc = src_u->loc; - dst_u->lab = src_u->lab; - dst_u->cop_u = src_u->cop_u; - dst_u->ham_u = src_u->ham_u; - dst_u->jet_o = src_u->jet_o; - - if ( dst_u->fin_p != src_u->fin_p ) { - if ( c3y == dst_u->fon_o ) { - _cj_fink_free(dst_u->fin_p); - } - - dst_u->fin_p = src_u->fin_p; - dst_u->fon_o = src_u->fon_o; - } - } -} - -/* u3j_site_ream(): refresh u3j_site after restoring from checkpoint -*/ -void -u3j_site_ream(u3j_site* sit_u) -{ - if ( u3_none != sit_u->loc ) { - u3z(sit_u->lab); - sit_u->jet_o = _cj_nail(sit_u->loc, sit_u->axe, - &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u)); - } -} - -/* _cj_site_lock(): ensure site has a valid program pointer - */ -static void -_cj_site_lock(u3_noun loc, u3_noun cor, u3j_site* sit_u) -{ - if ( (u3_none != sit_u->bat) && - (c3y == u3r_sing(sit_u->bat, u3h(cor))) ) { - return; - } - sit_u->pog_p = _cj_prog(loc, u3x_at(sit_u->axe, cor)); - if ( u3_none != sit_u->bat ) { - u3z(sit_u->bat); - } - sit_u->bat = u3k(u3h(cor)); -} - -/* _cj_burn(): stop tracing glu and call a nock program - */ -static u3_noun -_cj_burn(u3p(u3n_prog) pog_p, u3_noun cor) -{ - u3_noun pro; - u3t_off(glu_o); - pro = u3n_burn(pog_p, cor); - u3t_on(glu_o); - return pro; -} - -/* _cj_site_kick_hot(): execute site's kick on located core -** (no validity checks). -*/ -static u3_weak -_cj_site_kick_hot(u3_noun loc, u3_noun cor, u3j_site* sit_u, c3_o lok_o) -{ - u3_weak pro = u3_none; - c3_o jet_o = sit_u->jet_o; - c3_o pof_o = __(u3C.wag_w & u3o_debug_cpu); - c3_o trc_o = __(u3C.wag_w & u3o_trace); - - if ( c3n == pof_o && c3n == trc_o ) { - if ( c3y == jet_o ) { - u3t_off(glu_o); - pro = _cj_kick_z(cor, sit_u->cop_u, sit_u->ham_u, sit_u->axe); - u3t_on(glu_o); - } - if ( u3_none == pro ) { - if ( c3y == lok_o ) { - _cj_site_lock(loc, cor, sit_u); - } - } - } - else { - if ( _(pof_o) ) { - pof_o = u3t_come(sit_u->lab); - } - if ( _(trc_o) ) { - trc_o = u3t_nock_trace_push(sit_u->lab); - } - - if ( c3y == jet_o ) { - u3t_off(glu_o); - pro = _cj_kick_z(cor, sit_u->cop_u, sit_u->ham_u, sit_u->axe); - u3t_on(glu_o); - } - if ( u3_none == pro ) { - if ( c3y == lok_o ) { - _cj_site_lock(loc, cor, sit_u); - } - pro = _cj_burn(sit_u->pog_p, cor); - } - - if ( c3y == pof_o ) { - u3t_flee(); - } - if ( c3y == trc_o ) { - u3t_nock_trace_pop(); - } - } - - return pro; -} - -/* _cj_site_kick(): execute site's kick on core. - */ -static u3_weak -_cj_site_kick(u3_noun cor, u3j_site* sit_u) -{ - u3_weak loc, pro; - - loc = pro = u3_none; - - if ( u3_none != sit_u->loc ) { - if ( c3y == _cj_fine(cor, sit_u->fin_p) ) { - loc = sit_u->loc; - pro = _cj_site_kick_hot(loc, cor, sit_u, c3y); - } - } - - if ( u3_none == loc ) { - loc = _cj_spot(cor, &(sit_u->bas)); - if ( u3_none != loc ) { - u3p(u3j_fink) fon_p = 0; - u3_weak lod = u3_none; - u3_weak lob = u3_none; - - if ( u3_none != sit_u->loc ) { - lod = sit_u->loc; - lob = sit_u->lab; - if ( c3y == sit_u->fon_o ) { - fon_p = sit_u->fin_p; - } - } - - sit_u->loc = loc; - sit_u->fin_p = _cj_cast(cor, loc); - sit_u->fon_o = c3y; - sit_u->jet_o = _cj_nail(loc, sit_u->axe, - &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u)); - pro = _cj_site_kick_hot(loc, cor, sit_u, c3y); - - if ( u3_none != lod ) { - u3z(lod); - u3z(lob); - if ( 0 != fon_p ) { - _cj_fink_free(fon_p); - } - } - } - } - - if ( u3_none == pro ) { - _cj_site_lock(loc, cor, sit_u); - } - - return pro; -} - -/* u3j_site_kick(): kick a core with a u3j_site cache. - */ -u3_weak -u3j_site_kick(u3_noun cor, u3j_site* sit_u) -{ - u3_weak pro; - u3t_on(glu_o); - pro = _cj_site_kick(cor, sit_u); - u3t_off(glu_o); - return pro; -} - -/* u3j_cook(): Execute hook from core, call site cached by arbitrary c string -*/ -u3_noun -u3j_cook(const c3_c* key_c, - u3_noun cor, - const c3_c* tam_c) -{ - u3_noun pro, key, tam, inn; - _cj_hank* han_u; - - u3t_on(glu_o); - key = u3i_string(key_c); - tam = u3i_string(tam_c); - han_u = _cj_hank_find(key, tam); - if ( c3n == _cj_hank_fine(han_u, cor, &inn) ) { - _cj_hank_lose(han_u); - inn = _cj_hank_fill(han_u, tam, cor); - } - pro = _cj_site_kick(u3k(inn), &(han_u->sit_u)); - if ( u3_none == pro ) { - pro = _cj_burn(han_u->sit_u.pog_p, inn); - } - u3z(cor); - - u3z(key); - u3z(tam); - u3t_off(glu_o); - return pro; -} - -/* u3j_kink(): kick either by jet or by nock. -*/ -u3_noun -u3j_kink(u3_noun cor, u3_noun axe) -{ - u3_weak pro = u3j_kick(cor, axe); - - if ( u3_none != pro ) { - return pro; - } - else { - return _cj_sink(cor, axe); - } -} - -/* u3j_gate_prep(): prepare a locally cached gate to call repeatedly. - * core is TRANSFERRED. - */ -void -u3j_gate_prep(u3j_site* sit_u, u3_noun cor) -{ - u3_noun loc; - u3t_on(glu_o); - if ( c3n == u3du(cor) || c3n == u3du(u3t(cor)) ) { - u3m_bail(c3__exit); - return; - } - sit_u->bas = u3_none; - sit_u->axe = 2; - sit_u->bat = cor; // a lie, this isn't really the battery! - sit_u->loc = loc = _cj_spot(cor, &(sit_u->bas)); - sit_u->pog_p = _cj_prog(loc, u3h(cor)); - if ( u3_none != loc ) { - u3_noun pax = _cj_loc_axe(loc), - pay = u3qc_cap(pax), - pam = u3qc_mas(pax); - if ( 3 != pay || 2 == pam || (3 != pam && 3 != u3qc_cap(pam)) ) { - u3l_log("u3j_gate_prep(): parent axis includes sample"); - u3m_p("axis", pax); - u3_weak act = _cj_find_warm(loc); - c3_assert( u3_none != act ); - sit_u->jet_o = c3n; - sit_u->lab = u3k(u3h(u3t(u3t(act)))); - u3z(act); - } - else { - sit_u->jet_o = _cj_nail(loc, 2, - &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u)); - } - u3z(pam); u3z(pax); - } - u3t_off(glu_o); -} - -/* u3j_gate_slam(): slam a site prepared by u3j_gate_find() with sample. - * sam is TRANSFERRED. - */ -u3_noun -u3j_gate_slam(u3j_site* sit_u, u3_noun sam) -{ - u3_weak pro; - u3_noun cor; - - u3t_on(glu_o); - pro = u3_none; - cor = u3nt(u3k(u3h(sit_u->bat)), - sam, - u3k(u3t(u3t(sit_u->bat)))); - if ( u3_none != sit_u->loc ) { - pro = _cj_site_kick_hot(sit_u->loc, cor, sit_u, c3n); - } - if ( u3_none == pro ) { - pro = _cj_burn(sit_u->pog_p, cor); - } - u3t_off(glu_o); - return pro; -} - -/* u3j_gate_lose(): clean up site prepared by u3j_gate_find(). - */ -void -u3j_gate_lose(u3j_site* sit_u) -{ - u3z(sit_u->bat); - u3z(sit_u->bas); - if ( u3_none != sit_u->loc ) { - u3z(sit_u->loc); - u3z(sit_u->lab); - } -} - -/* _cj_minx(): produce location of core from fsck'd clue. RETAIN. - */ -static u3_weak -_cj_minx(u3_noun cey, u3_noun cor) -{ - u3_noun nam, axe, huc; - u3x_trel(cey, &nam, &axe, &huc); - - if ( 0 == axe ) { - return u3nt(u3nt(c3y, c3y, u3k(u3t(cor))), u3k(nam), u3k(huc)); - } - else { - u3_weak par, pel; - u3_noun pat; - - par = u3r_at(axe, cor); - if ( u3_none == par || c3n == u3du(par) ) { - u3l_log("fund: %s is bogus", u3r_string(nam)); - return u3_none; - } - pel = _cj_spot(par, NULL); - if ( u3_none == pel ) { - u3l_log("fund: in %s, parent %x not found at %d", - u3r_string(nam), - u3r_mug(u3h(par)), - axe); - return u3_none; - } - pat = ( ( 3 == axe ) && (c3y == u3h(u3h(pel))) ) - ? u3nt(c3y, c3n, pel) - : u3nt(c3n, u3k(axe), pel); - return u3nt(pat, u3k(nam), u3k(huc)); - } -} - -static void -_cj_print_tas(u3_noun tas) -{ - c3_w met_w = u3r_met(3, tas); - c3_c* str_c = alloca(met_w + 1); - u3r_bytes(0, met_w, (c3_y*)str_c, tas); - str_c[met_w] = 0; - u3l_log("/%s", str_c); -} - -/* _cj_mine(): declare a core and produce location. RETAIN. -*/ -static u3_weak -_cj_mine(u3_noun cey, u3_noun cor, u3_noun bas) -{ - u3_weak loc = _cj_minx(cey, cor); - if ( u3_none != loc ) { - c3_l par_l, jax_l; - u3_noun pel = _cj_loc_pel(loc), - axe = _cj_loc_axe(loc), - bat = u3h(cor), - nam = u3h(u3t(loc)), - bar = _cj_find_cold(bat), - reg, hap, bal, act; - if ( u3_none == bar ) { - reg = u3_none; - } - else { - reg = u3k(u3t(bar)); - u3z(bar); - } - reg = _cj_gust(reg, u3k(axe), u3k(pel), u3k(loc)); - if ( 0 == axe ) { - par_l = 0; - bal = u3nc(u3k(nam), u3_nul); - } - else { - u3_weak pac = _cj_find_warm(pel); - c3_assert(u3_none != pac); - par_l = u3h(pac); - bal = u3nc(u3k(nam), u3k(u3h(u3t(u3t(pac))))); - u3z(pac); - } - jax_l = _cj_hot_mean(par_l, nam); -#if 0 - u3m_p("new jet", bal); - u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l); -#endif - - if ( !(u3C.wag_w & u3o_hashless) ) { - if ( jax_l ) { - c3_y dig_y[32]; - c3_w i_w; - u3_noun i = bal; - u3l_log("hot jet: "); - while ( i != u3_nul ) { - _cj_print_tas(u3h(i)); - i = u3t(i); - } - u3l_log("\r\n axe %d, jax %d,\r\n bash ", axe, jax_l); - u3r_bytes(0, 32, dig_y, bas); - for ( i_w = 32; i_w > 0; ) { - u3l_log("%02x", dig_y[--i_w]); - } - u3l_log(""); - } - } - - hap = _cj_warm_hump(jax_l, u3t(u3t(loc))); - act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat)); - u3h_put(u3R->jed.cod_p, bat, u3nc(u3k(bas), reg)); - u3h_put(u3R->jed.war_p, loc, act); // see note in _cj_spot - u3z(pel); u3z(axe); - } - - return loc; -#if 0 - { - u3_noun bas = _cj_bash(bat), - hot = u3h_get(u3D.hot_p, bas); - c3_o hav_o = c3n; - - if ( u3_none != hot ) { - u3_noun her = u3h(hot), - hol = _cj_reg_find(her, cor); - if ( hol != u3_none ) { - hav_o = c3y; - u3z(hol); - } - u3z(hot); - } - - if ( c3n == hav_o ) { - u3m_p("unregistered battery", bal); - u3l_log("hash: %x", bas); - } - u3z(bas); - } -#endif -} - -static void -_cj_audit(u3_noun loc, u3_noun cey, u3_noun cor) -{ - u3_noun pat, nam, huc, cax, can, cuc, pax; - - u3x_trel(loc, &pat, &nam, &huc); - u3x_trel(cey, &can, &cax, &cuc); - - pax = _cj_loc_axe(loc); - - if ( (c3n == u3r_sing(nam, can)) || - (c3n == u3r_sing(pax, cax)) || - (c3n == u3r_sing(huc, cuc)) ) { - u3_noun mix = _cj_minx(cey, cor); - u3m_p("bad audit", loc); - u3m_p("hint says", mix); - u3z(mix); - } - - u3z(pax); -} - -/* _cj_mile(): register core for jets, returning location. -*/ -static u3_weak -_cj_mile(u3_noun clu, u3_noun cor) -{ - u3_weak loc = u3_none; - if ( c3n == u3du(cor) ) { - u3z(clu); - u3z(cor); - } - else { - u3_weak cey = _cj_je_fsck(clu); - if ( u3_none != cey ) { - u3_weak bas = u3_none; - loc = _cj_spot(cor, &bas); - if ( u3_none == loc ) { - loc = _cj_mine(cey, cor, bas); - } - else { - _cj_audit(loc, cey, cor); - } - u3z(cey); - if ( u3_none != bas ) { - u3z(bas); - } - } - u3z(cor); - } - return loc; -} - -/* u3j_mine(): register core for jets. -*/ -void -u3j_mine(u3_noun clu, u3_noun cor) -{ - u3_weak loc; - u3t_on(glu_o); - loc = _cj_mile(clu, cor); - u3z(loc); - u3t_off(glu_o); -} - -/* u3j_rite_mine(): mine cor with clue, using u3j_rite for caching -*/ -void -u3j_rite_mine(u3j_rite* rit_u, u3_noun clu, u3_noun cor) -{ - c3_t non_t; - u3t_on(glu_o); - - non_t = (u3_none == rit_u->clu); - - if ( non_t || - c3n == u3r_sing(rit_u->clu, clu) || - c3n == _cj_fine(cor, rit_u->fin_p) ) { - u3_weak loc = _cj_mile(u3k(clu), u3k(cor)); - if ( u3_none != loc ) { - u3p(u3j_fink) fon_p = rit_u->fin_p; - u3_noun old = rit_u->clu; - c3_o own_o = rit_u->own_o; - rit_u->own_o = c3y; - rit_u->clu = u3k(clu); - rit_u->fin_p = _cj_cast(cor, loc); - u3z(loc); - - if ( !non_t && (c3y == own_o) ) { - u3z(old); - _cj_fink_free(fon_p); - } - } - } - u3z(clu); - u3z(cor); - u3t_off(glu_o); -} - -/* _cj_take_hank_cb(): u3h_take_with cb for taking hanks -*/ -static u3p(_cj_hank) -_cj_take_hank_cb(u3p(_cj_hank) nah_p) -{ - _cj_hank* nah_u = u3to(_cj_hank, nah_p); - _cj_hank* han_u = u3a_walloc(c3_wiseof(_cj_hank)); - - if ( u3_none == nah_u->hax ) { - han_u->hax = u3_none; - // han_u->sit_u left uninitialized, will be ignored - } - else { - han_u->hax = u3a_take(nah_u->hax); - u3j_site_take(&(han_u->sit_u), &(nah_u->sit_u)); - } - - return u3of(_cj_hank, han_u); -} - -/* u3j_take(): copy junior jet state. -*/ -u3a_jets -u3j_take(u3a_jets jed_u) -{ - jed_u.war_p = u3h_take(jed_u.war_p); - jed_u.cod_p = u3h_take(jed_u.cod_p); - jed_u.han_p = u3h_take_with(jed_u.han_p, _cj_take_hank_cb); - jed_u.bas_p = u3h_take(jed_u.bas_p); - return jed_u; -} - -/* _cj_merge_hank_cb(): u3h_uni_with cb for integrating taken hanks -** NB "transfers" or frees hanks in jed_u.han_p -*/ -static void -_cj_merge_hank_cb(u3_noun kev, void* wit) -{ - u3p(u3h_root) han_p = *(u3p(u3h_root)*)wit; - _cj_hank* nah_u; - u3_noun key; - u3p(_cj_hank) nah_p; - u3x_cell(kev, &key, &nah_p); - - nah_u = u3to(_cj_hank, nah_p); - - if ( u3_none == nah_u->hax ) { - u3a_wfree(nah_u); - } - else { - _cj_hank* han_u; - u3_weak got = u3h_git(u3R->jed.han_p, key); - - if ( u3_none == got ) { - han_u = nah_u; - } - else { - han_u = u3to(_cj_hank, got); - - if ( u3_none != han_u->hax ) { - u3z(han_u->hax); - } - han_u->hax = nah_u->hax; - - u3j_site_merge(&(han_u->sit_u), &(nah_u->sit_u)); - u3a_wfree(nah_u); - } - - u3h_put(han_p, key, u3of(_cj_hank, han_u)); - } -} - -/* u3j_reap(): promote jet state. -*/ -void -u3j_reap(u3a_jets jed_u) -{ - u3h_uni(u3R->jed.war_p, jed_u.war_p); - u3h_free(jed_u.war_p); - - u3h_uni(u3R->jed.cod_p, jed_u.cod_p); - u3h_free(jed_u.cod_p); - - u3h_walk_with(jed_u.han_p, _cj_merge_hank_cb, &u3R->jed.han_p); - u3h_free(jed_u.han_p); - - u3h_uni(u3R->jed.bas_p, jed_u.bas_p); - u3h_free(jed_u.bas_p); -} - -/* _cj_ream(): ream list of battery [bash registry] pairs. RETAIN. - */ -static void -_cj_ream(u3_noun all) -{ - c3_l par_l, jax_l; - u3_noun i, j, k, rul, loc, bal, act, lop, kev, rut, hap, - pat, reg, pol, rem, rec, bat, pel, nam, huc; - u3_weak pac; - - for ( i = all, lop = u3_nul; i != u3_nul; i = u3t(i) ) { - kev = u3h(i); - bat = u3h(kev); - reg = u3t(u3t(kev)); - rut = u3h(reg); - - // register roots - rul = u3qdb_tap(rut); - for ( j = rul; j != u3_nul; j = u3t(j) ) { - loc = u3t(u3h(j)); - u3x_trel(loc, &pat, &nam, &huc); - bal = u3nc(u3k(nam), u3_nul); - jax_l = _cj_hot_mean(0, nam); - hap = _cj_warm_hump(jax_l, huc); - act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat)); -#if 0 - u3m_p("old jet", bal); - u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l); -#endif - u3h_put(u3R->jed.war_p, loc, act); - } - u3z(rul); - - // put ancestors in lop (list [battery=^ parent=location this=location]) - for ( j = u3t(reg); j != u3_nul; j = u3t(j) ) { - pol = lop; - lop = u3qdb_tap(u3t(u3h(j))); - for ( k = lop; u3_nul != k; k = u3t(k) ) { - pol = u3nc(u3nc(u3k(bat), u3k(u3h(k))), pol); - } - u3z(lop); - lop = pol; - } - } - - // ordering is random so we need to push onto rem when parent - // isn't yet present in the warm state - while ( u3_nul != lop ) { - rem = u3_nul; - for ( i = lop; u3_nul != i; i = u3t(i) ) { - rec = u3h(i); - u3x_trel(rec, &bat, &pel, &loc); - pac = _cj_find_warm(pel); - if ( u3_none == pac ) { - rem = u3nc(u3k(rec), rem); - } - else { - u3x_trel(loc, &pat, &nam, &huc); - par_l = u3h(pac); - jax_l = _cj_hot_mean(par_l, nam); - bal = u3nc(u3k(nam), u3k(u3h(u3t(u3t(pac))))); - hap = _cj_warm_hump(jax_l, huc), - u3z(pac); - act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat)); -#if 0 - u3m_p("old jet", bal); - u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l); -#endif - u3h_put(u3R->jed.war_p, loc, act); - } - } - u3z(lop); - lop = rem; - } -} - -/* _cj_warm_tap(): tap war_p to rel -*/ -static void -_cj_warm_tap(u3_noun kev, void* wit) -{ - u3_noun* rel = wit; - *rel = u3nc(u3k(kev), *rel); -} - -/* _cj_ream_hank(): clear hot state out of hook sites. -*/ -static void -_cj_ream_hank(u3_noun kev) -{ - u3j_site_ream(&(u3to(_cj_hank, u3t(kev))->sit_u)); -} - -/* u3j_ream(): rebuild warm state -*/ -void -u3j_ream(void) -{ - u3_noun rel = u3_nul; - c3_assert(u3R == &(u3H->rod_u)); - u3h_free(u3R->jed.war_p); - u3R->jed.war_p = u3h_new(); - u3h_walk_with(u3R->jed.cod_p, _cj_warm_tap, &rel); - _cj_ream(rel); - u3z(rel); - - u3h_walk(u3R->jed.han_p, _cj_ream_hank); -} - -/* u3j_stay(): extract cold state -*/ -u3_noun -u3j_stay(void) -{ - u3_noun rel = u3_nul; - c3_assert(u3R == &(u3H->rod_u)); - u3h_walk_with(u3R->jed.cod_p, _cj_warm_tap, &rel); - return rel; -} - -/* u3j_load(): inject cold state -*/ -void -u3j_load(u3_noun rel) -{ - u3_noun ler = rel; - u3_noun lor; - - while ( u3_nul != ler ) { - u3x_cell(ler, &lor, &ler); - u3h_put(u3R->jed.cod_p, u3h(lor), u3k(u3t(lor))); - } - - u3z(rel); -} - -/* _cj_fink_mark(): mark a u3j_fink for gc. -*/ -static c3_w -_cj_fink_mark(u3j_fink* fin_u) -{ - c3_w i_w, tot_w = u3a_mark_noun(fin_u->sat); - for ( i_w = 0; i_w < fin_u->len_w; ++i_w ) { - u3j_fist* fis_u = &(fin_u->fis_u[i_w]); - tot_w += u3a_mark_noun(fis_u->bat); - tot_w += u3a_mark_noun(fis_u->pax); - } - tot_w += u3a_mark_ptr(fin_u); - return tot_w; -} - -/* u3j_site_lose(): lose references of u3j_site (but do not free). - */ -void -u3j_site_lose(u3j_site* sit_u) -{ - u3z(sit_u->axe); - if ( u3_none != sit_u->bat ) { - u3z(sit_u->bat); - } - if ( u3_none != sit_u->bas ) { - u3z(sit_u->bas); - } - if ( u3_none != sit_u->loc ) { - u3z(sit_u->loc); - u3z(sit_u->lab); - if ( c3y == sit_u->fon_o ) { - _cj_fink_free(sit_u->fin_p); - } - } -} - -/* u3j_rite_lose(): lose references of u3j_rite (but do not free). - */ -void -u3j_rite_lose(u3j_rite* rit_u) -{ - if ( (c3y == rit_u->own_o) && u3_none != rit_u->clu ) { - u3z(rit_u->clu); - _cj_fink_free(rit_u->fin_p); - } -} - -/* u3j_rite_mark(): mark u3j_rite for gc. -*/ -c3_w -u3j_rite_mark(u3j_rite* rit_u) -{ - c3_w tot_w = 0; - if ( (c3y == rit_u->own_o) && u3_none != rit_u->clu ) { - tot_w += u3a_mark_noun(rit_u->clu); - tot_w += _cj_fink_mark(u3to(u3j_fink, rit_u->fin_p)); - } - return tot_w; -} - -/* u3j_site_mark(): mark u3j_site for gc. -*/ -c3_w -u3j_site_mark(u3j_site* sit_u) -{ - c3_w tot_w = u3a_mark_noun(sit_u->axe); - if ( u3_none != sit_u->bat ) { - tot_w += u3a_mark_noun(sit_u->bat); - } - if ( u3_none != sit_u->bas ) { - tot_w += u3a_mark_noun(sit_u->bas); - } - if ( u3_none != sit_u->loc ) { - tot_w += u3a_mark_noun(sit_u->loc); - tot_w += u3a_mark_noun(sit_u->lab); - if ( c3y == sit_u->fon_o ) { - tot_w += _cj_fink_mark(u3to(u3j_fink, sit_u->fin_p)); - } - } - return tot_w; -} - -/* _cj_mark_hank(): mark hank cache for gc. -*/ -static void -_cj_mark_hank(u3_noun kev, void* dat) -{ - c3_w* tot_w = (c3_w*) dat; - _cj_hank* han_u = u3to(_cj_hank, u3t(kev)); - *tot_w += u3a_mark_ptr(han_u); - if ( u3_none != han_u->hax ) { - *tot_w += u3a_mark_noun(han_u->hax); - *tot_w += u3j_site_mark(&(han_u->sit_u)); - } -} - -/* u3j_mark(): mark jet state for gc. -*/ -c3_w -u3j_mark(FILE* fil_u) -{ - c3_w tot_w = 0; - - tot_w += u3a_maid(fil_u, " warm jet state", u3h_mark(u3R->jed.war_p)); - tot_w += u3a_maid(fil_u, " cold jet state", u3h_mark(u3R->jed.cod_p)); - tot_w += u3a_maid(fil_u, " hank cache", u3h_mark(u3R->jed.han_p)); - tot_w += u3a_maid(fil_u, " battery hash cache", u3h_mark(u3R->jed.bas_p)); - - { - c3_w han_w = 0; - u3h_walk_with(u3R->jed.han_p, _cj_mark_hank, &han_w); - tot_w += u3a_maid(fil_u, " call site cache", han_w); - } - - if ( u3R == &(u3H->rod_u) ) { - tot_w += u3a_maid(fil_u, " hot jet state", u3h_mark(u3R->jed.hot_p)); - } - - return u3a_maid(fil_u, "total jet stuff", tot_w); -} - -/* _cj_free_hank(): free an entry from the hank cache. -*/ -static void -_cj_free_hank(u3_noun kev) -{ - _cj_hank* han_u = u3to(_cj_hank, u3t(kev)); - if ( u3_none != han_u->hax ) { - u3z(han_u->hax); - u3j_site_lose(&(han_u->sit_u)); - } - u3a_wfree(han_u); -} - -/* u3j_free(): free jet state. -*/ -void -u3j_free(void) -{ - u3h_walk(u3R->jed.han_p, _cj_free_hank); - u3h_free(u3R->jed.war_p); - u3h_free(u3R->jed.cod_p); - u3h_free(u3R->jed.han_p); - u3h_free(u3R->jed.bas_p); - if ( u3R == &(u3H->rod_u) ) { - u3h_free(u3R->jed.hot_p); - } -} - -/* u3j_reclaim(): clear ad-hoc persistent caches to reclaim memory. -*/ -void -u3j_reclaim(void) -{ - // re-establish the warm jet state - // - // XX might this reduce fragmentation? - // - // if ( &(u3H->rod_u) == u3R ) { - // u3j_ream(); - // } - - // clear the jet hank cache - // - u3h_walk(u3R->jed.han_p, _cj_free_hank); - u3h_free(u3R->jed.han_p); - u3R->jed.han_p = u3h_new(); -} - -/* u3j_rewrite_compact(): rewrite jet state for compaction. - * - * NB: u3R->jed.han_p *must* be cleared (currently via u3j_reclaim above) - * since it contains hanks which are not nouns but have loom pointers. - * Alternately, rewrite the entries with u3h_walk, using u3j_mark as a - * template for how to walk. There's an untested attempt at this in git - * history at e8a307a. -*/ -void -u3j_rewrite_compact() -{ - u3h_rewrite(u3R->jed.war_p); - u3h_rewrite(u3R->jed.cod_p); - u3h_rewrite(u3R->jed.han_p); - u3h_rewrite(u3R->jed.bas_p); - - if ( u3R == &(u3H->rod_u) ) { - u3h_rewrite(u3R->jed.hot_p); - u3R->jed.hot_p = u3a_rewritten(u3R->jed.hot_p); - } - - u3R->jed.war_p = u3a_rewritten(u3R->jed.war_p); - u3R->jed.cod_p = u3a_rewritten(u3R->jed.cod_p); - u3R->jed.han_p = u3a_rewritten(u3R->jed.han_p); - u3R->jed.bas_p = u3a_rewritten(u3R->jed.bas_p); -} diff --git a/pkg/urbit/noun/log.c b/pkg/urbit/noun/log.c deleted file mode 100644 index ddab9d52b..000000000 --- a/pkg/urbit/noun/log.c +++ /dev/null @@ -1,39 +0,0 @@ -/* noun/log.c -** -*/ -#include "all.h" - -#include - -void -u3l_log(const char* format, ...) -{ - va_list myargs; - va_start(myargs, format); - - if (u3C.stderr_log_f) { - // the user set their own logging function. render the line and redirect - // to them. - // - char msg[4096]; - vsnprintf(msg, 4096, format, myargs); - u3C.stderr_log_f(msg); - } else { - // this process did not set a logging function, fallback to stderr - // - vfprintf(stderr, format, myargs); - fprintf(stderr, "\r\n"); - fflush(stderr); - } - - va_end(myargs); -} - -u3_weak -u3l_punt(const char* name, u3_weak pro) -{ - if ( u3_none == pro ) { - u3l_log("%s-punt", name); - } - return pro; -} diff --git a/pkg/urbit/noun/manage.c b/pkg/urbit/noun/manage.c deleted file mode 100644 index 7052c4d40..000000000 --- a/pkg/urbit/noun/manage.c +++ /dev/null @@ -1,2002 +0,0 @@ -/* n/m.c -** -*/ -#include "all.h" -#include "rsignal.h" -#include "vere/vere.h" -#include -#include -#include -#include -#include -#include - -// XX stack-overflow recovery should be gated by -a -// -#undef NO_OVERFLOW - - /* (u3_noun)setjmp(u3R->esc.buf): setjmp within road. - */ -#if 0 - c3_o - u3m_trap(void); -#else -# define u3m_trap() (u3_noun)(_setjmp(u3R->esc.buf)) -#endif - - /* u3m_signal(): treat a nock-level exception as a signal interrupt. - */ - void - u3m_signal(u3_noun sig_l); - - /* u3m_dump(): dump the current road to stderr. - */ - void - u3m_dump(void); - - /* u3m_fall(): return to parent road. - */ - void - u3m_fall(void); - - /* u3m_leap(): in u3R, create a new road within the existing one. - */ - void - u3m_leap(c3_w pad_w); - - /* u3m_golf(): record cap length for u3m_flog(). - */ - c3_w - u3m_golf(void); - - /* u3m_flog(): pop the cap. - ** - ** A common sequence for inner allocation is: - ** - ** c3_w gof_w = u3m_golf(); - ** u3m_leap(); - ** // allocate some inner stuff... - ** u3m_fall(); - ** // inner stuff is still valid, but on cap - ** u3m_flog(gof_w); - ** - ** u3m_flog(0) simply clears the cap. - */ - void - u3m_flog(c3_w gof_w); - - /* u3m_soft_top(): top-level safety wrapper. - */ - u3_noun - u3m_soft_top(c3_w mil_w, // timer ms - c3_w pad_w, // base memory pad - u3_funk fun_f, - u3_noun arg); - - -// u3m_signal uses restricted functionality signals for compatibility reasons: -// some platforms may not provide true POSIX asynchronous signals and their -// compat layer will then implement this restricted functionality subset. -// u3m_signal never needs to interrupt I/O operations, its signal handlers -// do not manipulate signals, do not modify shared state, and always either -// return or longjmp. -// -static rsignal_jmpbuf u3_Signal; - -#if !defined(U3_OS_mingw) -#include - -#ifndef SIGSTKSZ -# define SIGSTKSZ 16384 -#endif -#ifndef NO_OVERFLOW -static uint8_t Sigstk[SIGSTKSZ]; -#endif -#endif - -#if 0 -/* _cm_punt(): crudely print trace. -*/ -static void -_cm_punt(u3_noun tax) -{ - u3_noun xat; - - for ( xat = tax; xat; xat = u3t(xat) ) { - u3m_p("&", u3h(xat)); - } -} -#endif - -/* _cm_emergency(): write emergency text to stderr, never failing. -*/ -static void -_cm_emergency(c3_c* cap_c, c3_l sig_l) -{ - c3_i ret_i; - - ret_i = write(2, "\r\n", 2); - ret_i = write(2, cap_c, strlen(cap_c)); - - if ( sig_l ) { - ret_i = write(2, ": ", 2); - ret_i = write(2, &sig_l, 4); - } - - ret_i = write(2, "\r\n", 2); -} - -static void _cm_overflow(void *arg1, void *arg2, void *arg3) -{ - (void)(arg1); - (void)(arg2); - (void)(arg3); - u3m_signal(c3__over); -} - -/* _cm_signal_handle(): handle a signal in general. -*/ -static void -_cm_signal_handle(c3_l sig_l) -{ -#ifndef U3_OS_mingw - if ( c3__over == sig_l ) { -#ifndef NO_OVERFLOW - sigsegv_leave_handler(_cm_overflow, NULL, NULL, NULL); -#endif - } else -#endif - { - u3m_signal(sig_l); - } -} - -#ifndef NO_OVERFLOW -static void -#ifndef U3_OS_mingw -_cm_signal_handle_over(int emergency, stackoverflow_context_t scp) -#else -_cm_signal_handle_over(int x) -#endif -{ - _cm_signal_handle(c3__over); -} -#endif - -static void -_cm_signal_handle_term(int x) -{ - // Ignore if we are using base memory from work memory, very rare. - // - if ( (0 != u3H->rod_u.kid_p) && (&(u3H->rod_u) == u3R) ) { - _cm_emergency("ignored", c3__term); - } - else { - _cm_signal_handle(c3__term); - } -} - -static void -_cm_signal_handle_intr(int x) -{ - // Interrupt: stop work. Ignore if not working, or (rarely) using base. - // - if ( &(u3H->rod_u) == u3R ) { - _cm_emergency("ignored", c3__intr); - } - else { - _cm_signal_handle(c3__intr); - } -} - -static void -_cm_signal_handle_alrm(int x) -{ - _cm_signal_handle(c3__alrm); -} - -/* _cm_signal_reset(): reset top road after signal longjmp. -*/ -static void -_cm_signal_reset(void) -{ - u3R = &u3H->rod_u; - u3R->cap_p = u3R->mat_p; - u3R->ear_p = 0; - u3R->kid_p = 0; -} - -#if 0 -/* _cm_stack_recover(): recover stack trace, with lacunae. -*/ -static u3_noun -_cm_stack_recover(u3a_road* rod_u) -{ - c3_w len_w; - - len_w = 0; - { - u3_noun tax = rod_u->bug.tax; - - while ( tax ) { - len_w++; - tax = u3t(tax); - } - - if ( len_w < 4096 ) { - return u3a_take(rod_u->bug.tax); - } - else { - u3_noun beg, fin; - c3_w i_w; - - tax = rod_u->bug.tax; - beg = u3_nul; - for ( i_w = 0; i_w < 2048; i_w++ ) { - beg = u3nc(u3a_take(u3h(tax)), beg); - tax = u3t(tax); - } - beg = u3kb_flop(beg); - - for ( i_w = 0; i_w < (len_w - 4096); i_w++ ) { - tax = u3t(tax); - } - fin = u3nc(u3nc(c3__lose, c3__over), u3a_take(tax)); - - return u3kb_weld(beg, fin); - } - } -} -#endif - -/* _cm_stack_unwind(): unwind to the top level, preserving all frames. -*/ -static u3_noun -_cm_stack_unwind(void) -{ - u3_noun tax; - - while ( u3R != &(u3H->rod_u) ) { - u3_noun yat = u3m_love(u3R->bug.tax); - - u3R->bug.tax = u3kb_weld(yat, u3R->bug.tax); - } - tax = u3R->bug.tax; - - u3R->bug.tax = 0; - return tax; -} - -/* _cm_signal_recover(): recover from a deep signal, after longjmp. Free arg. -*/ -static u3_noun -_cm_signal_recover(c3_l sig_l, u3_noun arg) -{ - u3_noun tax; - - // Unlikely to be set, but it can be made to happen. - // - tax = u3H->rod_u.bug.tax; - u3H->rod_u.bug.tax = 0; - - if ( &(u3H->rod_u) == u3R ) { - // A top-level crash - rather odd. We should GC. - // - _cm_emergency("recover: top", sig_l); - u3C.wag_w |= u3o_check_corrupt; - - // Reset the top road - the problem could be a fat cap. - // - _cm_signal_reset(); - - if ( (c3__meme == sig_l) && (u3a_open(u3R) <= 256) ) { - // Out of memory at the top level. Error becomes c3__full, - // and we release the emergency buffer. To continue work, - // we need to readjust the image, eg, migrate to 64 bit. - // - u3z(u3R->bug.mer); - u3R->bug.mer = 0; - sig_l = c3__full; - } - return u3nt(3, sig_l, tax); - } - else { - u3_noun pro; - - // A signal was generated while we were within Nock. - // - _cm_emergency("recover: dig", sig_l); - -#if 0 - // Descend to the innermost trace, collecting stack. - // - { - u3a_road* rod_u; - - u3R = &(u3H->rod_u); - rod_u = u3R; - - while ( rod_u->kid_p ) { -#if 0 - u3l_log("collecting %d frames", - u3kb_lent((u3to(u3_road, rod_u->kid_p)->bug.tax)); -#endif - tax = u3kb_weld(_cm_stack_recover(u3to(u3_road, rod_u->kid_p)), tax); - rod_u = u3to(u3_road, rod_u->kid_p); - } - } -#else - tax = _cm_stack_unwind(); -#endif - pro = u3nt(3, sig_l, tax); - _cm_signal_reset(); - - u3z(arg); - return pro; - } -} - -/* _cm_signal_deep(): start deep processing; set timer for [mil_w] or 0. -*/ -static void -_cm_signal_deep(c3_w mil_w) -{ - // disable outer system signal handling - // - if ( 0 != u3C.sign_hold_f ) { - u3C.sign_hold_f(); - } - -#ifndef NO_OVERFLOW -#ifndef U3_OS_mingw - stackoverflow_install_handler(_cm_signal_handle_over, Sigstk, SIGSTKSZ); -#else - rsignal_install_handler(SIGSTK, _cm_signal_handle_over); -#endif -#endif - rsignal_install_handler(SIGINT, _cm_signal_handle_intr); - rsignal_install_handler(SIGTERM, _cm_signal_handle_term); - - // Provide a little emergency memory, for use in case things - // go utterly haywire. - // - if ( 0 == u3H->rod_u.bug.mer ) { - u3H->rod_u.bug.mer = u3i_string( - "emergency buffer with sufficient space to cons the trace and bail" - ); - } - - if ( mil_w ) { - struct itimerval itm_u; - - timerclear(&itm_u.it_interval); - itm_u.it_value.tv_sec = (mil_w / 1000); - itm_u.it_value.tv_usec = 1000 * (mil_w % 1000); - - if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) { - u3l_log("loom: set timer failed %s", strerror(errno)); - } - else { - rsignal_install_handler(SIGVTALRM, _cm_signal_handle_alrm); - } - } - - u3t_boot(); -} - -/* _cm_signal_done(): -*/ -static void -_cm_signal_done() -{ - rsignal_deinstall_handler(SIGINT); - rsignal_deinstall_handler(SIGTERM); - rsignal_deinstall_handler(SIGVTALRM); - -#ifndef NO_OVERFLOW -#ifndef U3_OS_mingw - stackoverflow_deinstall_handler(); -#else - rsignal_deinstall_handler(SIGSTK); -#endif -#endif - { - struct itimerval itm_u; - - timerclear(&itm_u.it_interval); - timerclear(&itm_u.it_value); - - if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) { - u3l_log("loom: clear timer failed %s", strerror(errno)); - } - } - - // restore outer system signal handling - // - if ( 0 != u3C.sign_move_f ) { - u3C.sign_move_f(); - } - - u3t_boff(); -} - -/* u3m_signal(): treat a nock-level exception as a signal interrupt. -*/ -void -u3m_signal(u3_noun sig_l) -{ - rsignal_longjmp(u3_Signal, sig_l); -} - -/* u3m_file(): load file, as atom, or bail. -*/ -u3_noun -u3m_file(c3_c* pas_c) -{ - struct stat buf_b; - c3_i fid_i = c3_open(pas_c, O_RDONLY, 0644); - c3_w fln_w, red_w; - c3_y* pad_y; - - if ( (fid_i < 0) || (fstat(fid_i, &buf_b) < 0) ) { - u3l_log("%s: %s", pas_c, strerror(errno)); - return u3m_bail(c3__fail); - } - fln_w = buf_b.st_size; - pad_y = c3_malloc(buf_b.st_size); - - red_w = read(fid_i, pad_y, fln_w); - close(fid_i); - - if ( fln_w != red_w ) { - c3_free(pad_y); - return u3m_bail(c3__fail); - } - else { - u3_noun pad = u3i_bytes(fln_w, (c3_y *)pad_y); - c3_free(pad_y); - - return pad; - } -} - -/* u3m_mark(): mark all nouns in the road. -*/ -c3_w -u3m_mark(FILE* fil_u) -{ - c3_w tot_w = 0; - tot_w += u3v_mark(fil_u); - tot_w += u3j_mark(fil_u); - tot_w += u3n_mark(fil_u); - tot_w += u3a_mark_road(fil_u); - return tot_w; -} - -/* _pave_parts(): build internal tables. -*/ -static void -_pave_parts(void) -{ - u3R->cax.har_p = u3h_new_cache(u3_Host.ops_u.hap_w); - u3R->jed.war_p = u3h_new(); - u3R->jed.cod_p = u3h_new(); - u3R->jed.han_p = u3h_new(); - u3R->jed.bas_p = u3h_new(); - u3R->byc.har_p = u3h_new(); -} - -/* _pave_road(): initialize road boundaries -*/ -static u3_road* -_pave_road(c3_w* rut_w, c3_w* mat_w, c3_w* cap_w, c3_w siz_w) -{ - u3_road* rod_u = (void*) mat_w; - - // enable in case of corruption - // - // memset(mem_w, 0, 4 * len_w); - memset(rod_u, 0, 4 * siz_w); - - // the top and bottom of the heap are initially the same - // - rod_u->rut_p = u3of(c3_w, rut_w); - rod_u->hat_p = u3of(c3_w, rut_w); - - - rod_u->mat_p = u3of(c3_w, mat_w); // stack bottom - rod_u->cap_p = u3of(c3_w, cap_w); // stack top - - return rod_u; -} - -/* _pave_north(): calculate boundaries and initialize north road. -*/ -static u3_road* -_pave_north(c3_w* mem_w, c3_w siz_w, c3_w len_w) -{ - // in a north road, the heap is low and the stack is high - // - // the heap starts at the base memory pointer [mem_w]; - // the stack starts at the end of the memory segment, - // minus space for the road structure [siz_w] - // - c3_w* rut_w = mem_w; - c3_w* mat_w = ((mem_w + len_w) - siz_w); - c3_w* cap_w = mat_w; - - return _pave_road(rut_w, mat_w, cap_w, siz_w); -} - -/* _pave_south(): calculate boundaries and initialize south road. -*/ -static u3_road* -_pave_south(c3_w* mem_w, c3_w siz_w, c3_w len_w) -{ - // in a south road, the heap is high and the stack is low - // - // the heap starts at the end of the memory segment; - // the stack starts at the base memory pointer [mem_w], - // and ends after the space for the road structure [siz_w] - // - c3_w* rut_w = (mem_w + len_w); - c3_w* mat_w = mem_w; - c3_w* cap_w = mat_w + siz_w; - - return _pave_road(rut_w, mat_w, cap_w, siz_w); -} - -/* _pave_home(): initialize pristine home road. -*/ -static void -_pave_home(void) -{ - c3_w* mem_w = u3_Loom + 1; - c3_w siz_w = c3_wiseof(u3v_home); - c3_w len_w = u3C.wor_i - 1; - - u3H = (void *)_pave_north(mem_w, siz_w, len_w); - u3H->ver_w = u3v_version; - u3R = &u3H->rod_u; - - _pave_parts(); -} - -STATIC_ASSERT( ((c3_wiseof(u3v_home) * 4) == sizeof(u3v_home)), - "home road alignment" ); - -/* _find_home(): in restored image, point to home road. -*/ -static void -_find_home(void) -{ - // NB: the home road is always north - // - c3_w* mem_w = u3_Loom + 1; - c3_w siz_w = c3_wiseof(u3v_home); - c3_w len_w = u3C.wor_i - 1; - - { - c3_w ver_w = *((mem_w + len_w) - 1); - - if ( u3v_version != ver_w ) { - fprintf(stderr, "loom: checkpoint version mismatch: " - "have %u, need %u\r\n", - ver_w, - u3v_version); - abort(); - } - } - - u3H = (void *)((mem_w + len_w) - siz_w); - u3R = &u3H->rod_u; - - // this looks risky, but there are no legitimate scenarios - // where it's wrong - // - u3R->cap_p = u3R->mat_p = u3C.wor_i - c3_wiseof(*u3H); -} - -/* u3m_pave(): instantiate or activate image. -*/ -void -u3m_pave(c3_o nuu_o) -{ - if ( c3y == nuu_o ) { - _pave_home(); - } - else { - _find_home(); - } -} - -#if 0 -/* u3m_clear(): clear all allocated data in road. -*/ -void -u3m_clear(void) -{ - u3h_free(u3R->cax.har_p); - u3j_free(); - u3n_free(); -} - -void -u3m_dump(void) -{ - c3_w hat_w; - c3_w fre_w = 0; - c3_w i_w; - - hat_w = _(u3a_is_north(u3R)) ? u3R->hat_w - u3R->rut_w - : u3R->rut_w - u3R->hat_w; - - for ( i_w = 0; i_w < u3_cc_fbox_no; i_w++ ) { - u3a_fbox* fre_u = u3R->all.fre_u[i_w]; - - while ( fre_u ) { - fre_w += fre_u->box_u.siz_w; - fre_u = fre_u->nex_u; - } - } - u3l_log("dump: hat_w %x, fre_w %x, allocated %x", - hat_w, fre_w, (hat_w - fre_w)); - - if ( 0 != (hat_w - fre_w) ) { - c3_w* box_w = _(u3a_is_north(u3R)) ? u3R->rut_w : u3R->hat_w; - c3_w mem_w = 0; - - while ( box_w < (_(u3a_is_north(u3R)) ? u3R->hat_w : u3R->rut_w) ) { - u3a_box* box_u = (void *)box_w; - - if ( 0 != box_u->use_w ) { -#ifdef U3_MEMORY_DEBUG - // u3l_log("live %d words, code %x", box_u->siz_w, box_u->cod_w); -#endif - mem_w += box_u->siz_w; - } - box_w += box_u->siz_w; - } - - u3l_log("second count: %x", mem_w); - } -} -#endif - -/* u3m_bail(): bail out. Does not return. -** -** Bail motes: -** -** %evil :: erroneous cryptography -** %exit :: semantic failure -** %oops :: assertion failure -** %intr :: interrupt -** %fail :: computability failure -** %over :: stack overflow (a kind of %fail) -** %meme :: out of memory -** -** These are equivalents of the full exception noun, the error ball: -** -** $% [%0 success] -** [%1 paths] -** [%2 trace] -** [%3 code trace] -** == -** -** XX several of these abort() calls should be gated by -a -*/ -c3_i -u3m_bail(u3_noun how) -{ - if ( &(u3H->rod_u) == u3R ) { - // XX set exit code - // - fprintf(stderr, "home: bailing out\r\n"); - abort(); - } - - // printf some metadata - // - switch ( how ) { - case c3__evil: - case c3__exit: break; - - default: { - if ( _(u3ud(how)) ) { - c3_c str_c[5]; - - str_c[0] = ((how >> 0) & 0xff); - str_c[1] = ((how >> 8) & 0xff); - str_c[2] = ((how >> 16) & 0xff); - str_c[3] = ((how >> 24) & 0xff); - str_c[4] = 0; - fprintf(stderr, "\r\nbail: %s\r\n", str_c); - } - else if ( 1 != u3h(how) ) { - c3_assert(_(u3ud(u3h(how)))); - fprintf(stderr, "\r\nbail: %d\r\n", u3h(how)); - } - } - } - - // intercept fatal errors - // - switch ( how ) { - case c3__foul: - case c3__oops: { - // XX set exit code - // - fprintf(stderr, "bailing out\r\n"); - abort(); - } - } - - if ( &(u3H->rod_u) == u3R ) { - // For top-level errors, which shouldn't happen often, we have no - // choice but to use the signal process; and we require the flat - // form of how. - // - // XX JB: these seem unrecoverable, at least wrt memory management, - // so they've been disabled above for now - // - c3_assert(_(u3a_is_cat(how))); - u3m_signal(how); - } - - // release the emergency buffer, ensuring space for cells - // - u3z(u3R->bug.mer); - u3R->bug.mer = 0; - - /* Reconstruct a correct error ball. - */ - if ( _(u3ud(how)) ) { - switch ( how ) { - case c3__exit: { - how = u3nc(2, u3R->bug.tax); - } break; - - default: { - how = u3nt(3, how, u3R->bug.tax); - } break; - } - } - - /* Longjmp, with an underscore. - */ - _longjmp(u3R->esc.buf, how); -} - -int c3_cooked() { return u3m_bail(c3__oops); } - -/* u3m_error(): bail out with %exit, ct_pushing error. -*/ -c3_i -u3m_error(c3_c* str_c) -{ - u3t_mean(u3i_string(str_c)); - return u3m_bail(c3__exit); -} - -/* u3m_leap(): in u3R, create a new road within the existing one. -*/ -void -u3m_leap(c3_w pad_w) -{ - c3_w len_w; - u3_road* rod_u; - - /* Measure the pad - we'll need it. - */ - { -#if 0 - if ( pad_w < u3R->all.fre_w ) { - pad_w = 0; - } - else { - pad_w -= u3R->all.fre_w; - } -#endif - if ( (pad_w + c3_wiseof(u3a_road)) >= u3a_open(u3R) ) { - u3m_bail(c3__meme); - } - len_w = u3a_open(u3R) - (pad_w + c3_wiseof(u3a_road)); - } - - /* Allocate a region on the cap. - */ - { - u3p(c3_w) bot_p; - - if ( c3y == u3a_is_north(u3R) ) { - bot_p = (u3R->cap_p - len_w); - u3R->cap_p -= len_w; - - rod_u = _pave_south(u3a_into(bot_p), c3_wiseof(u3a_road), len_w); - u3e_ward(rod_u->cap_p, rod_u->hat_p); -#if 0 - fprintf(stderr, "leap: from north %p (cap 0x%x), to south %p\r\n", - u3R, - u3R->cap_p + len_w, - rod_u); -#endif - } - else { - bot_p = u3R->cap_p; - u3R->cap_p += len_w; - - rod_u = _pave_north(u3a_into(bot_p), c3_wiseof(u3a_road), len_w); - u3e_ward(rod_u->hat_p, rod_u->cap_p); -#if 0 - fprintf(stderr, "leap: from south %p (cap 0x%x), to north %p\r\n", - u3R, - u3R->cap_p - len_w, - rod_u); -#endif - } - } - - /* Attach the new road to its parents. - */ - { - c3_assert(0 == u3R->kid_p); - rod_u->par_p = u3of(u3_road, u3R); - u3R->kid_p = u3of(u3_road, rod_u); - } - - /* Set up the new road. - */ - { - u3R = rod_u; - _pave_parts(); - } -#ifdef U3_MEMORY_DEBUG - rod_u->all.fre_w = 0; -#endif -} - -void -_print_diff(c3_c* cap_c, c3_w a, c3_w b) -{ - c3_w diff = apar_p); - -#if 0 - /* If you're printing a lot of these you need to change - * u3a_print_memory from fprintf to u3l_log - */ - fprintf(stderr, "fall: from %s %p, to %s %p (cap 0x%x, was 0x%x)\r\n", - _(u3a_is_north(u3R)) ? "north" : "south", - u3R, - _(u3a_is_north(u3to(u3_road, u3R->par_p))) ? "north" : "south", - u3to(u3_road, u3R->par_p), - u3R->hat_p, - u3R->rut_p); - _print_diff("unused free", u3R->hat_p, u3R->cap_p); - _print_diff("freeing", u3R->rut_p, u3R->hat_p); - _print_diff("stack", u3R->cap_p, u3R->mat_p); - static c3_w wat_w = 500000000; - if (u3to(u3_road, u3R->par_p) == &u3H->rod_u) { - wat_w = 500000000; - } - else { - wat_w = c3_min(wat_w, - u3R->hat_p < u3R->cap_p ? - u3R->cap_p - u3R->hat_p : - u3R->hat_p - u3R->cap_p); - } - u3a_print_memory(stderr, "low water mark", wat_w); - -#endif - - u3to(u3_road, u3R->par_p)->pro.nox_d += u3R->pro.nox_d; - u3to(u3_road, u3R->par_p)->pro.cel_d += u3R->pro.cel_d; - - /* The new cap is the old hat - it's as simple as that. - */ - u3to(u3_road, u3R->par_p)->cap_p = u3R->hat_p; - - /* And, we're back home. - */ - u3R = u3to(u3_road, u3R->par_p); - u3R->kid_p = 0; -} - -/* u3m_hate(): new, integrated leap mechanism (enter). -*/ -void -u3m_hate(c3_w pad_w) -{ - c3_assert(0 == u3R->ear_p); - - u3R->ear_p = u3R->cap_p; - u3m_leap(pad_w); - - u3R->bug.mer = u3i_string( - "emergency buffer with sufficient space to cons the trace and bail" - ); -} - -/* u3m_love(): return product from leap. -*/ -u3_noun -u3m_love(u3_noun pro) -{ - // save cache pointers from current road - // - u3p(u3h_root) byc_p = u3R->byc.har_p; - u3a_jets jed_u = u3R->jed; - - // fallback to parent road (child heap on parent's stack) - // - u3m_fall(); - - // copy product and caches off our stack - // - pro = u3a_take(pro); - jed_u = u3j_take(jed_u); - byc_p = u3n_take(byc_p); - - // pop the stack - // - u3R->cap_p = u3R->ear_p; - u3R->ear_p = 0; - - // integrate junior caches - // - u3j_reap(jed_u); - u3n_reap(byc_p); - - return pro; -} - -/* u3m_golf(): record cap_p length for u3m_flog(). -*/ -c3_w -u3m_golf(void) -{ - if ( c3y == u3a_is_north(u3R) ) { - return u3R->mat_p - u3R->cap_p; - } - else { - return u3R->cap_p - u3R->mat_p; - } -} - -/* u3m_flog(): reset cap_p. -*/ -void -u3m_flog(c3_w gof_w) -{ - // Enable memsets in case of memory corruption. - // - if ( c3y == u3a_is_north(u3R) ) { - u3_post bot_p = (u3R->mat_p - gof_w); - // c3_w len_w = (bot_w - u3R->cap_w); - - // memset(u3R->cap_w, 0, 4 * len_w); - u3R->cap_p = bot_p; - } - else { - u3_post bot_p = u3R->mat_p + gof_w; - // c3_w len_w = (u3R->cap_w - bot_w); - - // memset(bot_w, 0, 4 * len_w); // - u3R->cap_p = bot_p; - } -} - -/* u3m_water(): produce watermarks. -*/ -void -u3m_water(c3_w* low_w, c3_w* hig_w) -{ - c3_assert(u3R == &u3H->rod_u); - - *low_w = u3a_heap(u3R); - *hig_w = u3a_temp(u3R) + c3_wiseof(u3v_home); -} - -/* u3m_soft_top(): top-level safety wrapper. -*/ -u3_noun -u3m_soft_top(c3_w mil_w, // timer ms - c3_w pad_w, // base memory pad - u3_funk fun_f, - u3_noun arg) -{ - u3_noun why, pro; - c3_l sig_l; - - /* Enter internal signal regime. - */ - _cm_signal_deep(mil_w); - - if ( 0 != (sig_l = rsignal_setjmp(u3_Signal)) ) { - // reinitialize trace state - // - u3t_init(); - - // return to blank state - // - _cm_signal_done(); - - // recover memory state from the top down - // - return _cm_signal_recover(sig_l, arg); - } - - /* Record the cap, and leap. - */ - u3m_hate(pad_w); - - /* Trap for ordinary nock exceptions. - */ - if ( 0 == (why = (u3_noun)_setjmp(u3R->esc.buf)) ) { - pro = fun_f(arg); - - /* Make sure the inner routine did not create garbage. - */ - if ( u3C.wag_w & u3o_debug_ram ) { -#ifdef U3_CPU_DEBUG - if ( u3R->all.max_w > 1000000 ) { - u3a_print_memory(stderr, "execute: top", u3R->all.max_w); - } -#endif - u3m_grab(pro, u3_none); - } - - /* Revert to external signal regime. - */ - _cm_signal_done(); - - /* Produce success, on the old road. - */ - pro = u3nc(0, u3m_love(pro)); - } - else { - /* Overload the error result. - */ - pro = u3m_love(why); - } - - /* Revert to external signal regime. - */ - _cm_signal_done(); - - /* Free the argument. - */ - u3z(arg); - - /* Return the product. - */ - return pro; -} - -/* u3m_soft_sure(): top-level call assumed correct. -*/ -u3_noun -u3m_soft_sure(u3_funk fun_f, u3_noun arg) -{ - u3_noun pro, pru = u3m_soft_top(0, (1 << 18), fun_f, arg); - - c3_assert(_(u3du(pru))); - pro = u3k(u3t(pru)); - u3z(pru); - - return pro; -} - -/* u3m_soft_slam: top-level call. -*/ -u3_noun _cm_slam(u3_noun arg) { return u3n_slam_on(u3h(arg), u3t(arg)); } -u3_noun -u3m_soft_slam(u3_noun gat, u3_noun sam) -{ - return u3m_soft_sure(_cm_slam, u3nc(gat, sam)); -} - -/* u3m_soft_nock: top-level nock. -*/ -u3_noun _cm_nock(u3_noun arg) { return u3n_nock_on(u3h(arg), u3t(arg)); } -u3_noun -u3m_soft_nock(u3_noun bus, u3_noun fol) -{ - return u3m_soft_sure(_cm_nock, u3nc(bus, fol)); -} - -/* u3m_soft_run(): descend into virtualization context. -*/ -u3_noun -u3m_soft_run(u3_noun gul, - u3_funq fun_f, - u3_noun aga, - u3_noun agb) -{ - u3_noun why = 0, pro; - - /* Record the cap, and leap. - */ - u3m_hate(1 << 18); - - /* Configure the new road. - */ - { - u3R->ski.gul = u3nc(gul, u3to(u3_road, u3R->par_p)->ski.gul); - u3R->pro.don = u3to(u3_road, u3R->par_p)->pro.don; - u3R->pro.trace = u3to(u3_road, u3R->par_p)->pro.trace; - u3R->bug.tax = 0; - } - u3t_on(coy_o); - - /* Trap for exceptions. - */ - if ( 0 == (why = (u3_noun)_setjmp(u3R->esc.buf)) ) { - u3t_off(coy_o); - pro = fun_f(aga, agb); - -#ifdef U3_CPU_DEBUG - if ( u3R->all.max_w > 1000000 ) { - u3a_print_memory(stderr, "execute: run", u3R->all.max_w); - } -#endif - - /* Today you can't run -g without memory debug, but you should be - * able to. - */ -#ifdef U3_MEMORY_DEBUG - if ( u3C.wag_w & u3o_debug_ram ) { - u3m_grab(pro, u3_none); - } -#endif - - /* Produce success, on the old road. - */ - pro = u3nc(0, u3m_love(pro)); - } - else { - u3t_init(); - - /* Produce - or fall again. - */ - { - c3_assert(_(u3du(why))); - switch ( u3h(why) ) { - default: c3_assert(0); return 0; - - case 0: { // unusual: bail with success. - pro = u3m_love(why); - } break; - - case 1: { // blocking request - pro = u3m_love(why); - } break; - - case 2: { // true exit - pro = u3m_love(why); - } break; - - case 3: { // failure; rebail w/trace - u3_noun yod = u3m_love(u3t(why)); - - u3m_bail - (u3nt(3, - u3a_take(u3h(yod)), - u3kb_weld(u3t(yod), u3k(u3R->bug.tax)))); - } break; - - case 4: { // meta-bail - u3m_bail(u3m_love(u3t(why))); - } break; - } - } - } - - /* Release the arguments. - */ - { - u3z(gul); - u3z(aga); - u3z(agb); - } - - /* Return the product. - */ - return pro; -} - -/* u3m_soft_esc(): namespace lookup. Produces direct result. -*/ -u3_noun -u3m_soft_esc(u3_noun ref, u3_noun sam) -{ - u3_noun why, gul, pro; - - /* Assert preconditions. - */ - { - c3_assert(0 != u3R->ski.gul); - gul = u3h(u3R->ski.gul); - } - - /* Record the cap, and leap. - */ - u3m_hate(1 << 18); - - /* Configure the new road. - */ - { - u3R->ski.gul = u3t(u3to(u3_road, u3R->par_p)->ski.gul); - u3R->pro.don = u3to(u3_road, u3R->par_p)->pro.don; - u3R->pro.trace = u3to(u3_road, u3R->par_p)->pro.trace; - u3R->bug.tax = 0; - } - - /* Trap for exceptions. - */ - if ( 0 == (why = (u3_noun)_setjmp(u3R->esc.buf)) ) { - pro = u3n_slam_on(gul, u3nc(ref, sam)); - - /* Fall back to the old road, leaving temporary memory intact. - */ - pro = u3m_love(pro); - } - else { - u3t_init(); - - /* Push the error back up to the calling context - not the run we - ** are in, but the caller of the run, matching pure nock semantics. - */ - u3m_bail(u3nc(4, u3m_love(why))); - } - - /* Release the sample. Note that we used it above, but in a junior - ** road, so its refcount is intact. - */ - u3z(ref); - u3z(sam); - - /* Return the product. - */ - return pro; -} - -/* u3m_grab(): garbage-collect the world, plus extra roots. -*/ -void -u3m_grab(u3_noun som, ...) // terminate with u3_none -{ - // u3h_free(u3R->cax.har_p); - // u3R->cax.har_p = u3h_new(); - - u3m_mark(0); - { - va_list vap; - u3_noun tur; - - va_start(vap, som); - - if ( som != u3_none ) { - u3a_mark_noun(som); - - while ( u3_none != (tur = va_arg(vap, u3_noun)) ) { - u3a_mark_noun(tur); - } - } - va_end(vap); - } - u3a_sweep(); -} - -/* u3m_soft(): top-level wrapper. -** -** Produces [0 product] or [%error (list tank)], top last. -*/ -u3_noun -u3m_soft(c3_w mil_w, - u3_funk fun_f, - u3_noun arg) -{ - u3_noun why; - - why = u3m_soft_top(mil_w, (1 << 20), fun_f, arg); // 2MB pad - - if ( 0 == u3h(why) ) { - return why; - } - else { - u3_noun tax, cod, pro; - - switch ( u3h(why) ) { - case 2: { - cod = c3__exit; - tax = u3t(why); - } break; - - case 3: { - cod = u3h(u3t(why)); - tax = u3t(u3t(why)); - } break; - - // don't use .^ at the top level! - // - default: { - u3m_p("invalid mot", u3h(why)); - c3_assert(0); - } - } - - // don't call +mook if we have no kernel - // - // This is required to soft the boot sequence. - // - if ( 0 == u3A->roc ) { - while ( u3_nul != tax ) { - u3_noun dat, mot, val; - u3x_cell(tax, &dat, &tax); - - if ( c3y == u3r_cell(dat, &mot, &val) ) { - if ( c3__spot == mot ) { - u3m_p("tax", val); - } - else if ( (c3__mean == mot) - && (c3y == u3a_is_atom(val)) ) - { - u3m_p("men", val); - } - else { - u3m_p("mot", mot); - } - } - } - - pro = u3nc(u3k(cod), u3_nul); - } - // %evil leaves no trace - // - else if ( c3__evil == cod ) { - pro = u3nc(u3k(cod), u3_nul); - } - else { - u3_noun mok = u3dc("mook", 2, u3k(tax)); - pro = u3nc(u3k(cod), u3k(u3t(mok))); - u3z(mok); - } - - u3z(why); - return pro; - } -} - -/* _cm_is_tas(): yes iff som (RETAIN) is @tas. -*/ -static c3_o -_cm_is_tas(u3_atom som, c3_w len_w) -{ - c3_w i_w; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_c c_c = u3r_byte(i_w, som); - - if ( islower(c_c) || - (isdigit(c_c) && (0 != i_w) && ((len_w - 1) != i_w)) - || '-' == c_c ) - { - continue; - } - return c3n; - } - return c3y; -} - -/* _cm_is_ta(): yes iff som (RETAIN) is @ta. -*/ -static c3_o -_cm_is_ta(u3_noun som, c3_w len_w) -{ - c3_w i_w; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_c c_c = u3r_byte(i_w, som); - - if ( (c_c < 32) || (c_c > 127) ) { - return c3n; - } - } - return c3y; -} - -/* _cm_hex(): hex byte. -*/ -c3_y _cm_hex(c3_y c_y) -{ - if ( c_y < 10 ) - return '0' + c_y; - else return 'a' + (c_y - 10); -} - -/* _cm_in_pretty: measure/cut prettyprint. -*/ -static c3_w -_cm_in_pretty(u3_noun som, c3_o sel_o, c3_c* str_c) -{ - if ( _(u3du(som)) ) { - c3_w sel_w, one_w, two_w; - - sel_w = 0; - if ( _(sel_o) ) { - if ( str_c ) { *(str_c++) = '['; } - sel_w += 1; - } - - one_w = _cm_in_pretty(u3h(som), c3y, str_c); - if ( str_c ) { - str_c += one_w; - *(str_c++) = ' '; - } - two_w = _cm_in_pretty(u3t(som), c3n, str_c); - if ( str_c ) { str_c += two_w; } - - if ( _(sel_o) ) { - if ( str_c ) { *(str_c++) = ']'; } - sel_w += 1; - } - return one_w + two_w + 1 + sel_w; - } - else { - if ( som < 65536 ) { - c3_c buf_c[6]; - c3_w len_w; - - snprintf(buf_c, 6, "%d", som); - len_w = strlen(buf_c); - - if ( str_c ) { strcpy(str_c, buf_c); str_c += len_w; } - return len_w; - } - else { - c3_w len_w = u3r_met(3, som); - - if ( _(_cm_is_tas(som, len_w)) ) { - c3_w len_w = u3r_met(3, som); - - if ( str_c ) { - *(str_c++) = '%'; - u3r_bytes(0, len_w, (c3_y *)str_c, som); - str_c += len_w; - } - return len_w + 1; - } - else if ( _(_cm_is_ta(som, len_w)) ) { - if ( str_c ) { - *(str_c++) = '\''; - u3r_bytes(0, len_w, (c3_y *)str_c, som); - str_c += len_w; - *(str_c++) = '\''; - } - return len_w + 2; - } - else { - c3_w len_w = u3r_met(3, som); - c3_c *buf_c = c3_malloc(2 + (2 * len_w) + 1); - c3_w i_w = 0; - c3_w a_w = 0; - - buf_c[a_w++] = '0'; - buf_c[a_w++] = 'x'; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_y c_y = u3r_byte(len_w - (i_w + 1), som); - - if ( (i_w == 0) && (c_y <= 0xf) ) { - buf_c[a_w++] = _cm_hex(c_y); - } else { - buf_c[a_w++] = _cm_hex(c_y >> 4); - buf_c[a_w++] = _cm_hex(c_y & 0xf); - } - } - buf_c[a_w] = 0; - len_w = a_w; - - if ( str_c ) { strcpy(str_c, buf_c); str_c += len_w; } - - c3_free(buf_c); - return len_w; - } - } - } -} - -/* u3m_pretty(): dumb prettyprint to string. -*/ -c3_c* -u3m_pretty(u3_noun som) -{ - c3_w len_w = _cm_in_pretty(som, c3y, 0); - c3_c* pre_c = c3_malloc(len_w + 1); - - _cm_in_pretty(som, c3y, pre_c); - pre_c[len_w] = 0; - return pre_c; -} - -/* _cm_in_pretty_path: measure/cut prettyprint. - * - * Modeled after _cm_in_pretty(), the backend to u3m_p(), but with the - * assumption that we're always displaying a path. - */ -static c3_w -_cm_in_pretty_path(u3_noun som, c3_c* str_c) -{ - if ( _(u3du(som)) ) { - c3_w sel_w, one_w, two_w; - if ( str_c ) { - *(str_c++) = '/'; - } - sel_w = 1; - - one_w = _cm_in_pretty_path(u3h(som), str_c); - if ( str_c ) { - str_c += one_w; - } - - two_w = _cm_in_pretty_path(u3t(som), str_c); - if ( str_c ) { - str_c += two_w; - } - - return sel_w + one_w + two_w; - } - else { - c3_w len_w = u3r_met(3, som); - if ( str_c && len_w ) { - u3r_bytes(0, len_w, (c3_y *)str_c, som); - str_c += len_w; - } - return len_w; - } -} - -/* u3m_pretty_path(): prettyprint a path to string. -*/ -c3_c* -u3m_pretty_path(u3_noun som) -{ - c3_w len_w = _cm_in_pretty_path(som, NULL); - c3_c* pre_c = c3_malloc(len_w + 1); - - _cm_in_pretty_path(som, pre_c); - pre_c[len_w] = 0; - return pre_c; -} - -/* u3m_p(): dumb print with caption. -*/ -void -u3m_p(const c3_c* cap_c, u3_noun som) -{ - c3_c* pre_c = u3m_pretty(som); - - u3l_log("%s: %s", cap_c, pre_c); - c3_free(pre_c); -} - -/* u3m_tape(): dump a tape to stdout. -*/ -void -u3m_tape(u3_noun tep) -{ - u3_noun tap = tep; - - while ( u3_nul != tap ) { - c3_c car_c; - - if ( u3h(tap) >= 127 ) { - car_c = '?'; - } else car_c = u3h(tap); - - putc(car_c, stdout); - tap = u3t(tap); - } - u3z(tep); -} - -/* u3m_wall(): dump a wall to stdout. -*/ -void -u3m_wall(u3_noun wol) -{ - u3_noun wal = wol; - - while ( u3_nul != wal ) { - u3m_tape(u3k(u3h(wal))); - - putc(13, stdout); - putc(10, stdout); - - wal = u3t(wal); - } - u3z(wol); -} - -/* _cm_limits(): set up global modes and limits. -*/ -static void -_cm_limits(void) -{ -# ifdef U3_OS_mingw - // Windows doesn't have rlimits. Default maximum thread - // stack size is set in the executable file header. -# else - struct rlimit rlm; - - // Moar stack. - // - { - c3_assert( 0 == getrlimit(RLIMIT_STACK, &rlm) ); - - rlm.rlim_cur = c3_min(rlm.rlim_max, (65536 << 10)); - - if ( 0 != setrlimit(RLIMIT_STACK, &rlm) ) { - u3l_log("boot: stack size: %s", strerror(errno)); - exit(1); - } - } - - // Moar filez. - // - { - getrlimit(RLIMIT_NOFILE, &rlm); - - #ifdef U3_OS_osx - rlm.rlim_cur = c3_min(OPEN_MAX, rlm.rlim_max); - #else - rlm.rlim_cur = rlm.rlim_max; - #endif - - // no exit, not a critical limit - // - if ( 0 != setrlimit(RLIMIT_NOFILE, &rlm) ) { - u3l_log("boot: open file limit: %s", strerror(errno)); - } - } - - // Moar core. - // -# ifndef ASAN_ENABLED - { - getrlimit(RLIMIT_CORE, &rlm); - rlm.rlim_cur = RLIM_INFINITY; - - // no exit, not a critical limit - // - if ( 0 != setrlimit(RLIMIT_CORE, &rlm) ) { - u3l_log("boot: core limit: %s", strerror(errno)); - } - } -# endif -# endif -} - -/* _cm_signals(): set up interrupts, etc. -*/ -static void -_cm_signals(void) -{ -# if defined(U3_OS_mingw) - // vere using libsigsegv on MingW is very slow, because libsigsegv - // works by installing a top-level SEH unhandled exception filter. - // The top-level filter runs only after Windows walks the whole stack, - // looking up registered exception filters for every stack frame, and - // finds no filter to handle the exception. - // Instead of libsigsegv, all vere functions register a SEH exception - // filter (see compat/mingw/seh_handler.c) that handles both memory - // access and stack overflow exceptions. It calls u3e_fault directly. -# else - if ( 0 != sigsegv_install_handler(u3e_fault) ) { - u3l_log("boot: sigsegv install failed"); - exit(1); - } -# endif - -# if defined(U3_OS_PROF) - // Block SIGPROF, so that if/when we reactivate it on the - // main thread for profiling, we won't get hits in parallel - // on other threads. - if ( u3C.wag_w & u3o_debug_cpu ) { - sigset_t set; - - sigemptyset(&set); - sigaddset(&set, SIGPROF); - - if ( 0 != pthread_sigmask(SIG_BLOCK, &set, NULL) ) { - u3l_log("boot: thread mask SIGPROF: %s", strerror(errno)); - exit(1); - } - } -# endif -} - -/* _cm_malloc_ssl(): openssl-shaped malloc -*/ -static void* -_cm_malloc_ssl(size_t len_i -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - , const char* file, int line -#endif - ) -{ - return u3a_malloc(len_i); -} - -/* _cm_realloc_ssl(): openssl-shaped realloc. -*/ -static void* -_cm_realloc_ssl(void* lag_v, size_t len_i -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - , const char* file, int line -#endif - ) -{ - return u3a_realloc(lag_v, len_i); -} - -/* _cm_free_ssl(): openssl-shaped free. -*/ -static void -_cm_free_ssl(void* tox_v -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - , const char* file, int line -#endif - ) -{ - return u3a_free(tox_v); -} - -extern void u3je_secp_init(void); - -/* _cm_crypto(): initialize openssl and crypto jets. -*/ -static void -_cm_crypto() -{ - /* Initialize OpenSSL with loom allocation functions. */ - if ( 0 == CRYPTO_set_mem_functions(&_cm_malloc_ssl, - &_cm_realloc_ssl, - &_cm_free_ssl) ) { - u3l_log("%s", "openssl initialization failed"); - abort(); - } - - u3je_secp_init(); -} - -/* _cm_realloc2(): gmp-shaped realloc. -*/ -static void* -_cm_realloc2(void* lag_v, size_t old_i, size_t new_i) -{ - return u3a_realloc(lag_v, new_i); -} - -/* _cm_free2(): gmp-shaped free. -*/ -static void -_cm_free2(void* tox_v, size_t siz_i) -{ - return u3a_free(tox_v); -} - -/* u3m_init(): start the environment. -*/ -void -u3m_init(size_t len_i) -{ - _cm_limits(); - _cm_signals(); - _cm_crypto(); - - // make sure GMP uses our malloc. - // - mp_set_memory_functions(u3a_malloc, _cm_realloc2, _cm_free2); - - // make sure that [len_i] is a fully-addressible non-zero power of two. - // - if ( !len_i - || (len_i & (len_i - 1)) - || (len_i < (1 << (u3a_page + 2))) - || (len_i > u3a_bytes) ) - { - u3l_log("loom: bad size: %zu", len_i); - exit(1); - } - - // map at fixed address. - // - { - void* map_v = mmap((void *)u3_Loom, - len_i, - (PROT_READ | PROT_WRITE), - (MAP_ANON | MAP_FIXED | MAP_PRIVATE), - -1, 0); - - if ( -1 == (c3_ps)map_v ) { - map_v = mmap((void *)0, - len_i, - (PROT_READ | PROT_WRITE), - (MAP_ANON | MAP_PRIVATE), - -1, 0); - - u3l_log("boot: mapping %zuMB failed", len_i >> 20); - u3l_log("see urbit.org/using/install/#about-swap-space" - " for adding swap space"); - if ( -1 != (c3_ps)map_v ) { - u3l_log("if porting to a new platform, try U3_OS_LoomBase %p", - map_v); - } - exit(1); - } - - u3C.wor_i = len_i >> 2; - u3l_log("loom: mapped %zuMB", len_i >> 20); - } -} - -extern void u3je_secp_stop(void); - -/* u3m_stop(): graceful shutdown cleanup. -*/ -void -u3m_stop() -{ - u3je_secp_stop(); -} - -/* u3m_boot(): start the u3 system. return next event, starting from 1. -*/ -c3_d -u3m_boot(c3_c* dir_c, size_t len_i) -{ - c3_o nuu_o; - - /* Activate the loom. - */ - u3m_init(len_i); - - /* Activate the storage system. - */ - nuu_o = u3e_live(c3n, dir_c); - - /* Activate tracing. - */ - u3C.slog_f = 0; - u3C.sign_hold_f = 0; - u3C.sign_move_f = 0; - u3t_init(); - - /* Construct or activate the allocator. - */ - u3m_pave(nuu_o); - - /* Place the guard page. - */ - u3e_init(); - - /* Initialize the jet system. - */ - { - c3_w len_w = u3j_boot(nuu_o); - u3l_log("boot: installed %d jets", len_w); - } - - /* Reactivate jets on old kernel. - */ - if ( c3n == nuu_o ) { - u3j_ream(); - u3n_ream(); - return u3A->eve_d; - } - else { - /* Basic initialization. - */ - memset(u3A, 0, sizeof(*u3A)); - return 0; - } -} - -/* u3m_boot_lite(): start without checkpointing. -*/ -c3_d -u3m_boot_lite(size_t len_i) -{ - /* Activate the loom. - */ - u3m_init(len_i); - - /* Activate tracing. - */ - u3C.slog_f = 0; - u3C.sign_hold_f = 0; - u3C.sign_move_f = 0; - u3t_init(); - - /* Construct or activate the allocator. - */ - u3m_pave(c3y); - - /* Place the guard page. - */ - u3e_init(); - - /* Initialize the jet system. - */ - u3j_boot(c3y); - - /* Basic initialization. - */ - memset(u3A, 0, sizeof(*u3A)); - return 0; -} - -/* u3m_reclaim: clear persistent caches to reclaim memory -*/ -void -u3m_reclaim(void) -{ - u3v_reclaim(); - u3j_reclaim(); - u3n_reclaim(); - u3a_reclaim(); -} - -/* _cm_pack_rewrite(): trace through arena, rewriting pointers. -*/ -static void -_cm_pack_rewrite(void) -{ - // XX fix u3a_rewrit* to support south roads - // - c3_assert( &(u3H->rod_u) == u3R ); - - // NB: these implementations must be kept in sync with u3m_reclaim(); - // anything not reclaimed must be rewritable - // - u3v_rewrite_compact(); - u3j_rewrite_compact(); - u3n_rewrite_compact(); - u3a_rewrite_compact(); -} - -/* u3m_pack: compact (defragment) memory. -*/ -c3_w -u3m_pack(void) -{ - c3_w pre_w = u3a_open(u3R); - - // reclaim first, to free space, and discard anything we can't/don't rewrite - // - u3m_reclaim(); - - // sweep the heap, finding and saving new locations - // - u3a_pack_seek(u3R); - - // trace roots, rewriting inner pointers - // - _cm_pack_rewrite(); - - // sweep the heap, relocating objects to their new locations - // - u3a_pack_move(u3R); - - return (u3a_open(u3R) - pre_w); -} diff --git a/pkg/urbit/noun/nock.c b/pkg/urbit/noun/nock.c deleted file mode 100644 index 518ff5161..000000000 --- a/pkg/urbit/noun/nock.c +++ /dev/null @@ -1,3123 +0,0 @@ -/* g/n.c -** -*/ -#include "all.h" - -// define to have each opcode printed as it executes, -// along with some other debugging info -# undef VERBOSE_BYTECODE - -#if 0 -// Retained for debugging purposes. -static u3_noun _n_nock_on(u3_noun bus, u3_noun fol); - -/* _n_hint(): process hint. -*/ -static u3_noun -_n_hint(u3_noun zep, - u3_noun hod, - u3_noun bus, - u3_noun nex) -{ - switch ( zep ) { - default: { - // u3m_p("weird zep", zep); - u3a_lose(zep); - u3a_lose(hod); - - return _n_nock_on(bus, nex); - } - - case c3__hunk: - case c3__lose: - case c3__mean: - case c3__spot: { - u3_noun tac = u3nc(zep, hod); - u3_noun pro; - - u3t_push(tac); -#if 0 - { - static int low_i; - - if ( !low_i ) { - low_i = 1; - if ( 0 == (u3R->pro.nox_d % 65536ULL) ) { - if ( c3__spot == zep ) { - u3l_log("spot %d/%d : %d/%d", - u3h(u3h(u3t(hod))), - u3t(u3h(u3t(hod))), - u3h(u3t(u3t(hod))), - u3t(u3t(u3t(hod)))); - } - } - low_i = 0; - } - } -#endif - pro = _n_nock_on(bus, nex); - u3t_drop(); - - return pro; - } - - case c3__live: { - if ( c3y == u3ud(hod) ) { - u3t_off(noc_o); - u3t_heck(hod); - u3t_on(noc_o); - } else { - u3z(hod); - } - return _n_nock_on(bus, nex); - } - - case c3__slog: { - if ( !(u3C.wag_w & u3o_quiet) ) { - u3t_off(noc_o); - u3t_slog(hod); - u3t_on(noc_o); - } - return _n_nock_on(bus, nex); - } - - case c3__germ: { - u3_noun pro = _n_nock_on(bus, nex); - - if ( c3y == u3r_sing(pro, hod) ) { - u3z(pro); return hod; - } else { - u3z(hod); return pro; - } - } - - case c3__fast: { - u3_noun pro = _n_nock_on(bus, nex); - - u3t_off(noc_o); - u3j_mine(hod, u3k(pro)); - u3t_on(noc_o); - - return pro; - } - - case c3__memo: { - u3z(hod); -#if 0 - return _n_nock_on(bus, nex); -#else - { - u3_noun pro = u3z_find_2(144 + c3__nock, bus, nex); - - if ( pro != u3_none ) { - u3z(bus); u3z(nex); - return pro; - } - pro = _n_nock_on(u3k(bus), u3k(nex)); - - if ( &(u3H->rod_u) != u3R ) { - u3z_save_2(144 + c3__nock, bus, nex, pro); - } - - u3z(bus); u3z(nex); - - return pro; - } -#endif - } - - case c3__sole: { - u3z(hod); - { - u3_noun pro = _n_nock_on(bus, nex); - - // return u3z_uniq(pro); - return pro; - } - } - } -} - -/* _n_nock_on(): produce .*(bus fol). Do not virtualize. -*/ -static u3_noun -_n_nock_on(u3_noun bus, u3_noun fol) -{ - u3_noun hib, gal; - - while ( 1 ) { - hib = u3h(fol); - gal = u3t(fol); - -#ifdef U3_CPU_DEBUG - u3R->pro.nox_d += 1; -#endif - - if ( c3y == u3r_du(hib) ) { - u3_noun poz, riv; - - poz = _n_nock_on(u3k(bus), u3k(hib)); - riv = _n_nock_on(bus, u3k(gal)); - - u3a_lose(fol); - return u3i_cell(poz, riv); - } - else switch ( hib ) { - default: return u3m_bail(c3__exit); - - case 0: { - if ( c3n == u3r_ud(gal) ) { - return u3m_bail(c3__exit); - } - else { - u3_noun pro = u3k(u3at(gal, bus)); - - u3a_lose(bus); u3a_lose(fol); - return pro; - } - } - c3_assert(!"not reached"); - - case 1: { - u3_noun pro = u3k(gal); - - u3a_lose(bus); u3a_lose(fol); - return pro; - } - c3_assert(!"not reached"); - - case 2: { - u3_noun nex = _n_nock_on(u3k(bus), u3k(u3t(gal))); - u3_noun seb = _n_nock_on(bus, u3k(u3h(gal))); - - u3a_lose(fol); - bus = seb; - fol = nex; - continue; - } - c3_assert(!"not reached"); - - case 3: { - u3_noun gof, pro; - - gof = _n_nock_on(bus, u3k(gal)); - pro = u3r_du(gof); - - u3a_lose(gof); u3a_lose(fol); - return pro; - } - c3_assert(!"not reached"); - - case 4: { - u3_noun gof, pro; - - gof = _n_nock_on(bus, u3k(gal)); - pro = u3i_vint(gof); - - u3a_lose(fol); - return pro; - } - c3_assert(!"not reached"); - - case 5: { - u3_noun wim = _n_nock_on(bus, u3k(gal)); - u3_noun pro = u3r_sing(u3h(wim), u3t(wim)); - - u3a_lose(wim); u3a_lose(fol); - return pro; - } - c3_assert(!"not reached"); - - case 6: { - u3_noun b_gal, c_gal, d_gal; - - u3x_trel(gal, &b_gal, &c_gal, &d_gal); - { - u3_noun tys = _n_nock_on(u3k(bus), u3k(b_gal)); - u3_noun nex; - - if ( 0 == tys ) { - nex = u3k(c_gal); - } else if ( 1 == tys ) { - nex = u3k(d_gal); - } else return u3m_bail(c3__exit); - - u3a_lose(fol); - fol = nex; - continue; - } - } - c3_assert(!"not reached"); - - case 7: { - u3_noun b_gal, c_gal; - - u3x_cell(gal, &b_gal, &c_gal); - { - u3_noun bod = _n_nock_on(bus, u3k(b_gal)); - u3_noun nex = u3k(c_gal); - - u3a_lose(fol); - bus = bod; - fol = nex; - continue; - } - } - c3_assert(!"not reached"); - - case 8: { - u3_noun b_gal, c_gal; - - u3x_cell(gal, &b_gal, &c_gal); - { - u3_noun heb = _n_nock_on(u3k(bus), u3k(b_gal)); - u3_noun bod = u3nc(heb, bus); - u3_noun nex = u3k(c_gal); - - u3a_lose(fol); - bus = bod; - fol = nex; - continue; - } - } - c3_assert(!"not reached"); - - case 9: { - u3_noun b_gal, c_gal; - - u3x_cell(gal, &b_gal, &c_gal); - { - u3_noun seb = _n_nock_on(bus, u3k(c_gal)); - u3_noun pro; - - u3t_off(noc_o); - pro = u3j_kick(seb, b_gal); - u3t_on(noc_o); - - if ( u3_none != pro ) { - u3a_lose(fol); - return pro; - } - else { - if ( c3n == u3r_ud(b_gal) ) { - return u3m_bail(c3__exit); - } - else { - u3_noun nex = u3k(u3at(b_gal, seb)); - - u3a_lose(fol); - bus = seb; - fol = nex; - continue; - } - } - } - } - c3_assert(!"not reached"); - - case 10: { - u3_noun p_gal, q_gal; - - u3x_cell(gal, &p_gal, &q_gal); - { - u3_noun zep, hod, nex; - - if ( c3y == u3r_du(p_gal) ) { - u3_noun b_gal = u3h(p_gal); - u3_noun c_gal = u3t(p_gal); - u3_noun d_gal = q_gal; - - zep = u3k(b_gal); - hod = _n_nock_on(u3k(bus), u3k(c_gal)); - nex = u3k(d_gal); - } - else { - u3_noun b_gal = p_gal; - u3_noun c_gal = q_gal; - - zep = u3k(b_gal); - hod = u3_nul; - nex = u3k(c_gal); - } - - u3a_lose(fol); - return _n_hint(zep, hod, bus, nex); - } - } - - case 11: { - u3_noun ref = _n_nock_on(u3k(bus), u3k(u3h(gal))); - u3_noun gof = _n_nock_on(bus, u3k(u3t(gal))); - u3_noun val; - - u3t_off(noc_o); - val = u3m_soft_esc(u3k(ref), u3k(gof)); - u3t_on(noc_o); - - if ( !_(u3du(val)) ) { - u3m_bail(u3nt(1, gof, 0)); - } - if ( !_(u3du(u3t(val))) ) { - // - // replace with proper error stack push - // - u3t_push(u3nt(c3__hunk, ref, gof)); - return u3m_bail(c3__exit); - } - else { - u3_noun pro; - - u3z(ref); - u3z(gof); - u3z(fol); - pro = u3k(u3t(u3t(val))); - u3z(val); - - return pro; - } - } - c3_assert(!"not reached"); - } - } -} -#endif - -// Several opcodes "overflow" (from byte to short index) to their successor, so -// order can matter here. -// Note that we use an X macro (https://en.wikipedia.org/wiki/X_Macro) to unify -// the opcode's enum name, string representation, and computed goto into a -// single structure. -#define OPCODES \ - /* non-nock bytecodes */ \ - X(HALT, "halt", &&do_halt), /* 0: terminator, end of bytcode program */ \ - X(BAIL, "bail", &&do_bail), /* 1: deterministic crash */ \ - /* stack manipulation */ \ - X(COPY, "copy", &&do_copy), /* 2 */ \ - X(SWAP, "swap", &&do_swap), /* 3 */ \ - X(TOSS, "toss", &&do_toss), /* 4 */ \ - /* auto-cons */ \ - X(AUTO, "auto", &&do_auto), /* 5: keep */ \ - X(AULT, "ault", &&do_ault), /* 6: lose */ \ - /* general purposes */ \ - X(SNOC, "snoc", &&do_snoc), /* 7: keep */ \ - X(SNOL, "snol", &&do_snol), /* 8: lose */ \ - /* nock 0: head */ \ - X(HEAD, "head", &&do_head), /* 9: keep */ \ - X(HELD, "held", &&do_held), /* 10: lose */ \ - /* nock 0: tail */ \ - X(TAIL, "tail", &&do_tail), /* 11: keep */ \ - X(TALL, "tall", &&do_tall), /* 12: lose */ \ - /* nock 0: fragment (keep) */ \ - X(FABK, "fabk", &&do_fabk), /* 13: c3_y */ \ - X(FASK, "fask", &&do_fask), /* 14: c3_s */ \ - X(FIBK, "fibk", &&do_fibk), /* 15: c3_y */ \ - X(FISK, "fisk", &&do_fisk), /* 16: c3_s */ \ - /* nock 0: fragment (lose) */ \ - X(FABL, "fabl", &&do_fabl), /* 17: c3_y */ \ - X(FASL, "fasl", &&do_fasl), /* 18: c3_s */ \ - X(FIBL, "fibl", &&do_fibl), /* 19: c3_y */ \ - X(FISL, "fisl", &&do_fisl), /* 20: c3_s */ \ - /* nock 1: literal (keep) */ \ - X(LIT0, "lit0", &&do_lit0), /* 21: a literal 0 */ \ - X(LIT1, "lit1", &&do_lit1), /* 22: a literal 1 */ \ - X(LITB, "litb", &&do_litb), /* 23: c3_y */ \ - X(LITS, "lits", &&do_lits), /* 24: c3_s */ \ - X(LIBK, "libk", &&do_libk), /* 25: c3_y */ \ - X(LISK, "lisk", &&do_lisk), /* 26: c3_s */ \ - /* nock 1: literal (lose) */ \ - X(LIL0, "lil0", &&do_lil0), /* 27: a literal 0 */ \ - X(LIL1, "lil1", &&do_lil1), /* 28: a literal 1 */ \ - X(LILB, "lilb", &&do_lilb), /* 29: c3_y */ \ - X(LILS, "lils", &&do_lils), /* 30: c3_s */ \ - X(LIBL, "libl", &&do_libl), /* 31: c3_y */ \ - X(LISL, "lisl", &&do_lisl), /* 32: c3_s */ \ - /* nock 2: nock (lose) */ \ - X(NOLK, "nolk", &&do_nolk), /* 33 */ \ - X(NOCT, "noct", &&do_noct), /* 34 */ \ - X(NOCK, "nock", &&do_nock), /* 35 */ \ - /* nock 3 & 4 */ \ - X(DEEP, "deep", &&do_deep), /* 36 */ \ - X(BUMP, "bump", &&do_bump), /* 37 */ \ - /* nock 5: equality */ \ - X(SAM0, "sam0", &&do_sam0), /* 38: test that it is equal to 0 */ \ - X(SAM1, "sam1", &&do_sam1), /* 39: test that it is equal to 1 */ \ - X(SAMB, "samb", &&do_samb), /* 40: test equality for vars size c3_b */ \ - X(SAMS, "sams", &&do_sams), /* 41: test equality for vars size c3_s */ \ - X(SANB, "sanb", &&do_sanb), /* 42: test equality for vars size c3_b */ \ - X(SANS, "sans", &&do_sans), /* 43: test equality for vars size c3_s */ \ - X(SAME, "same", &&do_same), /* 44 */ \ - X(SALM, "salm", &&do_salm), /* 45 */ \ - X(SAMC, "samc", &&do_samc), /* 46 */ \ - /* related to nock 6: unconditional skips */ \ - X(SBIP, "sbip", &&do_sbip), /* 47: c3_b */ \ - X(SIPS, "sips", &&do_sips), /* 48: c3_s */ \ - X(SWIP, "swip", &&do_swip), /* 49: c3_l */ \ - /* related to nock 6: conditional skips */ \ - X(SBIN, "sbin", &&do_sbin), /* 50: c3_b */ \ - X(SINS, "sins", &&do_sins), /* 51: c3_s */ \ - X(SWIN, "swin", &&do_swin), /* 52: c3_l */ \ - /* nock 9 */ \ - X(KICB, "kicb", &&do_kicb), /* 53: c3_b */ \ - X(KICS, "kics", &&do_kics), /* 54: c3_s */ \ - X(TICB, "ticb", &&do_ticb), /* 55: c3_b */ \ - X(TICS, "tics", &&do_tics), /* 56: c3_s */ \ - /* nock 12: scry (only defined in arvo, not in base nock spec) */ \ - X(WILS, "wils", &&do_wils), /* 57 */ \ - X(WISH, "wish", &&do_wish), /* 58 */ \ - /* nock 11: hint processing */ \ - X(BUSH, "bush", &&do_bush), /* 59: c3_b */ \ - X(SUSH, "sush", &&do_sush), /* 60: c3_s */ \ - X(DROP, "drop", &&do_drop), /* 61 */ \ - X(HECK, "heck", &&do_heck), /* 62 */ \ - X(SLOG, "slog", &&do_slog), /* 63 */ \ - /* nock 11: fast (keep) */ \ - X(BAST, "bast", &&do_bast), /* 64: c3_b */ \ - X(SAST, "sast", &&do_sast), /* 65: c3_s */ \ - /* nock 11: fast (lose) */ \ - X(BALT, "balt", &&do_balt), /* 66: c3_b */ \ - X(SALT, "salt", &&do_salt), /* 67: c3_s */ \ - /* nock 11: memo (keep) */ \ - X(SKIB, "skib", &&do_skib), /* 68: c3_b */ \ - X(SKIS, "skis", &&do_skis), /* 69: c3_s */ \ - /* nock 11: memo (lose) */ \ - X(SLIB, "slib", &&do_slib), /* 70: c3_b */ \ - X(SLIS, "slis", &&do_slis), /* 71: c3_s */ \ - X(SAVE, "save", &&do_save), /* 72 */ \ - /* nock 11: before formula */ \ - X(HILB, "hilb", &&do_hilb), /* 73: atomic, byte */ \ - X(HILS, "hils", &&do_hils), /* 74: atomic, short */ \ - X(HINB, "hinb", &&do_hinb), /* 75: arbitrary, byte */ \ - X(HINS, "hins", &&do_hins), /* 76: arbitrary, short */ \ - /* nock 11: after formula */ \ - X(HILK, "hilk", &&do_hilk), /* 77: atomic, keep */ \ - X(HILL, "hill", &&do_hill), /* 78: atomic, lose */ \ - X(HINK, "hink", &&do_hink), /* 79: arbitrary, keep */ \ - X(HINL, "hinl", &&do_hinl), /* 80: arbitrary, lose */ \ - /* nock 10 */ \ - X(MUTH, "muth", &&do_muth), /* 81 */ \ - X(KUTH, "kuth", &&do_kuth), /* 82 */ \ - X(MUTT, "mutt", &&do_mutt), /* 83 */ \ - X(KUTT, "kutt", &&do_kutt), /* 84 */ \ - X(MUSM, "musm", &&do_musm), /* 85 */ \ - X(KUSM, "kusm", &&do_kusm), /* 86 */ \ - X(MUTB, "mutb", &&do_mutb), /* 87: c3_b */ \ - X(MUTS, "muts", &&do_muts), /* 88: c3_s */ \ - X(MITB, "mitb", &&do_mitb), /* 89: c3_b */ \ - X(MITS, "mits", &&do_mits), /* 90: c3_s */ \ - X(KUTB, "kutb", &&do_kutb), /* 91: c3_b */ \ - X(KUTS, "kuts", &&do_kuts), /* 92: c3_s */ \ - X(KITB, "kitb", &&do_kitb), /* 93: c3_b */ \ - X(KITS, "kits", &&do_kits), /* 94: c3_s */ \ - X(LAST, NULL, NULL), /* 95 */ - -// Opcodes. Define X to select the enum name from OPCODES. -#define X(opcode, name, indirect_jump) opcode -enum { OPCODES }; -#undef X - -/* _n_arg(): return the size (in bytes) of an opcode's argument - */ -static inline c3_y -_n_arg(c3_y cod_y) -{ - switch ( cod_y ) { - case FABK: case FABL: case FIBL: case FIBK: - case LILB: case LITB: case LIBL: case LIBK: - case SAMB: case SANB: case SBIP: case SBIN: - case SLIB: case SKIB: case KICB: case TICB: - case BUSH: case BAST: case BALT: - case MUTB: case KUTB: case MITB: case KITB: - case HILB: case HINB: - return sizeof(c3_y); - - case FASK: case FASL: case FISL: case FISK: - case LILS: case LITS: case LISL: case LISK: - case SAMS: case SANS: case SIPS: case SINS: - case SLIS: case SKIS: case KICS: case TICS: - case SUSH: case SAST: case SALT: - case MUTS: case KUTS: case MITS: case KITS: - case HILS: case HINS: - return sizeof(c3_s); - - case SWIP: case SWIN: - return sizeof(c3_l); - - default: - c3_assert( cod_y < LAST ); - return 0; - } -} - - -/* _n_melt(): measure space for list of ops (from _n_comp) */ -static u3_noun -_n_melt(u3_noun ops, c3_w* byc_w, c3_w* cal_w, - c3_w* reg_w, c3_w* lit_w, c3_w* mem_w) -{ - c3_w len_w = u3qb_lent(ops), - i_w = len_w - 1, - a_w; - c3_y cod_y; - c3_y* siz_y = u3a_malloc(len_w); - u3_noun op, sip = u3_nul; - - while ( u3_nul != ops ) { - op = u3h(ops); - if ( c3n == u3du(op) ) { - switch ( op ) { - default: - siz_y[i_w] = 1; - break; - - case BAST: case BALT: - a_w = (*reg_w)++; - if ( a_w <= 0xFF ) { - siz_y[i_w] = 2; - } - else if ( a_w <= 0xFFFF ) { - siz_y[i_w] = 3; - } - else { - fprintf(stderr, "_n_melt(): over 2^16 registration sites.\r\n"); - c3_assert(0); - } - break; - } - } - else { - cod_y = u3h(op); - - switch ( cod_y ) { - default: - siz_y[i_w] = 1 + _n_arg(cod_y); - break; - - case SBIP: case SBIN: { - c3_l tot_l = 0, - sip_l = u3t(op); - c3_w j_w, k_w = i_w; - for ( j_w = 0; j_w < sip_l; ++j_w ) { - tot_l += siz_y[++k_w]; - } - sip = u3nc(tot_l, sip); - siz_y[i_w] = tot_l <= 0xFF ? 2 : tot_l <= 0xFFFF ? 3 : 5; - break; - } - - case SKIB: case SLIB: { - c3_l tot_l = 0, - sip_l = u3h(u3t(op)); - c3_w j_w, k_w = i_w; - for ( j_w = 0; j_w < sip_l; ++j_w ) { - tot_l += siz_y[++k_w]; - } - sip = u3nc(tot_l, sip); - a_w = (*mem_w)++; - if ( a_w <= 0xFF ) { - siz_y[i_w] = 2; - } - else if ( a_w <= 0xFFFF ) { - siz_y[i_w] = 3; - } - else { - fprintf(stderr, "_n_melt(): over 2^16 memos.\r\n"); - c3_assert(0); - } - break; - } - - case SIPS: case SINS: case SWIP: case SWIN: - case SAST: case SALT: case KICS: case TICS: - case FISK: case FISL: case SUSH: case SANS: - case LISL: case LISK: case SKIS: case SLIS: - case HILS: case HINS: - c3_assert(0); //overflows - break; - - case KICB: case TICB: - a_w = (*cal_w)++; - if ( a_w <= 0xFF ) { - siz_y[i_w] = 2; - } - else if ( a_w <= 0xFFFF ) { - siz_y[i_w] = 3; - } - else { - fprintf(stderr, "_n_melt(): over 2^16 call sites.\r\n"); - c3_assert(0); - } - break; - - case BUSH: case FIBK: case FIBL: - case SANB: case LIBL: case LIBK: - case KITB: case MITB: - case HILB: case HINB: - a_w = (*lit_w)++; - if ( a_w <= 0xFF ) { - siz_y[i_w] = 2; - } - else if ( a_w <= 0xFFFF ) { - siz_y[i_w] = 3; - } - else { - fprintf(stderr, "_n_melt(): over 2^16 literals.\r\n"); - c3_assert(0); - } - break; - } - } - - *(byc_w) += siz_y[i_w--]; - ops = u3t(ops); - } - - u3a_free(siz_y); - return u3kb_flop(sip); -} - -/* _n_prog_dat(): return pointer to program's data segment - */ -static void* -_n_prog_dat(u3n_prog* pog_u) -{ - return ((void*) pog_u) + sizeof(u3n_prog); -} - -/* _n_prog_new(): allocate and set up pointers for u3n_prog - */ -static u3n_prog* -_n_prog_new(c3_w byc_w, c3_w cal_w, - c3_w reg_w, c3_w lit_w, c3_w mem_w) -{ - c3_w cab_w = (sizeof(u3j_site) * cal_w), - reb_w = (sizeof(u3j_rite) * reg_w), - lib_w = (sizeof(u3_noun) * lit_w), - meb_w = (sizeof(u3n_memo) * mem_w), - dat_w = byc_w + cab_w + reb_w + lib_w + meb_w; - - u3n_prog* pog_u = u3a_malloc(sizeof(u3n_prog) + dat_w); - pog_u->byc_u.own_o = c3y; - pog_u->byc_u.len_w = byc_w; - pog_u->byc_u.ops_y = (c3_y*) _n_prog_dat(pog_u); - - pog_u->lit_u.len_w = lit_w; - pog_u->lit_u.non = (u3_noun*) (pog_u->byc_u.ops_y + pog_u->byc_u.len_w); - - pog_u->mem_u.len_w = mem_w; - pog_u->mem_u.sot_u = (u3n_memo*) (pog_u->lit_u.non + pog_u->lit_u.len_w); - - pog_u->cal_u.len_w = cal_w; - pog_u->cal_u.sit_u = (u3j_site*) (pog_u->mem_u.sot_u + pog_u->mem_u.len_w); - - pog_u->reg_u.len_w = reg_w; - pog_u->reg_u.rit_u = (u3j_rite*) (pog_u->cal_u.sit_u + pog_u->cal_u.len_w); - - return pog_u; -} - -/* _n_prog_old(): as _n_prog_new(), - * but leech off senior program's data segment - */ -static u3n_prog* -_n_prog_old(u3n_prog* sep_u) -{ - c3_w cab_w = sizeof(u3j_site) * sep_u->cal_u.len_w, - reb_w = sizeof(u3j_rite) * sep_u->reg_u.len_w, - lib_w = sizeof(u3_noun) * sep_u->lit_u.len_w, - meb_w = sizeof(u3n_memo) * sep_u->mem_u.len_w, - dat_w = cab_w + reb_w + lib_w + meb_w; - - u3n_prog* pog_u = u3a_malloc(sizeof(u3n_prog) + dat_w); - pog_u->byc_u.own_o = c3n; - pog_u->byc_u.len_w = sep_u->byc_u.len_w; - pog_u->byc_u.ops_y = sep_u->byc_u.ops_y; - - pog_u->lit_u.len_w = sep_u->lit_u.len_w; - pog_u->lit_u.non = (u3_noun*) _n_prog_dat(pog_u); - - pog_u->mem_u.len_w = sep_u->mem_u.len_w; - pog_u->mem_u.sot_u = (u3n_memo*) (pog_u->lit_u.non + pog_u->lit_u.len_w); - - pog_u->cal_u.len_w = sep_u->cal_u.len_w; - pog_u->cal_u.sit_u = (u3j_site*) (pog_u->mem_u.sot_u + pog_u->mem_u.len_w); - - pog_u->reg_u.len_w = sep_u->reg_u.len_w; - pog_u->reg_u.rit_u = (u3j_rite*) (pog_u->cal_u.sit_u + pog_u->cal_u.len_w); - - memcpy(pog_u->lit_u.non, sep_u->lit_u.non, dat_w); - return pog_u; -} - -/* _n_prog_asm_inx(): write an index to the bytestream with overflow - */ -static void -_n_prog_asm_inx(c3_y* buf_y, c3_w* i_w, c3_s inx_s, c3_y cod) -{ - if ( inx_s <= 0xFF ) { - buf_y[(*i_w)--] = (c3_y) (inx_s); - buf_y[*i_w] = (c3_y) cod; - } - else { - buf_y[(*i_w)--] = (c3_y) (inx_s >> 8); - buf_y[(*i_w)--] = (c3_y) (inx_s); - // the short-index versions of these opcodes must immediately - // follow the byte-index versions because of this convention - buf_y[(*i_w)] = cod + 1; - } -} - -/* _n_prog_asm(): assemble list of ops (from _n_comp) into u3n_prog - */ -static void -_n_prog_asm(u3_noun ops, u3n_prog* pog_u, u3_noun sip) -{ - u3_noun top = ops; - c3_y* buf_y = pog_u->byc_u.ops_y; - c3_s lit_s = 0, - cal_s = 0, - mem_s = 0, - reg_s = 0; - c3_w i_w = pog_u->byc_u.len_w-1; - - buf_y[i_w] = HALT; - - while ( i_w-- > 0 ) { - u3_noun op = u3h(ops); - if ( c3y == u3ud(op) ) { - switch ( op ) { - default: - buf_y[i_w] = (c3_y) op; - break; - - /* registration site index args */ - case BAST: case BALT: { - _n_prog_asm_inx(buf_y, &i_w, reg_s, op); - u3j_rite* rit_u = &(pog_u->reg_u.rit_u[reg_s++]); - rit_u->own_o = c3n; - rit_u->clu = u3_none; - rit_u->fin_p = 0; - break; - } - } - } - else { - u3_noun cod = u3h(op); - switch ( cod ) { - default: - c3_assert(0); - return; - - /* memo index args */ - case SKIB: case SLIB: { - u3n_memo* mem_u; - c3_l sip_l = u3h(sip); - u3_noun tmp = sip; - sip = u3k(u3t(sip)); - u3z(tmp); - _n_prog_asm_inx(buf_y, &i_w, mem_s, cod); - mem_u = &(pog_u->mem_u.sot_u[mem_s++]); - mem_u->sip_l = sip_l; - mem_u->key = u3k(u3t(u3t(op))); - break; - } - - /* skips */ - case SBIP: case SBIN: { - c3_l sip_l = u3h(sip); - u3_noun tmp = sip; - sip = u3k(u3t(sip)); - u3z(tmp); - if ( sip_l <= 0xFF ) { - buf_y[i_w--] = (c3_y) sip_l; - buf_y[i_w] = (c3_y) cod; - } - else if ( sip_l <= 0xFFFF ) { - buf_y[i_w--] = (c3_y) (sip_l >> 8); - buf_y[i_w--] = (c3_y) sip_l; - buf_y[i_w] = (c3_y) cod + 1; - } - else { - buf_y[i_w--] = (c3_y) (sip_l >> 24); - buf_y[i_w--] = (c3_y) (sip_l >> 16); - buf_y[i_w--] = (c3_y) (sip_l >> 8); - buf_y[i_w--] = (c3_y) sip_l; - buf_y[i_w] = (c3_y) cod + 2; - } - break; - } - - /* 8-bit direct args */ - case FABK: case FABL: - case LITB: case LILB: - case MUTB: case KUTB: - case SAMB: - buf_y[i_w--] = (c3_y) u3t(op); - buf_y[i_w] = (c3_y) cod; - break; - - /* 16-bit direct args */ - case FASK: case FASL: - case LILS: case LITS: - case MUTS: case KUTS: - case SAMS: case SIPS: case SINS: { - c3_s off_s = u3t(op); - buf_y[i_w--] = (c3_y) (off_s >> 8); - buf_y[i_w--] = (c3_y) off_s; - buf_y[i_w] = (c3_y) cod; - break; - } - - /* 31-bit direct args */ - case SWIP: case SWIN: { - c3_w off_l = u3t(op); - buf_y[i_w--] = (c3_y) (off_l >> 24); - buf_y[i_w--] = (c3_y) (off_l >> 16); - buf_y[i_w--] = (c3_y) (off_l >> 8); - buf_y[i_w--] = (c3_y) off_l; - buf_y[i_w] = (c3_y) cod; - break; - } - - /* literal index args */ - case FIBK: case FIBL: - case LIBK: case LIBL: - case BUSH: case SANB: - case KITB: case MITB: - case HILB: case HINB: - _n_prog_asm_inx(buf_y, &i_w, lit_s, cod); - pog_u->lit_u.non[lit_s++] = u3k(u3t(op)); - break; - - /* call site index args */ - case TICB: case KICB: { - _n_prog_asm_inx(buf_y, &i_w, cal_s, cod); - u3j_site* sit_u = &(pog_u->cal_u.sit_u[cal_s++]); - sit_u->axe = u3k(u3t(op)); - sit_u->pog_p = 0; - sit_u->bat = u3_none; - sit_u->bas = u3_none; - sit_u->loc = u3_none; - sit_u->lab = u3_none; - sit_u->jet_o = c3n; - sit_u->fon_o = c3n; - sit_u->cop_u = NULL; - sit_u->ham_u = NULL; - sit_u->fin_p = 0; - break; - } - } - } - ops = u3t(ops); - } - u3z(top); - // this assert will fail if we overflow a c3_w worth of instructions - c3_assert(u3_nul == ops); - // this is just a sanity check - c3_assert(u3_nul == sip); -} - -/* _n_prog_from_ops(): new program from _n_comp() product - */ -static u3n_prog* -_n_prog_from_ops(u3_noun ops) -{ - u3_noun sip; - u3n_prog* pog_u; - c3_w byc_w = 1, // HALT - cal_w = 0, - reg_w = 0, - lit_w = 0, - mem_w = 0; - - sip = _n_melt(ops, &byc_w, &cal_w, ®_w, &lit_w, &mem_w); - pog_u = _n_prog_new(byc_w, cal_w, reg_w, lit_w, mem_w); - _n_prog_asm(ops, pog_u, sip); - return pog_u; -} - -#if 0 -/* _n_print_stack(): print out the cap stack up to a designated "empty" - * used only for debugging - */ -static void _n_print_stack(u3p(u3_noun) empty) { - c3_w cur_p = u3R->cap_p; - fprintf(stderr, "["); - int first = 1; - while ( cur_p != empty ) { - if ( first ) { - first = 0; - } - else { - fprintf(stderr, " "); - } - if ( c3y == u3a_is_north(u3R) ) { - fprintf(stderr, "%u", *(u3to(u3_noun, cur_p))); - cur_p++; - } - else { - fprintf(stderr, "%u", *(u3to(u3_noun, cur_p-1))); - cur_p--; - } - } - fprintf(stderr, "]\r\n"); -} -#endif - -// Define X to select the opcode string representation from OPCODES. -# define X(opcode, name, indirect_jump) name -static c3_c* opcode_names[] = { OPCODES }; -# undef X - -/* _n_apen(): emit the instructions contained in src to dst - */ -static inline void -_n_apen(u3_noun* dst, u3_noun src) -{ - *dst = u3kb_weld(src, *dst); -} - -/* _n_emit(): emit a single instruction to ops - */ -static inline void -_n_emit(u3_noun *ops, u3_noun op) -{ - *ops = u3nc(op, *ops); -} - -static c3_w _n_comp(u3_noun*, u3_noun, c3_o, c3_o); - -/* _n_bint(): hint-processing helper for _n_comp. - * hif: hint-formula (first part of 11). RETAIN. - * nef: next-formula (second part of 11). RETAIN. - */ -static c3_w -_n_bint(u3_noun* ops, u3_noun hif, u3_noun nef, c3_o los_o, c3_o tel_o) -{ - c3_w tot_w = 0; - - if ( c3n == u3du(hif) ) { - // compile whitelisted atomic hints to dispatch protocol; - // compute and drop all others; - // - switch ( hif ) { - default: { - return _n_comp(ops, nef, los_o, tel_o); - } - case c3__xray: - case c3__nara: - case c3__hela: - case c3__bout: { - u3_noun fen = u3_nul; - c3_w nef_w = _n_comp(&fen, nef, los_o, c3n); - // add appropriate hind opcode - ++nef_w; _n_emit(&fen, ( c3y == los_o ) ? HILL : HILK); - // skip over the cleanup opcode - ++nef_w; _n_emit(&fen, u3nc(SBIP, 1)); - - // call hilt_fore - // HILB overflows to HILS - ++tot_w; _n_emit(ops, u3nc(HILB, u3nc(u3k(hif), u3k(nef)))); - // if fore return c3n, skip fen - ++tot_w; _n_emit(ops, u3nc(SBIN, nef_w)); - tot_w += nef_w; _n_apen(ops, fen); - // post-skip cleanup opcode - ++tot_w; _n_emit(ops, ( c3y == los_o ) ? TOSS : SWAP); - } break; - } - } - else { - u3_noun zep, hod; - u3x_cell(hif, &zep, &hod); - - switch ( zep ) { - default: { - // compile whitelisted dynamic hints to dispatch protocol; - // compute and drop all others; - // - switch ( zep ) { - default: { - tot_w += _n_comp(ops, hod, c3n, c3n); - ++tot_w; _n_emit(ops, TOSS); - tot_w += _n_comp(ops, nef, los_o, tel_o); - } break; - case c3__xray: - case c3__nara: - case c3__hela: - case c3__bout: { - u3_noun fen = u3_nul; - c3_w nef_w = _n_comp(&fen, nef, los_o, c3n); - // add appropriate hind opcode - ++nef_w; _n_emit(&fen, ( c3y == los_o ) ? HINL : HINK); - // skip over the cleanup opcode - ++nef_w; _n_emit(&fen, u3nc(SBIP, 1)); - - // push clue - tot_w += _n_comp(ops, hod, c3n, c3n); - // call hint_fore - // HINB overflows to HINS - ++tot_w; _n_emit(ops, u3nc(HINB, u3nc(u3k(zep), u3k(nef)))); - // if fore return c3n, skip fen - ++tot_w; _n_emit(ops, u3nc(SBIN, nef_w)); - tot_w += nef_w; _n_apen(ops, fen); - // post-skip cleanup opcode - ++tot_w; _n_emit(ops, ( c3y == los_o ) ? TOSS : SWAP); - } break; - } - } break; - - case c3__hunk: - case c3__lose: - case c3__mean: - case c3__spot: - tot_w += _n_comp(ops, hod, c3n, c3n); - ++tot_w; _n_emit(ops, u3nc(BUSH, zep)); // overflows to SUSH - tot_w += _n_comp(ops, nef, los_o, c3n); - ++tot_w; _n_emit(ops, DROP); - break; - - case c3__live: - tot_w += _n_comp(ops, hod, c3n, c3n); - ++tot_w; _n_emit(ops, HECK); - tot_w += _n_comp(ops, nef, los_o, tel_o); - break; - - case c3__slog: - tot_w += _n_comp(ops, hod, c3n, c3n); - ++tot_w; _n_emit(ops, SLOG); - tot_w += _n_comp(ops, nef, los_o, tel_o); - break; - - // germ and sole are unused... - - case c3__fast: - tot_w += _n_comp(ops, hod, c3n, c3n); - ++tot_w; _n_emit(ops, SWAP); - tot_w += _n_comp(ops, nef, c3n, c3n); - // overflows to SALT / SAST - ++tot_w; _n_emit(ops, (c3y == los_o) ? BALT : BAST); - break; - - case c3__memo: { - u3_noun mem = u3_nul; - c3_w mem_w = 0; - c3_y op_y; - - // we just throw away the hint (why is this not a static hint?) - tot_w += _n_comp(ops, hod, c3n, c3n); - ++tot_w; _n_emit(ops, TOSS); - - // memoizing code always loses TOS because SAVE needs [pro key] - mem_w += _n_comp(&mem, nef, c3y, c3n); - ++mem_w; _n_emit(&mem, SAVE); - - op_y = (c3y == los_o) ? SLIB : SKIB; // overflows to SLIS / SKIS - ++tot_w; _n_emit(ops, u3nt(op_y, mem_w, u3k(nef))); - tot_w += mem_w; _n_apen(ops, mem); - break; - } - } - } - - return tot_w; -} - -static c3_t -_n_formulaic(u3_noun fol) -{ - u3_noun op, ar, a, b, c; - if ( c3n == u3r_cell(fol, &op, &ar) ) { - return 0; - } - if ( c3y == u3du(op) ) { - return _n_formulaic(op) && _n_formulaic(ar); - } - else switch ( op ) { - case 0: - return ( c3y == u3ud(ar) ); - case 1: - return 1; - case 3: - case 4: - return _n_formulaic(ar); - case 2: - case 5: - case 7: - case 8: - case 12: - return (c3y == u3r_cell(ar, &a, &b)) - && _n_formulaic(a) && _n_formulaic(b); - case 6: - return ( c3y == u3r_trel(ar, &a, &b, &c) ) - && _n_formulaic(a) && - (_n_formulaic(b) || _n_formulaic(c)); - case 9: - return (c3y == u3r_cell(ar, &a, &b)) - && (c3y == u3ud(a)) - && _n_formulaic(b); - case 10: - if ( c3n == u3r_cell(ar, &a, &b) ) { - return 0; - } - if ( c3n == u3du(a) ) { - return 0; - } - if ( c3n == u3ud(u3h(a)) ) { - return 0; - } - return _n_formulaic(u3t(a)) && _n_formulaic(b); - case 11: - if ( c3n == u3r_cell(ar, &a, &b) ) { - return 0; - } - if ( !_n_formulaic(b) ) { - return 0; - } - if ( c3y == u3ud(a) ) { - return 1; - } - else { - return ( c3y == u3ud(u3h(a)) ) && _n_formulaic(u3t(a)); - } - default: - return 0; - } -} - -/* _n_comp(): compile nock formula to reversed opcode list - * ops is a pointer to a list (to be emitted to) - * fol is the nock formula to compile. RETAIN. - * los_o indicates whether we should remove our - * subject from the stack - * tel_o is yes if this formula is in tail position - * return: number of instructions added to the opcode list - */ -static c3_w -_n_comp(u3_noun* ops, u3_noun fol, c3_o los_o, c3_o tel_o) -{ - c3_y op_y; - c3_w tot_w = 0; - u3_noun cod, arg, hed, tel; - u3x_cell(fol, &cod, &arg); - if ( c3y == u3du(cod) ) { - tot_w += _n_comp(ops, cod, c3n, c3n); - ++tot_w; _n_emit(ops, SWAP); - tot_w += _n_comp(ops, arg, c3n, c3n); - ++tot_w; _n_emit(ops, (c3y == los_o ) ? AULT : AUTO); - } - else switch ( cod ) { - case 0: - if ( c3n == u3ud(arg) ) { - u3m_bail(c3__exit); - return 0; - } - switch ( arg ) { - case 0: - ++tot_w; _n_emit(ops, BAIL); - break; - case 1: - if ( c3n == los_o ) { - ++tot_w; _n_emit(ops, COPY); - } - break; - case 2: - ++tot_w; _n_emit(ops, (c3y == los_o) ? HELD : HEAD); - break; - case 3: - ++tot_w; _n_emit(ops, (c3y == los_o) ? TALL : TAIL); - break; - default: - op_y = (c3y == los_o) - ? (arg <= 0xFF ? FABL : arg <= 0xFFFF ? FASL : FIBL) // overflows to FISL - : (arg <= 0xFF ? FABK : arg <= 0xFFFF ? FASK : FIBK); // overflows to FISK - ++tot_w; _n_emit(ops, u3nc(op_y, u3k(arg))); - break; - } - break; - - case 1: - switch ( arg ) { - case 0: - ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL0 : LIT0); - break; - case 1: - ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL1 : LIT1); - break; - default: - op_y = (c3y == los_o) - ? (arg <= 0xFF ? LILB : arg <= 0xFFFF ? LILS : LIBL) // overflows to LISL - : (arg <= 0xFF ? LITB : arg <= 0xFFFF ? LITS : LIBK); // overflows to LISK - ++tot_w; _n_emit(ops, u3nc(op_y, u3k(arg))); - break; - } - break; - - case 2: - u3x_cell(arg, &hed, &tel); - tot_w += _n_comp(ops, hed, c3n, c3n); - ++tot_w; _n_emit(ops, SWAP); - tot_w += _n_comp(ops, tel, c3n, c3n); - /* things in tail position replace (so, lose) top of stack, - * so NOCT "loses" and there is no non-losing version */ - op_y = (c3y == tel_o) ? NOCT - : ((c3y == los_o) ? NOLK : NOCK); - ++tot_w; _n_emit(ops, op_y); - break; - - case 3: - tot_w += _n_comp(ops, arg, los_o, c3n); - ++tot_w; _n_emit(ops, DEEP); - break; - - case 4: - tot_w += _n_comp(ops, arg, los_o, c3n); - ++tot_w; _n_emit(ops, BUMP); - break; - - case 5: { - u3x_cell(arg, &hed, &tel); - - if ( c3n == u3du(hed) ) { - u3m_bail(c3__exit); - return 0; - } - else { - c3_t hec_t, tec_t; - hec_t = (1 == u3h(hed)); - if ( c3n == u3du(tel) ) { - u3m_bail(c3__exit); - break; - } - else { - tec_t = (1 == u3h(tel)); - } - if ( hec_t && tec_t ) { - if ( c3y == u3r_sing(u3t(hed), u3t(tel)) ) { - ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL0 : LIT0); - } - else { - ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL1 : LIT1); - } - } - else if ( !hec_t && !tec_t ) { - tot_w += _n_comp(ops, hed, c3n, c3n); - ++tot_w; _n_emit(ops, SWAP); - tot_w += _n_comp(ops, tel, c3n, c3n); - ++tot_w; _n_emit(ops, (c3y == los_o) ? SALM : SAME); - } - else { - tot_w += _n_comp(ops, (hec_t ? tel : hed), los_o, c3n); - u3_noun lit = u3t(hec_t ? hed : tel); - switch ( lit ) { - case 0: - ++tot_w; _n_emit(ops, SAM0); - break; - case 1: - ++tot_w; _n_emit(ops, SAM1); - break; - default: - // overflows to SANS - op_y = lit <= 0xFF ? SAMB : lit <= 0xFFFF ? SAMS : SANB; - ++tot_w; _n_emit(ops, u3nc(op_y, u3k(lit))); - } - } - } - break; - } - - case 6: { - u3_noun mid, - yep = u3_nul, - nop = u3_nul; - c3_w yep_w, nop_w; - c3_t yep_t, nop_t; - u3x_trel(arg, &hed, &mid, &tel); - - tot_w += _n_comp(ops, hed, c3n, c3n); - yep_t = _n_formulaic(mid); - nop_t = _n_formulaic(tel); - - if ( !yep_t && !nop_t ) { - u3m_bail(c3__exit); - break; - } - - if ( yep_t ) { - yep_w = _n_comp(&yep, mid, los_o, tel_o); - } - else { - yep_w = 1; _n_emit(&yep, BAIL); - } - - if ( nop_t ) { - nop_w = _n_comp(&nop, tel, los_o, tel_o); - } - else { - nop_w = 1; _n_emit(&nop, BAIL); - } - - // SBIP and SBIN get sized during assembly - ++yep_w; _n_emit(&yep, u3nc(SBIP, nop_w)); - ++tot_w; _n_emit(ops, u3nc(SBIN, yep_w)); - tot_w += yep_w; _n_apen(ops, yep); - tot_w += nop_w; _n_apen(ops, nop); - break; - } - - case 7: - u3x_cell(arg, &hed, &tel); - tot_w += _n_comp(ops, hed, los_o, c3n); - tot_w += _n_comp(ops, tel, c3y, tel_o); - break; - - case 8: - u3x_cell(arg, &hed, &tel); - tot_w += _n_comp(ops, hed, c3n, c3n); - ++tot_w; _n_emit(ops, (c3y == los_o) ? SNOL : SNOC); - tot_w += _n_comp(ops, tel, c3y, tel_o); - break; - - case 9: - u3x_cell(arg, &hed, &tel); - if ( (1 == hed) || (3 == u3qc_cap(hed)) ) { - u3_noun mac = u3nq(7, u3k(tel), 2, u3nt(u3nc(0, 1), 0, u3k(hed))); - tot_w += _n_comp(ops, mac, los_o, tel_o); - u3z(mac); - } - else { - tot_w += _n_comp(ops, tel, (c3y == tel_o ? c3y : los_o), c3n); - op_y = (c3y == tel_o) ? TICB : KICB; // overflows to TICS/KICS - ++tot_w; _n_emit(ops, u3nc(op_y, u3k(hed))); - } - break; - - case 10: { - u3_noun axe, nef; - u3x_cell(arg, &hed, &tel); - u3x_cell(hed, &axe, &nef); - tot_w += _n_comp(ops, tel, c3n, c3n); - ++tot_w; _n_emit(ops, SWAP); - tot_w += _n_comp(ops, nef, c3n, c3n); - - ++tot_w; - switch ( axe ) { - case 2: - _n_emit(ops, (c3y == los_o) ? MUTH : KUTH); - break; - - case 3: - _n_emit(ops, (c3y == los_o) ? MUTT : KUTT); - break; - - case u3x_sam: - _n_emit(ops, (c3y == los_o) ? MUSM : KUSM); - break; - - default: - op_y = (c3y == los_o) - ? (axe <= 0xFF) ? MUTB : (axe <= 0xFFFF) ? MUTS : MITB // overflows to MITS - : (axe <= 0xFF) ? KUTB : (axe <= 0xFFFF) ? KUTS : KITB; // overflows to KITS - _n_emit(ops, u3nc(op_y, u3k(axe))); - break; - } - break; - } - - case 11: - u3x_cell(arg, &hed, &tel); - tot_w += _n_bint(ops, hed, tel, los_o, tel_o); - break; - - case 12: - u3x_cell(arg, &hed, &tel); - tot_w += _n_comp(ops, hed, c3n, c3n); - ++tot_w; _n_emit(ops, SWAP); - tot_w += _n_comp(ops, tel, c3n, c3n); - ++tot_w; _n_emit(ops, (c3y == los_o) ? WILS : WISH); - break; - - default: - u3m_bail(c3__exit); - return 0; - } - return tot_w; -} - -/* _n_push(): push a noun onto the stack. RETAIN - * mov: -1 north, 1 south - * off: 0 north, -1 south - */ -static inline void -_n_push(c3_ys mov, c3_ys off, u3_noun a) -{ - u3R->cap_p += mov; - - // XX switch to u3a_push() - // -#ifndef U3_GUARD_PAGE - if ( 0 == off ) { - if( !(u3R->cap_p > u3R->hat_p) ) { - u3m_bail(c3__meme); - } - } - else { - if( !(u3R->cap_p < u3R->hat_p) ) { - u3m_bail(c3__meme); - } - } -#endif - - u3_noun* p = u3to(u3_noun, u3R->cap_p + off); - *p = a; -} - -/* _n_peek(): pointer to noun at top of stack - * off: 0 north, -1 south - */ -static inline u3_noun* -_n_peek(c3_ys off) -{ - return u3to(u3_noun, u3R->cap_p + off); -} - -/* _n_peet(): address of the next-to-top of stack - * mov: -1 north, 1 south - * off: 0 north, -1 south - */ -static inline u3_noun* -_n_peet(c3_ys mov, c3_ys off) -{ - return u3to(u3_noun, (u3R->cap_p - mov) + off); -} - -/* _n_pop(): pop a noun from the cap stack - * mov: -1 north, 1 south - */ -static inline void -_n_pop(c3_ys mov) -{ - u3R->cap_p -= mov; -} - -/* _n_pep(): pop and return noun from the cap stack - * mov: -1 north, 1 south - * off: 0 north, -1 south - */ -static inline u3_noun -_n_pep(c3_ys mov, c3_ys off) -{ - u3_noun r = *(_n_peek(off)); - _n_pop(mov); - return r; -} - -/* _n_toss(): pep and lose - */ -static inline void -_n_toss(c3_ys mov, c3_ys off) -{ - u3z(_n_pep(mov, off)); -} - -/* _n_resh(): read a c3_s from the bytecode stream - */ -static inline c3_s -_n_resh(c3_y* buf, c3_w* ip_w) -{ - c3_y les = buf[(*ip_w)++]; - c3_y mos = buf[(*ip_w)++]; - return les | (mos << 8); -} - -/* _n_rewo(): read a c3_w from the bytecode stream. - */ -static inline c3_w -_n_rewo(c3_y* buf, c3_w* ip_w) -{ - c3_y one = buf[(*ip_w)++], - two = buf[(*ip_w)++], - tre = buf[(*ip_w)++], - qua = buf[(*ip_w)++]; - return one | (two << 8) | (tre << 16) | (qua << 24); -} - -/* _n_swap(): swap two items on the top of the stack, return pointer to top - */ -static inline u3_noun* -_n_swap(c3_ys mov, c3_ys off) -{ - u3_noun* top = _n_peek(off); - u3_noun* up = _n_peet(mov, off); - u3_noun tmp = *up; - *up = *top; - *top = tmp; - return top; -} - -#ifdef VERBOSE_BYTECODE -/* _n_print_byc(): print bytecode. used for debugging. - */ -static void -_n_print_byc(c3_y* pog, c3_w her_w) -{ - c3_w ip_w = 0; - if ( her_w == 0 ) { - fprintf(stderr, "begin: {"); - } - else { - fprintf(stderr, "resume: {"); - } - int first = 1; - while ( pog[ip_w] ) { - if ( first ) { - first = 0; - } - else if (ip_w == her_w) { - fprintf(stderr, " [*]"); - } - else { - fprintf(stderr, " "); - } - switch ( _n_arg(pog[ip_w]) ) { - case 0: - fprintf(stderr, "%s", opcode_names[pog[ip_w++]]); - break; - - case 1: - fprintf(stderr, "[%s ", opcode_names[pog[ip_w++]]); - fprintf(stderr, "%u]", pog[ip_w++]); - break; - - case 2: - fprintf(stderr, "[%s ", opcode_names[pog[ip_w++]]); - fprintf(stderr, "%u]", _n_resh(pog, &ip_w)); - break; - - case 4: - fprintf(stderr, "[%s", opcode_names[pog[ip_w++]]); - fprintf(stderr, "%u]", _n_rewo(pog, &ip_w)); - break; - default: - c3_assert(0); - break; - } - } - fprintf(stderr, " halt}\r\n"); -} -#endif - -/* _n_bite(): compile a nock formula to bytecode. RETAIN. - */ -static inline u3n_prog* -_n_bite(u3_noun fol) { - u3_noun ops = u3_nul; - _n_comp(&ops, fol, c3y, c3y); - return _n_prog_from_ops(ops); -} - -/* _n_find(): return prog for given formula with prefix (u3_nul for none). - * RETAIN. - */ -static u3n_prog* -_n_find(u3_noun pre, u3_noun fol) -{ - u3_noun key = u3nc(u3k(pre), u3k(fol)); - u3_weak pog = u3h_git(u3R->byc.har_p, key); - if ( u3_none != pog ) { - u3z(key); - return u3to(u3n_prog, pog); - } - else if ( u3R != &u3H->rod_u ) { - u3a_road* rod_u = u3R; - while ( rod_u->par_p ) { - rod_u = u3to(u3a_road, rod_u->par_p); - pog = u3h_git(rod_u->byc.har_p, key); - if ( u3_none != pog ) { - c3_w i_w; - u3n_prog* old = _n_prog_old(u3to(u3n_prog, pog)); - for ( i_w = 0; i_w < old->reg_u.len_w; ++i_w ) { - u3j_rite* rit_u = &(old->reg_u.rit_u[i_w]); - rit_u->own_o = c3n; - } - for ( i_w = 0; i_w < old->cal_u.len_w; ++i_w ) { - u3j_site* sit_u = &(old->cal_u.sit_u[i_w]); - sit_u->bat = u3_none; - sit_u->pog_p = 0; - sit_u->fon_o = c3n; - } - u3h_put(u3R->byc.har_p, key, u3a_outa(old)); - u3z(key); - return old; - } - } - } - - { - u3n_prog* gop = _n_bite(fol); - u3h_put(u3R->byc.har_p, key, u3a_outa(gop)); - u3z(key); - return gop; - } -} - -/* u3n_find(): return prog for given formula, - * split by key (u3_nul for no key). RETAIN. - */ -u3p(u3n_prog) -u3n_find(u3_noun key, u3_noun fol) -{ - u3p(u3n_prog) pog_p; - u3t_on(noc_o); - pog_p = u3of(u3n_prog, _n_find(key, fol)); - u3t_off(noc_o); - return pog_p; -} - -/* _cn_prog_free(): free memory retained by program pog_u -*/ -static void -_cn_prog_free(u3n_prog* pog_u) -{ - c3_w dex_w; - for (dex_w = 0; dex_w < pog_u->lit_u.len_w; ++dex_w) { - u3z(pog_u->lit_u.non[dex_w]); - } - for (dex_w = 0; dex_w < pog_u->mem_u.len_w; ++dex_w) { - u3z(pog_u->mem_u.sot_u[dex_w].key); - } - for (dex_w = 0; dex_w < pog_u->cal_u.len_w; ++dex_w) { - u3j_site_lose(&(pog_u->cal_u.sit_u[dex_w])); - } - for (dex_w = 0; dex_w < pog_u->reg_u.len_w; ++dex_w) { - u3j_rite_lose(&(pog_u->reg_u.rit_u[dex_w])); - } - u3a_free(pog_u); -} - -/* _cn_intlen(): find the number of characters num_w would take to print. -** num_w: an int we want to later serialize to a string -*/ -c3_w -_cn_intlen(c3_w num_w) -{ - c3_w len_w=0; - while(num_w){ - num_w/=10; - len_w++; - } - return len_w; -} - -/* _cn_is_indexed(): return true if bop_w is an opcodes that uses pog_u->lit_u.non -** bop_w: opcode (assumed 0-94) -*/ -c3_b -_cn_is_indexed(c3_w bop_w) -{ - switch (bop_w) { - case FIBK: case FISK: - case FIBL: case FISL: - case LIBK: case LISK: - case LIBL: case LISL: - case BUSH: case SUSH: - case SANB: case SANS: - case KITB: case KITS: - case MITB: case MITS: - case HILB: case HILS: - case HINB: case HINS: - return 1; - default: - return 0; - } -} - -/* _cn_pog_to_num(): read a bytecode from the steam and advance the index -** par_w: c3_w: can be 0, 2, 4 -** pog_y: c3_y*: a bytecode stream -** ip_w: c3_w: an index into pog -*/ -#define _cn_pog_to_num(par_w, pog_y, ip_w) (\ - par_w == 4 ? _n_rewo(pog_y, &ip_w): \ - par_w == 2 ? _n_resh(pog_y, &ip_w): \ - pog_y[ip_w++]) - -/* _cn_etch_bytecode(): render a nock program as string of bytecodes -** fol: a nock formula to compile and render -** returns: a u3i_string noun of the rendered bytecode -*/ -u3_noun -_cn_etch_bytecode(u3_noun fol) { - u3n_prog* pog_u = _n_bite(fol); - c3_y* pog_y = pog_u->byc_u.ops_y; - c3_w len_w = pog_u->byc_u.len_w; - c3_w ip_w=0, num_w=0, bop_w=0, dex_w=0; - c3_w len_c = 1; // opening "{" - // set par_w (parameter flag) to an invalid value, - // so we can break imeadately if needed - c3_w par_w = 5; - // lets count the chars in this string - while ( ip_w < len_w ) { - par_w = _n_arg(pog_y[ip_w]); - bop_w = pog_y[ip_w++]; // move ip_w for reading a opcode name - dex_w = _cn_is_indexed(bop_w); // is this an indexed bytecode argument - len_c += 5; // a leading space, and opcode name - if (par_w > 0) { // if pair: "[bytecode arg]" else "bytecode" - len_c += 3; // "[", space between opcode & arg, "]" - if ( dex_w ) len_c += 2; // 'i:' - len_c += _cn_intlen( // length of the bytecode argument - _cn_pog_to_num(par_w, pog_y, ip_w) - ); - } - } - // reset so we can loop again - ip_w=0, num_w=0, bop_w=0, dex_w=0, par_w=5; - // init our string, and give it a trailing null - c3_c str_c[len_c]; - str_c[0] = 0; - // lets print this string - while ( ip_w < len_w ) { - par_w = _n_arg(pog_y[ip_w]); - bop_w = pog_y[ip_w++]; // move ip_w for reading a opcode name - dex_w = _cn_is_indexed(bop_w); // is this an indexed bytecode argument - strcat(str_c, " "); // leading space - if (par_w > 0) strcat(str_c, "["); // add "[" if the opcode pairs - strncat(str_c, opcode_names[bop_w], 4); // add the opcode name - if (par_w > 0) { // finish the pair - strcat(str_c, " "); // add the space between byt and arg - if ( dex_w ) strcat(str_c, "i:"); // indexed args are labeled as "index of arg" - num_w = _cn_pog_to_num(par_w, pog_y, ip_w); // the bytecode argument - if (num_w == 0) { // - strcat(str_c, "0"); // handle a literal zero - } // - else { // - c3_w x = 0; // - for (x = _cn_intlen(num_w); x > 0; x--) { // - strcat(str_c, "_"); // prefill the buffer - } // - c3_w f = strlen(str_c)-1; // get the index of the last prefill - while (num_w > 0) { // stringify number in LSB order - str_c[f--] = (num_w%10)+'0'; // .. stringify the tail of num into tail of buf - num_w /= 10; // .. turncate num by one digit - } // - } // - strcat(str_c, "]"); // add the closing brace - } - } - // replace the first leading space and append the last char to the string - str_c[0] = '{'; - strcat(str_c, "}"); - _cn_prog_free(pog_u); - return u3i_string(str_c); -} - - -/* _n_hilt_fore(): literal (atomic) dynamic hint, before formula evaluation. -** hin: [hint-atom, formula]. TRANSFER -** bus: subject. RETAIN -** out: token for _n_hilt_hind(); convention: -** [hint-atom] or [hint-atom data], ~ if unused. -** -** any hints herein must be whitelisted in _n_burn(). -*/ -static c3_o -_n_hilt_fore(u3_noun hin, u3_noun bus, u3_noun* out) -{ - u3_noun tag, fol; - u3x_cell(hin, &tag, &fol); - - switch ( tag ) { - case c3__bout: { - u3_atom now = u3i_chub(u3t_trace_time()); - *out = u3i_cell(tag, now); - } break; - - case c3__nara : { - u3t_slog_nara(0); - *out = u3_nul; - } break; - - case c3__hela : { - u3t_slog_hela(0); - *out = u3_nul; - } break; - - case c3__xray : { - u3t_slog(u3nc(0, _cn_etch_bytecode(fol))); - *out = u3_nul; - } break; - - default: { - *out = u3_nul; - } break; - } - - u3z(hin); - return c3y; -} - -/* _n_hilt_hind(): literal (atomic) dynamic hint, after formula evaluation. -** tok: token from _n_hilt_fore(). TRANSFER -** pro: product of formula evaluation. RETAIN -*/ -static void -_n_hilt_hind(u3_noun tok, u3_noun pro) -{ - u3_noun p_tok, q_tok; - if ( (c3y == u3r_cell(tok, &p_tok, &q_tok)) && (c3__bout == p_tok) ) { - u3_atom delta = u3ka_sub(u3i_chub(u3t_trace_time()), u3k(q_tok)); - c3_c str_c[64]; - u3a_print_time(str_c, "took", u3r_chub(0, delta)); - u3t_slog(u3nc(0, u3i_string(str_c))); - u3z(delta); - } - else { - c3_assert( u3_nul == tok ); - } - - u3z(tok); -} - -/* _n_hint_fore(): arbitrary dynamic hint, before formula evaluation -** hin: [hint-atom, formula]. TRANSFER -** bus: subject. RETAIN -** clu: product of the hint-formula. TRANSFER -** also, token for _n_hilt_hind(); convention: -** [hint-atom] or [hint-atom data], ~ if unused. -** -** any hints herein must be whitelisted in _n_burn(). -*/ -static c3_o -_n_hint_fore(u3_cell hin, u3_noun bus, u3_noun* clu) -{ - u3_noun tag, fol; - u3x_cell(hin, &tag, &fol); - - switch ( tag ) { - case c3__bout: { - u3_atom now = u3i_chub(u3t_trace_time()); - *clu = u3nt(u3k(tag), *clu, now); - } break; - - case c3__nara: { - u3_noun pri, tan; - if ( c3y == u3r_cell(*clu, &pri, &tan) ) { - c3_l pri_l = c3y == u3a_is_cat(pri) ? pri : 0; - u3t_slog_cap(pri_l, u3i_string("trace of"), u3k(tan)); - u3t_slog_nara(pri_l); - } - u3z(*clu); - *clu = u3_nul; - } break; - - case c3__hela: { - u3_noun pri, tan; - if ( c3y == u3r_cell(*clu, &pri, &tan) ) { - c3_l pri_l = c3y == u3a_is_cat(pri) ? pri : 0; - u3t_slog_cap(pri_l, u3i_string("trace of"), u3k(tan)); - u3t_slog_hela(pri_l); - } - u3z(*clu); - *clu = u3_nul; - } break; - - case c3__xray : { - u3_noun pri, tan; - if ( c3y == u3r_cell(*clu, &pri, &tan) ) { - c3_l pri_l = c3y == u3a_is_cat(pri) ? pri : 0; - u3t_slog_cap(pri_l, u3k(tan), _cn_etch_bytecode(fol)); - } - u3z(*clu); - *clu = u3_nul; - } break; - - default: { - u3z(*clu); - *clu = u3_nul; - } break; - } - - u3z(hin); - return c3y; -} - -/* _n_hint_hind(): arbitrary dynamic hint, after formula evaluation. -** tok: token from _n_hint_fore(). TRANSFER -** pro: product of formula evaluation. RETAIN -*/ -static void -_n_hint_hind(u3_noun tok, u3_noun pro) -{ - u3_noun p_tok, q_tok, r_tok; - if ( (c3y == u3r_trel(tok, &p_tok, &q_tok, &r_tok)) && (c3__bout == p_tok) ) { - // get the microseconds elapsed - u3_atom delta = u3ka_sub(u3i_chub(u3t_trace_time()), u3k(r_tok)); - - // unpack q_tok to get the priority integer and the tank - // p_q_tok is the priority, q_q_tok is the tank we will work with - u3_noun p_q_tok, q_q_tok; - c3_assert(c3y == u3r_cell(q_tok, &p_q_tok, &q_q_tok)); - - // format the timing report - c3_c str_c[64]; - u3a_print_time(str_c, "took", u3r_chub(0, delta)); - - // join the timing report with the original tank from q_q_tok like so: - // "q_q_tok: report" - // prepend the priority to form a cell of the same shape q_tok - // send this to ut3_slog so that it can be logged out - c3_l pri_l = c3y == u3a_is_cat(p_q_tok) ? p_q_tok : 0; - u3t_slog_cap(pri_l, u3k(q_q_tok), u3i_string(str_c)); - u3z(delta); - } - else { - c3_assert( u3_nul == tok ); - } - - u3z(tok); -} - -/* _n_kick(): stop tracing noc and kick a u3j_site. - */ -static u3_weak -_n_kick(u3_noun cor, u3j_site* sit_u) -{ - u3_weak pro; - u3t_off(noc_o); - pro = u3j_site_kick(cor, sit_u); - u3t_on(noc_o); - return pro; -} - -/* _n_kale(): bail(exit) if not cell - */ -static inline u3_noun -_n_kale(u3_noun a) -{ - if ( c3n == u3du(a) ) { - u3m_bail(c3__exit); - } - return a; -} - -typedef struct { - u3n_prog* pog_u; - c3_w ip_w; -} burnframe; - -/* _n_burn(): pog: program - * bus: subject (TRANSFER) - * mov: -1 north, 1 south - * off: 0 north, -1 south - */ -static u3_noun -_n_burn(u3n_prog* pog_u, u3_noun bus, c3_ys mov, c3_ys off) -{ - - // Opcode jump table. Define X to select the opcode computed goto from - // OPCODES. -# define X(opcode, name, indirect_jump) indirect_jump - static void* lab[] = { OPCODES }; -# undef X - - u3j_site* sit_u; - u3j_rite* rit_u; - u3n_memo* mem_u; - c3_y *pog = pog_u->byc_u.ops_y; - c3_w sip_w, ip_w = 0; - u3_noun* top; - u3_noun x, o; - u3p(void) empty; - burnframe* fam; - - empty = u3R->cap_p; - _n_push(mov, off, bus); - -#ifdef U3_CPU_DEBUG - u3R->pro.nox_d += 1; -#endif -#ifdef VERBOSE_BYTECODE - #define BURN() fprintf(stderr, "%s ", opcode_names[pog[ip_w]]); goto *lab[pog[ip_w++]] -#else - #define BURN() goto *lab[pog[ip_w++]] -#endif - BURN(); - { - do_halt: // [product ...burnframes...] - x = _n_pep(mov, off); -#ifdef VERBOSE_BYTECODE - fprintf(stderr, "return\r\n"); -#endif - if ( empty == u3R->cap_p ) { - return x; - } - else { - fam = u3to(burnframe, u3R->cap_p) + off; - pog_u = fam->pog_u; - pog = pog_u->byc_u.ops_y; - ip_w = fam->ip_w; - - u3R->cap_p = u3of(burnframe, fam - (mov+off)); - _n_push(mov, off, x); -#ifdef VERBOSE_BYTECODE - _n_print_byc(pog, ip_w); -#endif - BURN(); - } - - do_bail: - u3m_bail(c3__exit); - return u3_none; - - do_copy: - top = _n_peek(off); - _n_push(mov, off, u3k(*top)); - BURN(); - - do_swap: - _n_swap(mov, off); - BURN(); - - do_toss: - _n_toss(mov, off); - BURN(); - - do_auto: // [tel bus hed] - x = _n_pep(mov, off); // [bus hed] - top = _n_swap(mov, off); // [hed bus] - *top = u3nc(*top, x); // [pro bus] - BURN(); - - do_ault: // [tel bus hed] - x = _n_pep(mov, off); // [bus hed] - _n_toss(mov, off); // [hed] - top = _n_peek(off); - *top = u3nc(*top, x); // [pro] - BURN(); - - do_snoc: // [hed tel] - x = _n_pep(mov, off); - top = _n_peek(off); - _n_push(mov, off, u3nc(x, u3k(*top))); - BURN(); - - do_snol: - x = _n_pep(mov, off); - top = _n_peek(off); - *top = u3nc(x, *top); - BURN(); - - do_head: - top = _n_peek(off); - _n_push(mov, off, u3k(u3h(_n_kale(*top)))); - BURN(); - - do_held: - top = _n_peek(off); - o = _n_kale(*top); - *top = u3k(u3h(o)); - u3z(o); - BURN(); - - do_tail: - top = _n_peek(off); - _n_push(mov, off, u3k(u3t(_n_kale(*top)))); - BURN(); - - do_tall: - top = _n_peek(off); - o = _n_kale(*top); - *top = u3k(u3t(o)); - u3z(o); - BURN(); - - do_fisk: - x = pog_u->lit_u.non[_n_resh(pog, &ip_w)]; - goto frag_in; - - do_fibk: - x = pog_u->lit_u.non[pog[ip_w++]]; - goto frag_in; - - do_fask: - x = _n_resh(pog, &ip_w); - goto frag_in; - - do_fabk: - x = pog[ip_w++]; - frag_in: - top = _n_peek(off); - _n_push(mov, off, u3k(u3x_at(x, *top))); - BURN(); - - do_fisl: - x = pog_u->lit_u.non[_n_resh(pog, &ip_w)]; - goto flag_in; - - do_fibl: - x = pog_u->lit_u.non[pog[ip_w++]]; - goto flag_in; - - do_fasl: - x = _n_resh(pog, &ip_w); - goto flag_in; - - do_fabl: - x = pog[ip_w++]; - flag_in: - top = _n_peek(off); - o = *top; - *top = u3k(u3x_at(x, o)); - u3z(o); - BURN(); - - do_lit0: - _n_push(mov, off, 0); - BURN(); - - do_lit1: - _n_push(mov, off, 1); - BURN(); - - do_litb: - _n_push(mov, off, pog[ip_w++]); - BURN(); - - do_lits: - _n_push(mov, off, _n_resh(pog, &ip_w)); - BURN(); - - do_libk: - _n_push(mov, off, u3k(pog_u->lit_u.non[pog[ip_w++]])); - BURN(); - - do_lisk: - _n_push(mov, off, u3k(pog_u->lit_u.non[_n_resh(pog, &ip_w)])); - BURN(); - - do_lil1: - x = 1; - goto lil_in; - - do_lilb: - x = pog[ip_w++]; - goto lil_in; - - do_lils: - x = _n_resh(pog, &ip_w); - goto lil_in; - - do_libl: - x = u3k(pog_u->lit_u.non[pog[ip_w++]]); - goto lil_in; - - do_lisl: - x = u3k(pog_u->lit_u.non[_n_resh(pog, &ip_w)]); - goto lil_in; - - do_lil0: - x = 0; - lil_in: - top = _n_peek(off); - u3z(*top); - *top = x; - BURN(); - - do_noct: // [fol old bus] - o = _n_pep(mov, off); // [old bus] - _n_toss(mov, off); // [bus] - goto nock_out; - - do_nolk: // [fol old bus] - o = _n_pep(mov, off); // [old bus] - _n_toss(mov, off); // [bus] - goto nock_in; - - do_nock: // [fol old bus] - o = _n_pep(mov, off); // [old bus] - _n_swap(mov, off); // [bus old] - nock_in: - x = _n_pep(mov, off); - fam = u3to(burnframe, u3R->cap_p) + off + mov; - u3R->cap_p = u3of(burnframe, fam - off); - fam->ip_w = ip_w; - fam->pog_u = pog_u; - _n_push(mov, off, x); - nock_out: - pog_u = _n_find(u3_nul, o); - pog = pog_u->byc_u.ops_y; - ip_w = 0; -#ifdef U3_CPU_DEBUG - u3R->pro.nox_d += 1; -#endif -#ifdef VERBOSE_BYTECODE - fprintf(stderr, "\r\nnock jump: %u\r\n", o); - _n_print_byc(pog, ip_w); -#endif - u3z(o); - BURN(); - - do_deep: - top = _n_peek(off); - o = *top; - *top = u3du(o); - u3z(o); - BURN(); - - do_bump: - top = _n_peek(off); - *top = u3i_vint(*top); - BURN(); - - do_sam0: - top = _n_peek(off); - if ( *top == 0 ) { - *top = c3y; - } - else { - u3z(*top); - *top = c3n; - } - BURN(); - - do_sam1: - top = _n_peek(off); - if ( *top == 1 ) { - *top = c3y; - } - else { - u3z(*top); - *top = c3n; - } - BURN(); - - do_samb: - top = _n_peek(off); - if ( *top == pog[ip_w++] ) { - *top = c3y; - } - else { - u3z(*top); - *top = c3n; - } - BURN(); - - do_sams: - top = _n_peek(off); - if ( *top == _n_resh(pog, &ip_w) ) { - *top = c3y; - } - else { - u3z(*top); - *top = c3n; - } - BURN(); - - do_sans: - x = pog_u->lit_u.non[_n_resh(pog, &ip_w)]; - goto samn_in; - do_sanb: - x = pog_u->lit_u.non[pog[ip_w++]]; - samn_in: - top = _n_peek(off); - o = *top; - *top = u3r_sing(o, x); - u3z(o); - BURN(); - - do_same: - x = _n_pep(mov, off); - _n_swap(mov, off); - goto same_in; - - do_salm: - x = _n_pep(mov, off); - _n_toss(mov, off); - goto same_in; - - same_in: - top = _n_peek(off); - o = *top; - *top = u3r_sing(x, o); - u3z(o); - u3z(x); - BURN(); - - do_samc: - top = _n_peek(off); - o = *top; - *top = u3r_sing(u3h(o), u3t(o)); - u3z(o); - BURN(); - - do_sbip: - sip_w = pog[ip_w++]; - ip_w += sip_w; - BURN(); - - do_sips: - sip_w = _n_resh(pog, &ip_w); - ip_w += sip_w; - BURN(); - - do_swip: - sip_w = _n_rewo(pog, &ip_w); - ip_w += sip_w; - BURN(); - - do_swin: - sip_w = _n_rewo(pog, &ip_w); - goto skin_in; - - do_sins: - sip_w = _n_resh(pog, &ip_w); - goto skin_in; - - do_sbin: - sip_w = pog[ip_w++]; - skin_in: - x = _n_pep(mov, off); - if ( c3n == x ) { - ip_w += sip_w; - } - else if ( c3y != x ) { - u3m_bail(c3__exit); - return u3_none; - } - BURN(); - - do_kics: - x = _n_resh(pog, &ip_w); - goto kick_in; - - do_kicb: - x = pog[ip_w++]; - kick_in: - sit_u = &(pog_u->cal_u.sit_u[x]); - top = _n_peek(off); - o = *top; - *top = _n_kick(o, sit_u); - if ( u3_none == *top ) { - _n_toss(mov, off); - - fam = u3to(burnframe, u3R->cap_p) + off + mov; - u3R->cap_p = u3of(burnframe, fam - off); - fam->ip_w = ip_w; - fam->pog_u = pog_u; - - pog_u = u3to(u3n_prog, sit_u->pog_p); - pog = pog_u->byc_u.ops_y; - ip_w = 0; -#ifdef U3_CPU_DEBUG - u3R->pro.nox_d += 1; -#endif -#ifdef VERBOSE_BYTECODE - fprintf(stderr, "\r\nhead kick jump: %u, sp: %p\r\n", u3r_at(sit_u->axe, cor), top); - _n_print_byc(pog, ip_w); -#endif - _n_push(mov, off, o); - } -#ifdef VERBOSE_BYTECODE - else { - fprintf(stderr, "head jet\r\n"); - } -#endif - BURN(); - - do_tics: - x = _n_resh(pog, &ip_w); - goto tick_in; - - do_ticb: - x = pog[ip_w++]; - tick_in: - sit_u = &(pog_u->cal_u.sit_u[x]); - top = _n_peek(off); - o = *top; - *top = _n_kick(o, sit_u); - if ( u3_none == *top ) { - *top = o; - pog_u = u3to(u3n_prog, sit_u->pog_p); - pog = pog_u->byc_u.ops_y; - ip_w = 0; -#ifdef U3_CPU_DEBUG - u3R->pro.nox_d += 1; -#endif -#ifdef VERBOSE_BYTECODE - fprintf(stderr, "\r\ntail kick jump: %u, sp: %p\r\n", u3x_at(sit_u->axe, o);, top); - _n_print_byc(pog, ip_w); -#endif - } -#ifdef VERBOSE_BYTECODE - else { - fprintf(stderr, "tail jet\r\n"); - } -#endif - BURN(); - - do_wils: // [gof bus ref] - o = _n_pep(mov,off); // [bus ref] - _n_toss(mov, off); // [ref] - top = _n_peek(off); - goto wish_in; - - do_wish: // [gof bus ref] - o = _n_pep(mov,off); // [bus ref] - top = _n_swap(mov, off); // [ref bus] - wish_in: - u3t_off(noc_o); - x = u3m_soft_esc(u3k(*top), u3k(o)); - u3t_on(noc_o); - - if ( c3n == u3du(x) ) { - u3m_bail(u3nc(1, o)); - return u3_none; - } - else if ( c3n == u3du(u3t(x)) ) { - u3t_push(u3nt(c3__hunk, *top, o)); - u3m_bail(c3__exit); - return u3_none; - } - else { - u3z(o); - u3z(*top); - *top = u3k(u3t(u3t(x))); - u3z(x); - BURN(); - } - - do_sush: - x = _n_resh(pog, &ip_w); - goto cush_in; - - do_bush: - x = pog[ip_w++]; - cush_in: - x = u3k(pog_u->lit_u.non[x]); - o = _n_pep(mov, off); - u3t_push(u3nc(x, o)); - BURN(); - - do_drop: - u3t_drop(); - BURN(); - - do_heck: - x = _n_pep(mov, off); - if ( c3y == u3ud(x) ) { - u3t_off(noc_o); - u3t_heck(x); - u3t_on(noc_o); - } - else { - u3z(x); - } - BURN(); - - do_slog: - x = _n_pep(mov, off); - if ( !(u3C.wag_w & u3o_quiet) ) { - u3t_off(noc_o); - u3t_slog(x); - u3t_on(noc_o); - } - else { - u3z(x); - } - BURN(); - - - do_sast: - x = _n_resh(pog, &ip_w); - goto fast_in; - - do_bast: - x = pog[ip_w++]; - goto fast_in; - - do_salt: - x = _n_resh(pog, &ip_w); - goto falt_in; - do_balt: - x = pog[ip_w++]; - falt_in: // [pro bus clu] - o = _n_pep(mov, off); // [bus clu] - _n_toss(mov, off); // [clu] - top = _n_peek(off); - goto fast_out; - - fast_in: // [pro bus clu] - o = _n_pep(mov, off); // [bus clu] - top = _n_swap(mov, off); // [clu bus] - fast_out: - rit_u = &(pog_u->reg_u.rit_u[x]); - u3t_off(noc_o); - u3j_rite_mine(rit_u, *top, u3k(o)); - u3t_on(noc_o); - *top = o; - BURN(); - - do_skis: - x = _n_resh(pog, &ip_w); - goto skim_in; - - do_skib: - x = pog[ip_w++]; - skim_in: - mem_u = &(pog_u->mem_u.sot_u[x]); - top = _n_peek(off); - x = u3k(*top); - goto skim_out; - - do_slis: - x = _n_resh(pog, &ip_w); - goto slim_in; - - do_slib: - x = pog[ip_w++]; - slim_in: - mem_u = &(pog_u->mem_u.sot_u[x]); - x = _n_pep(mov, off); - skim_out: - o = u3k(mem_u->key); - x = u3nc(x, o); - o = u3z_find_m(144 + c3__nock, x); - if ( u3_none == o ) { - _n_push(mov, off, x); - _n_push(mov, off, u3k(u3h(x))); - } - else { - ip_w += mem_u->sip_l; - _n_push(mov, off, o); - u3z(x); - } - BURN(); - - do_save: - x = _n_pep(mov, off); - top = _n_peek(off); - o = *top; - if ( &(u3H->rod_u) != u3R ) { - u3z_save_m(144 + c3__nock, o, x); - } - *top = x; - u3z(o); - BURN(); - - do_hilb: - x = pog[ip_w++]; - goto hilt_fore_in; - - do_hils: - x = _n_resh(pog, &ip_w); - hilt_fore_in: - x = u3k(pog_u->lit_u.non[x]); - top = _n_peek(off); // bus - x = _n_hilt_fore(x, *top, &o); - _n_push(mov, off, o); - _n_swap(mov, off); // bus - _n_push(mov, off, x); // shortcircuit if c3n - BURN(); - - do_hinb: - x = pog[ip_w++]; - goto hint_fore_in; - - do_hins: - x = _n_resh(pog, &ip_w); - hint_fore_in: // [clu bus] - x = u3k(pog_u->lit_u.non[x]); - o = _n_pep(mov, off); // [bus] - top = _n_peek(off); - x = _n_hint_fore(x, *top, &o); - _n_push(mov, off, o); // [tok bus] - _n_swap(mov, off); // [bus tok] - _n_push(mov, off, x); // [kip bus tok] - BURN(); - - do_hilk: // [pro bus tok] - x = _n_pep(mov, off); // [bus tok] - _n_swap(mov, off); // [tok bus] - o = _n_pep(mov, off); // [bus] - _n_push(mov, off, x); // [pro bus] - _n_hilt_hind(o, x); - BURN(); - - do_hill: // [pro tok] - top = _n_swap(mov, off); // [tok pro] - o = _n_pep(mov, off); // [pro] - top = _n_peek(off); - _n_hilt_hind(o, *top); - BURN(); - - do_hink: // [pro bus tok] - x = _n_pep(mov, off); // [bus tok] - _n_swap(mov, off); // [tok bus] - o = _n_pep(mov, off); // [bus] - _n_push(mov, off, x); // [pro bus] - _n_hint_hind(o, x); - BURN(); - - do_hinl: // [pro tok] - top = _n_swap(mov, off); // [tok pro] - o = _n_pep(mov, off); // [pro] - top = _n_peek(off); - _n_hint_hind(o, *top); - BURN(); - - do_kuth: - x = _n_pep(mov, off); - top = _n_swap(mov, off); - goto muth_in; - do_muth: - x = _n_pep(mov, off); - _n_toss(mov, off); - top = _n_peek(off); - muth_in: - o = *top; - *top = u3nc(x, u3k(u3t(o))); - u3z(o); - BURN(); - - do_kutt: - x = _n_pep(mov, off); - top = _n_swap(mov, off); - goto mutt_in; - do_mutt: - x = _n_pep(mov, off); - _n_toss(mov, off); - top = _n_peek(off); - mutt_in: - o = *top; - *top = u3nc(u3k(u3h(o)), x); - u3z(o); - BURN(); - - do_kusm: - x = _n_pep(mov, off); - top = _n_swap(mov, off); - goto musm_in; - do_musm: - x = _n_pep(mov, off); - _n_toss(mov, off); - top = _n_peek(off); - musm_in: - o = *top; - *top = u3nt(u3k(u3h(o)), x, u3k(u3t(u3t(o)))); - u3z(o); - BURN(); - - do_kitb: - x = pog_u->lit_u.non[pog[ip_w++]]; - goto kut_in; - - do_kits: - x = pog_u->lit_u.non[_n_resh(pog, &ip_w)]; - goto kut_in; - - do_kuts: - x = _n_resh(pog, &ip_w); - goto kut_in; - - do_kutb: - x = pog[ip_w++]; - kut_in: - o = _n_pep(mov, off); - top = _n_swap(mov, off); - goto edit_in; - - do_mitb: - x = pog_u->lit_u.non[pog[ip_w++]]; - goto mut_in; - - do_mits: - x = pog_u->lit_u.non[_n_resh(pog, &ip_w)]; - goto mut_in; - - do_muts: - x = _n_resh(pog, &ip_w); - goto mut_in; - - do_mutb: - x = pog[ip_w++]; - mut_in: - o = _n_pep(mov, off); - _n_toss(mov, off); - top = _n_peek(off); - edit_in: - *top = u3i_edit(*top, x, o); - BURN(); - } -} - -/* _n_burn_out(): execute u3n_prog with bus as subject. - */ -static u3_noun -_n_burn_out(u3_noun bus, u3n_prog* pog_u) -{ - c3_ys mov, off; - if ( c3y == u3a_is_north(u3R) ) { - mov = -1; - off = 0; - } - else { - mov = 1; - off = -1; - } - return _n_burn(pog_u, bus, mov, off); -} - -/* u3n_burn(): execute u3n_prog with bus as subject. - */ -u3_noun -u3n_burn(u3p(u3n_prog) pog_p, u3_noun bus) -{ - u3_noun pro; - u3t_on(noc_o); - pro = _n_burn_out(bus, u3to(u3n_prog, pog_p)); - u3t_off(noc_o); - return pro; -} - -/* _n_burn_on(): produce .*(bus fol) with bytecode interpreter - */ -static u3_noun -_n_burn_on(u3_noun bus, u3_noun fol) -{ - u3n_prog* pog_u = _n_find(u3_nul, fol); - - u3z(fol); - return _n_burn_out(bus, pog_u); -} - -/* u3n_nock_on(): produce .*(bus fol). Do not virtualize. -*/ -u3_noun -u3n_nock_on(u3_noun bus, u3_noun fol) -{ - u3_noun pro; - - u3t_on(noc_o); -#if 0 - pro = _n_nock_on(bus, fol); -#else - pro = _n_burn_on(bus, fol); -#endif - u3t_off(noc_o); - - return pro; -} - -/* _cn_take_prog_dat(): take references from junior u3n_prog. -*/ -static void -_cn_take_prog_dat(u3n_prog* dst_u, u3n_prog* src_u) -{ - c3_w i_w; - - for ( i_w = 0; i_w < src_u->lit_u.len_w; ++i_w ) { - dst_u->lit_u.non[i_w] = u3a_take(src_u->lit_u.non[i_w]); - } - - for ( i_w = 0; i_w < src_u->mem_u.len_w; ++i_w ) { - u3n_memo* emo_u = &(src_u->mem_u.sot_u[i_w]); - u3n_memo* ome_u = &(dst_u->mem_u.sot_u[i_w]); - ome_u->sip_l = emo_u->sip_l; - ome_u->key = u3a_take(emo_u->key); - } - - for ( i_w = 0; i_w < src_u->cal_u.len_w; ++i_w ) { - u3j_site_take(&(dst_u->cal_u.sit_u[i_w]), - &(src_u->cal_u.sit_u[i_w])); - } - - for ( i_w = 0; i_w < src_u->reg_u.len_w; ++i_w ) { - u3j_rite_take(&(dst_u->reg_u.rit_u[i_w]), - &(src_u->reg_u.rit_u[i_w])); - } -} - -/* _cn_take_prog_cb(): u3h_take_with cb for taking junior u3n_prog's. -*/ -static u3p(u3n_prog) -_cn_take_prog_cb(u3p(u3n_prog) pog_p) -{ - u3n_prog* pog_u = u3to(u3n_prog, pog_p); - u3n_prog* gop_u; - - if ( c3y == pog_u->byc_u.own_o ) { - gop_u = _n_prog_new(pog_u->byc_u.len_w, - pog_u->cal_u.len_w, - pog_u->reg_u.len_w, - pog_u->lit_u.len_w, - pog_u->mem_u.len_w); - memcpy(gop_u->byc_u.ops_y, pog_u->byc_u.ops_y, pog_u->byc_u.len_w); - } - else { - gop_u = _n_prog_old(pog_u); - } - - _cn_take_prog_dat(gop_u, pog_u); - // _n_prog_take_dat(gop_u, pog_u, c3n); - - return u3of(u3n_prog, gop_u); -} - -/* u3n_take(): copy junior bytecode state. -*/ -u3p(u3h_root) -u3n_take(u3p(u3h_root) har_p) -{ - return u3h_take_with(har_p, _cn_take_prog_cb); -} - -/* _cn_merge_prog_dat(): copy references from src_u u3n_prog to dst_u. -*/ -static void -_cn_merge_prog_dat(u3n_prog* dst_u, u3n_prog* src_u) -{ - c3_w i_w; - - for ( i_w = 0; i_w < src_u->lit_u.len_w; ++i_w ) { - u3z(dst_u->lit_u.non[i_w]); - dst_u->lit_u.non[i_w] = src_u->lit_u.non[i_w]; - } - - for ( i_w = 0; i_w < src_u->mem_u.len_w; ++i_w ) { - u3n_memo* emo_u = &(dst_u->mem_u.sot_u[i_w]); - u3n_memo* ome_u = &(src_u->mem_u.sot_u[i_w]); - u3z(emo_u->key); - emo_u->sip_l = ome_u->sip_l; - emo_u->key = ome_u->key; - } - - for ( i_w = 0; i_w < src_u->cal_u.len_w; ++i_w ) { - u3j_site_merge(&(dst_u->cal_u.sit_u[i_w]), - &(src_u->cal_u.sit_u[i_w])); - } - - for ( i_w = 0; i_w < src_u->reg_u.len_w; ++i_w ) { - u3j_rite_merge(&(dst_u->reg_u.rit_u[i_w]), - &(src_u->reg_u.rit_u[i_w])); - } -} - -/* _cn_merge_prog_cb(): u3h_walk_with cb for integrating taken u3n_prog's. -*/ -static void -_cn_merge_prog_cb(u3_noun kev, void* wit) -{ - u3p(u3h_root) har_p = *(u3p(u3h_root)*)wit; - u3n_prog* pog_u; - u3_weak got; - u3_noun key; - u3p(u3n_prog) pog_p; - u3x_cell(kev, &key, &pog_p); - - pog_u = u3to(u3n_prog, pog_p); - got = u3h_git(har_p, key); - - if ( u3_none != got ) { - u3n_prog* sep_u = u3to(u3n_prog, got); - _cn_merge_prog_dat(sep_u, pog_u); - u3a_free(pog_u); - pog_u = sep_u; - } - - u3h_put(har_p, key, u3of(u3n_prog, pog_u)); -} - -/* u3n_reap(): promote bytecode state. -*/ -void -u3n_reap(u3p(u3h_root) har_p) -{ - u3h_walk_with(har_p, _cn_merge_prog_cb, &u3R->byc.har_p); - // NB *not* u3n_free, _cn_merge_prog_cb() transfers u3n_prog's - u3h_free(har_p); -} - -/* _n_ream(): ream program call sites -*/ -void -_n_ream(u3_noun kev) -{ - c3_w i_w; - u3n_prog* pog_u = u3to(u3n_prog, u3t(kev)); - - // fix up pointers for loom portability - pog_u->byc_u.ops_y = (c3_y*) _n_prog_dat(pog_u); - pog_u->lit_u.non = (u3_noun*) (pog_u->byc_u.ops_y + pog_u->byc_u.len_w); - pog_u->mem_u.sot_u = (u3n_memo*) (pog_u->lit_u.non + pog_u->lit_u.len_w); - pog_u->cal_u.sit_u = (u3j_site*) (pog_u->mem_u.sot_u + pog_u->mem_u.len_w); - pog_u->reg_u.rit_u = (u3j_rite*) (pog_u->cal_u.sit_u + pog_u->cal_u.len_w); - - for ( i_w = 0; i_w < pog_u->cal_u.len_w; ++i_w ) { - u3j_site_ream(&(pog_u->cal_u.sit_u[i_w])); - } -} - -/* u3n_ream(): refresh after restoring from checkpoint. -*/ -void -u3n_ream() -{ - c3_assert(u3R == &(u3H->rod_u)); - u3h_walk(u3R->byc.har_p, _n_ream); -} - -/* _n_prog_mark(): mark program for gc. -*/ -static c3_w -_n_prog_mark(u3n_prog* pog_u) -{ - c3_w i_w, tot_w = u3a_mark_mptr(pog_u); - - for ( i_w = 0; i_w < pog_u->lit_u.len_w; ++i_w ) { - tot_w += u3a_mark_noun(pog_u->lit_u.non[i_w]); - } - - for ( i_w = 0; i_w < pog_u->mem_u.len_w; ++i_w ) { - tot_w += u3a_mark_noun(pog_u->mem_u.sot_u[i_w].key); - } - - for ( i_w = 0; i_w < pog_u->cal_u.len_w; ++i_w ) { - tot_w += u3j_site_mark(&(pog_u->cal_u.sit_u[i_w])); - } - - for ( i_w = 0; i_w < pog_u->reg_u.len_w; ++i_w ) { - tot_w += u3j_rite_mark(&(pog_u->reg_u.rit_u[i_w])); - } - - return tot_w; -} - -/* _n_bam(): u3h_walk_with helper for u3n_mark - */ -static void -_n_bam(u3_noun kev, void* dat) -{ - c3_w* bam_w = dat; - u3n_prog* pog = u3to(u3n_prog, u3t(kev)); - *bam_w += _n_prog_mark(pog); -} - -/* u3n_mark(): mark the bytecode cache for gc. - */ -c3_w -u3n_mark(FILE* fil_u) -{ - c3_w bam_w = 0, har_w = 0; - u3p(u3h_root) har_p = u3R->byc.har_p; - u3h_walk_with(har_p, _n_bam, &bam_w); - - bam_w = u3a_maid(fil_u, " bytecode programs", bam_w); - har_w = u3a_maid(fil_u, " bytecode cache", u3h_mark(har_p)); - return u3a_maid(fil_u, "total nock stuff", bam_w + har_w); -} - -/* u3n_reclaim(): clear ad-hoc persistent caches to reclaim memory. -*/ -void -u3n_reclaim(void) -{ - // clear the bytecode cache - // - // We can't just u3h_free() -- the value is a post to a u3n_prog. - // Note that the hank cache *must* also be freed (in u3j_reclaim()) - // - u3n_free(); - u3R->byc.har_p = u3h_new(); -} - -/* u3n_rewrite_compact(): rewrite the bytecode cache for compaction. - * - * NB: u3R->byc.har_p *must* be cleared (currently via u3n_reclaim above), - * since it contains things that look like nouns but aren't. - * Specifically, it contains "cells" where the tail is a - * pointer to a u3a_malloc'ed block that contains loom pointers. - * - * You should be able to walk this with u3h_walk and rewrite the - * pointers, but you need to be careful to handle that u3a_malloc - * pointers can't be turned into a box by stepping back two words. You - * must step back one word to get the padding, step then step back that - * many more words (plus one?). - */ -void -u3n_rewrite_compact() -{ - u3h_rewrite(u3R->byc.har_p); - u3R->byc.har_p = u3a_rewritten(u3R->byc.har_p); -} - - -/* _n_feb(): u3h_walk helper for u3n_free - */ -static void -_n_feb(u3_noun kev) -{ - _cn_prog_free(u3to(u3n_prog, u3t(kev))); -} - -/* u3n_free(): free bytecode cache - */ -void -u3n_free() -{ - u3p(u3h_root) har_p = u3R->byc.har_p; - u3h_walk(har_p, _n_feb); - u3h_free(har_p); -} - -/* u3n_kick_on(): fire `gat` without changing the sample. -*/ -u3_noun -u3n_kick_on(u3_noun gat) -{ - return u3j_kink(gat, 2); -} - -c3_w exc_w; - -/* u3n_slam_on(): produce (gat sam). -*/ -u3_noun -u3n_slam_on(u3_noun gat, u3_noun sam) -{ - u3_noun cor = u3nc(u3k(u3h(gat)), u3nc(sam, u3k(u3t(u3t(gat))))); - -#if 0 - if ( &u3H->rod_u == u3R ) { - if ( exc_w == 1 ) { - c3_assert(0); - } - exc_w++; - } -#endif - u3z(gat); - return u3n_kick_on(cor); -} - -/* u3n_nock_et(): produce .*(bus fol), as ++toon, in namespace. -*/ -u3_noun -u3n_nock_et(u3_noun gul, u3_noun bus, u3_noun fol) -{ - return u3m_soft_run(gul, u3n_nock_on, bus, fol); -} - -/* u3n_slam_et(): produce (gat sam), as ++toon, in namespace. -*/ -u3_noun -u3n_slam_et(u3_noun gul, u3_noun gat, u3_noun sam) -{ - return u3m_soft_run(gul, u3n_slam_on, gat, sam); -} - -/* u3n_nock_an(): as slam_in(), but with empty fly. -*/ -u3_noun -u3n_nock_an(u3_noun bus, u3_noun fol) -{ - u3_noun gul = u3nt(u3nt(1, 0, 0), 0, 0); // |=(a/{* *} ~) - - return u3n_nock_et(gul, bus, fol); -} diff --git a/pkg/urbit/noun/retrieve.c b/pkg/urbit/noun/retrieve.c deleted file mode 100644 index 06a9fb2fe..000000000 --- a/pkg/urbit/noun/retrieve.c +++ /dev/null @@ -1,1918 +0,0 @@ -/* g/r.c -** -*/ -#include "all.h" -#include - -/* _frag_word(): fast fragment/branch prediction for top word. -*/ -static u3_weak -_frag_word(c3_w a_w, u3_noun b) -{ - c3_assert(0 != a_w); - - { - c3_w dep_w = u3x_dep(a_w); - - while ( dep_w ) { - if ( c3n == u3a_is_cell(b) ) { - return u3_none; - } - else { - u3a_cell* b_u = u3a_to_ptr(b); - - b = *(((u3_noun*)&(b_u->hed)) + (1 & (a_w >> (dep_w - 1)))); - dep_w--; - } - } - return b; - } -} - -/* _frag_deep(): fast fragment/branch for deep words. -*/ -static u3_weak -_frag_deep(c3_w a_w, u3_noun b) -{ - c3_w dep_w = 32; - - while ( dep_w ) { - if ( c3n == u3a_is_cell(b) ) { - return u3_none; - } - else { - u3a_cell* b_u = u3a_to_ptr(b); - - b = *(((u3_noun*)&(b_u->hed)) + (1 & (a_w >> (dep_w - 1)))); - dep_w--; - } - } - return b; -} - -/* u3r_at(): -** -** Return fragment (a) of (b), or u3_none if not applicable. -*/ -u3_weak -u3r_at(u3_atom a, u3_noun b) -{ - c3_assert(u3_none != a); - c3_assert(u3_none != b); - - u3t_on(far_o); - - if ( 0 == a ) { - u3t_off(far_o); - return u3_none; - } - - if ( _(u3a_is_cat(a)) ) { - u3t_off(far_o); - return _frag_word(a, b); - } - else { - if ( !_(u3a_is_pug(a)) ) { - u3t_off(far_o); - return u3_none; - } - else { - u3a_atom* a_u = u3a_to_ptr(a); - c3_w len_w = a_u->len_w; - - b = _frag_word(a_u->buf_w[len_w - 1], b); - len_w -= 1; - - if ( u3_none == b ) { - u3t_off(far_o); - return b; - } - - while ( len_w ) { - b = _frag_deep(a_u->buf_w[len_w - 1], b); - - if ( u3_none == b ) { - u3t_off(far_o); - - return b; - } else { - len_w--; - } - } - u3t_off(far_o); - - return b; - } - } -} - -/* u3r_mean(): -** -** Attempt to deconstruct `a` by axis, noun pairs; 0 terminates. -** Axes must be sorted in tree order. -*/ - struct _mean_pair { - c3_w axe_w; - u3_noun* som; - }; - - static c3_w - _mean_cut(c3_w len_w, - struct _mean_pair* prs_m) - { - c3_w i_w, cut_t, cut_w; - - cut_t = 0; - cut_w = 0; - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_w axe_w = prs_m[i_w].axe_w; - - if ( (cut_t == 0) && (3 == u3x_cap(axe_w)) ) { - cut_t = 1; - cut_w = i_w; - } - prs_m[i_w].axe_w = u3x_mas(axe_w); - } - return cut_t ? cut_w : i_w; - } - - static c3_o - _mean_extract(u3_noun som, - c3_w len_w, - struct _mean_pair* prs_m) - { - if ( len_w == 0 ) { - return c3y; - } - else if ( (len_w == 1) && (1 == prs_m[0].axe_w) ) { - *prs_m->som = som; - return c3y; - } - else { - if ( c3n == u3a_is_cell(som) ) { - return c3n; - } else { - c3_w cut_w = _mean_cut(len_w, prs_m); - - return c3a - (_mean_extract(u3a_h(som), cut_w, prs_m), - _mean_extract(u3a_t(som), (len_w - cut_w), (prs_m + cut_w))); - } - } - } - -c3_o -u3r_vmean(u3_noun som, va_list ap) -{ - va_list aq; - c3_w len_w; - struct _mean_pair* prs_m; - - c3_assert(u3_none != som); - - // traverse copy of va_list for alloca - // - va_copy(aq, ap); - len_w = 0; - - while ( 1 ) { - if ( 0 == va_arg(aq, c3_w) ) { - break; - } - va_arg(aq, u3_noun*); - len_w++; - } - - va_end(aq); - - c3_assert( 0 != len_w ); - prs_m = alloca(len_w * sizeof(struct _mean_pair)); - - // traverse va_list and extract args - // - { - c3_w i_w; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - prs_m[i_w].axe_w = va_arg(ap, c3_w); - prs_m[i_w].som = va_arg(ap, u3_noun*); - } - - va_end(ap); - } - - // extract axis from som - // - return _mean_extract(som, len_w, prs_m); -} - -c3_o -u3r_mean(u3_noun som, ...) -{ - c3_o ret_o; - va_list ap; - - va_start(ap, som); - ret_o = u3r_vmean(som, ap); - va_end(ap); - - return ret_o; -} - -// stack frame for tracking noun comparison and unification -// -// we always compare arbitrary nouns in a none-frame. -// when we compare two cells, we change the none-frame to a head-frame -// and push a new none-frame for their heads. if the heads are equal, -// we get the cells from the head-frame and unify their head pointers. -// then, we convert the head-frame to a tail-frame and repeat with -// the tails, mutatis mutandis. -// -// in Hoon, this structure would be: -// -// $% [%none a=* b=*] -// [%head a=^ b=^] -// [%tail a=^ b=^] -// == -// -#define SING_NONE 0 -#define SING_HEAD 1 -#define SING_TAIL 2 - -typedef struct { - c3_y sat_y; - u3_noun a; - u3_noun b; -} eqframe; - -/* _cr_sing_push(): push a new stack frame, initialized as SING_NONE. -*/ -static inline eqframe* -_cr_sing_push(u3a_pile* pil_u, u3_noun a, u3_noun b) -{ - eqframe* fam_u = u3a_push(pil_u); - fam_u->sat_y = SING_NONE; - fam_u->a = a; - fam_u->b = b; - return fam_u; -} - -/* _cr_sing_mug(): short-circuit comparison if mugs are present and not equal. -*/ -static inline c3_o -_cr_sing_mug(u3a_noun* a_u, u3a_noun* b_u) -{ - // XX add debug assertions that both mugs are 31-bit - // (ie, not u3a_take() relocation references) - // - if ( a_u->mug_w && b_u->mug_w && (a_u->mug_w != b_u->mug_w) ) { - return c3n; - } - - return c3y; -} - -/* _cr_sing_atom(): check if atom [a] is indirect and equal to noun [b] -*/ -static inline c3_o -_cr_sing_atom(u3_atom a, u3_noun b) -{ - // [a] is an atom, not pointer-equal to noun [b]. - // if they're not both indirect atoms, they can't be equal. - // - if ( (c3n == u3a_is_pug(a)) - || (c3n == u3a_is_pug(b)) ) - { - return c3n; - } - else { - u3a_atom* a_u = u3a_to_ptr(a); - u3a_atom* b_u = u3a_to_ptr(b); - - // [a] and [b] are not equal if their mugs are present and not equal. - // - if ( c3n == _cr_sing_mug((u3a_noun*)a_u, (u3a_noun*)b_u) ) { - return c3n; - } - else { - c3_w a_w = a_u->len_w; - c3_w b_w = b_u->len_w; - - // [a] and [b] are not equal if their lengths are not equal - // - if ( a_w != b_w ) { - return c3n; - } - else { - c3_w i_w; - - // XX memcmp - // - for ( i_w = 0; i_w < a_w; i_w++ ) { - if ( a_u->buf_w[i_w] != b_u->buf_w[i_w] ) { - return c3n; - } - } - } - } - } - - return c3y; -} - -/* _cr_sing_cape_test(): check for previous comparison of [a] and [b]. -*/ -static inline c3_o -_cr_sing_cape_test(u3p(u3h_root) har_p, u3_noun a, u3_noun b) -{ - u3_noun key = u3nc(u3a_to_off(a), u3a_to_off(b)); - u3_noun val; - - u3t_off(euq_o); - val = u3h_git(har_p, key); - u3t_on(euq_o); - - u3z(key); - return ( u3_none != val ) ? c3y : c3n; -} - -/* _cr_sing_cape_keep(): store [a] and [b] to short-circuit subsequent tests. -** NB: [a] and [b] (which MUST be equal nouns) -** are cons'd as offsets (direct atoms) to avoid refcount churn. -*/ -static inline void -_cr_sing_cape_keep(u3p(u3h_root) har_p, u3_noun a, u3_noun b) -{ - // only store if [a] and [b] are copies of each other - // - if ( a != b ) { - u3_noun key = u3nc(u3a_to_off(a), u3a_to_off(b)); - u3t_off(euq_o); - u3h_put(har_p, key, c3y); - u3t_on(euq_o); - u3z(key); - } -} - -/* _cr_sing_cape(): unifying equality with comparison deduplication - * (tightly coupled to _cr_sing) - */ -static c3_o -_cr_sing_cape(u3a_pile* pil_u, u3p(u3h_root) har_p) -{ - eqframe* fam_u = u3a_peek(pil_u); - u3_noun a, b, key; - u3_weak got; - u3a_cell* a_u; - u3a_cell* b_u; - - // loop while arguments remain on the stack - // - do { - a = fam_u->a; - b = fam_u->b; - - switch ( fam_u->sat_y ) { - - // [a] and [b] are arbitrary nouns - // - case SING_NONE: { - if ( a == b ) { - break; - } - else if ( c3y == u3a_is_atom(a) ) { - if ( c3n == _cr_sing_atom(a, b) ) { - return c3n; - } - else { - break; - } - } - else if ( c3y == u3a_is_atom(b) ) { - return c3n; - } - // [a] and [b] are cells - // - else { - a_u = u3a_to_ptr(a); - b_u = u3a_to_ptr(b); - - // short-circuiting mug check - // - if ( c3n == _cr_sing_mug((u3a_noun*)a_u, (u3a_noun*)b_u) ) { - return c3n; - } - // short-circuiting re-comparison check - // - else if ( c3y == _cr_sing_cape_test(har_p, a, b) ) { - fam_u = u3a_pop(pil_u); - continue; - } - // upgrade none-frame to head-frame, check heads - // - else { - fam_u->sat_y = SING_HEAD; - fam_u = _cr_sing_push(pil_u, a_u->hed, b_u->hed); - continue; - } - } - } break; - - // cells [a] and [b] have equal heads - // - case SING_HEAD: { - a_u = u3a_to_ptr(a); - b_u = u3a_to_ptr(b); - u3a_wed(&(a_u->hed), &(b_u->hed)); - - // upgrade head-frame to tail-frame, check tails - // - fam_u->sat_y = SING_TAIL; - fam_u = _cr_sing_push(pil_u, a_u->tel, b_u->tel); - continue; - } - - // cells [a] and [b] are equal - // - case SING_TAIL: { - a_u = u3a_to_ptr(a); - b_u = u3a_to_ptr(b); - u3a_wed(&(a_u->tel), &(b_u->tel)); - } break; - - default: { - c3_assert(0); - } break; - } - - // track equal pairs to short-circuit possible (re-)comparison - // - _cr_sing_cape_keep(har_p, a, b); - - fam_u = u3a_pop(pil_u); - } - while ( c3n == u3a_pile_done(pil_u) ); - - return c3y; -} - -/* _cr_sing(): unifying equality. -*/ -static c3_o -_cr_sing(u3_noun a, u3_noun b) -{ - c3_s ovr_s = 0; - u3a_cell* a_u; - u3a_cell* b_u; - eqframe* fam_u; - u3a_pile pil_u; - - // initialize stack control, push arguments onto the stack (none-frame) - // - u3a_pile_prep(&pil_u, sizeof(eqframe)); - fam_u = _cr_sing_push(&pil_u, a, b); - - // loop while arguments are on the stack - // - while ( c3n == u3a_pile_done(&pil_u) ) { - a = fam_u->a; - b = fam_u->b; - - switch ( fam_u->sat_y ) { - - // [a] and [b] are arbitrary nouns - // - case SING_NONE: { - if ( a == b ) { - break; - } - else if ( c3y == u3a_is_atom(a) ) { - if ( c3n == _cr_sing_atom(a, b) ) { - u3R->cap_p = pil_u.top_p; - return c3n; - } - else { - break; - } - } - else if ( c3y == u3a_is_atom(b) ) { - u3R->cap_p = pil_u.top_p; - return c3n; - } - // [a] and [b] are cells - // - else { - a_u = u3a_to_ptr(a); - b_u = u3a_to_ptr(b); - - // short-circuiting mug check - // - if ( c3n == _cr_sing_mug((u3a_noun*)a_u, (u3a_noun*)b_u) ) { - u3R->cap_p = pil_u.top_p; - return c3n; - } - // upgrade none-frame to head-frame, check heads - // - else { - fam_u->sat_y = SING_HEAD; - fam_u = _cr_sing_push(&pil_u, a_u->hed, b_u->hed); - continue; - } - } - } break; - - // cells [a] and [b] have equal heads - // - case SING_HEAD: { - a_u = u3a_to_ptr(a); - b_u = u3a_to_ptr(b); - u3a_wed(&(a_u->hed), &(b_u->hed)); - - // upgrade head-frame to tail-frame, check tails - // - fam_u->sat_y = SING_TAIL; - fam_u = _cr_sing_push(&pil_u, a_u->tel, b_u->tel); - continue; - } - - // cells [a] and [b] are equal - // - case SING_TAIL: { - a_u = u3a_to_ptr(a); - b_u = u3a_to_ptr(b); - u3a_wed(&(a_u->tel), &(b_u->tel)); - } break; - - default: { - c3_assert(0); - } break; - } - - // [ovr_s] counts comparisons, if it overflows, we've likely hit - // a pathological case (highly duplicated tree), so we de-duplicate - // subsequent comparisons by maintaining a set of equal pairs. - // - if ( 0 == ++ovr_s ) { - u3p(u3h_root) har_p = u3h_new(); - c3_o ret_o = _cr_sing_cape(&pil_u, har_p); - u3h_free(har_p); - u3R->cap_p = pil_u.top_p; - return ret_o; - } - - fam_u = u3a_pop(&pil_u); - } - - return c3y; -} - -/* u3r_sing(): Yes iff [a] and [b] are the same noun. -*/ -c3_o -u3r_sing(u3_noun a, u3_noun b) -{ - c3_o ret_o; - u3t_on(euq_o); - ret_o = _cr_sing(a, b); - u3t_off(euq_o); - return ret_o; -} - -c3_o -u3r_fing(u3_noun a, - u3_noun b) -{ - return (a == b) ? c3y : c3n; -} - -/* u3r_sing_cell(): -** -** Yes iff `[p q]` and `b` are the same noun. -*/ -c3_o -u3r_sing_cell(u3_noun p, - u3_noun q, - u3_noun b) -{ - return c3a(_(u3a_is_cell(b)), - c3a(u3r_sing(p, u3a_h(b)), - u3r_sing(q, u3a_t(b)))); -} -c3_o -u3r_fing_cell(u3_noun p, - u3_noun q, - u3_noun b) -{ - return c3a(_(u3a_is_cell(b)), - c3a(u3r_fing(p, u3a_h(b)), - u3r_fing(q, u3a_t(b)))); -} - -/* u3r_sing_mixt(): -** -** Yes iff `[p q]` and `b` are the same noun. -*/ -c3_o -u3r_sing_mixt(const c3_c* p_c, - u3_noun q, - u3_noun b) -{ - return c3a(_(u3a_is_cell(b)), - c3a(u3r_sing_c(p_c, u3a_h(b)), - u3r_sing(q, u3a_t(b)))); -} -c3_o -u3r_fing_mixt(const c3_c* p_c, - u3_noun q, - u3_noun b) -{ - return c3a(_(u3a_is_cell(b)), - c3a(u3r_sing_c(p_c, u3a_h(b)), - u3r_fing(q, u3a_t(b)))); -} - -/* u3r_sing_trel(): -** -** Yes iff `[p q r]` and `b` are the same noun. -*/ -c3_o -u3r_sing_trel(u3_noun p, - u3_noun q, - u3_noun r, - u3_noun b) -{ - return c3a(_(u3a_is_cell(b)), - c3a(u3r_sing(p, u3a_h(b)), - u3r_sing_cell(q, r, u3a_t(b)))); -} -c3_o -u3r_fing_trel(u3_noun p, - u3_noun q, - u3_noun r, - u3_noun b) -{ - return c3a(_(u3a_is_cell(b)), - c3a(u3r_fing(p, u3a_h(b)), - u3r_fing_cell(q, r, u3a_t(b)))); -} - -/* u3r_sing_qual(): -** -** Yes iff `[p q r]` and `b` are the same noun. -*/ -c3_o -u3r_sing_qual(u3_noun p, - u3_noun q, - u3_noun r, - u3_noun s, - u3_noun b) -{ - return c3a(_(u3a_is_cell(b)), - c3a(u3r_sing(p, u3a_h(b)), - u3r_sing_trel(q, r, s, u3a_t(b)))); -} -c3_o -u3r_fing_qual(u3_noun p, - u3_noun q, - u3_noun r, - u3_noun s, - u3_noun b) -{ - return c3a(_(u3a_is_cell(b)), - c3a(u3r_fing(p, u3a_h(b)), - u3r_fing_trel(q, r, s, u3a_t(b)))); -} - -/* u3r_nord(): -** -** Return 0, 1 or 2 if `a` is below, equal to, or above `b`. -*/ -u3_atom -u3r_nord(u3_noun a, - u3_noun b) -{ - c3_assert(u3_none != a); - c3_assert(u3_none != b); - - if ( a == b ) { - return 1; - } - else { - if ( _(u3a_is_atom(a)) ) { - if ( !_(u3a_is_atom(b)) ) { - return 0; - } else { - if ( _(u3a_is_cat(a)) ) { - if ( _(u3a_is_cat(b)) ) { - return (a < b) ? 0 : 2; - } - else return 0; - } - else if ( _(u3a_is_cat(b)) ) { - return 2; - } - else { - u3a_atom* a_u = u3a_to_ptr(a); - u3a_atom* b_u = u3a_to_ptr(b); - - c3_w w_rez = a_u->len_w; - c3_w w_mox = b_u->len_w; - - if ( w_rez != w_mox ) { - return (w_rez < w_mox) ? 0 : 2; - } - else { - c3_w i_w; - - for ( i_w = 0; i_w < w_rez; i_w++ ) { - c3_w ai_w = a_u->buf_w[i_w]; - c3_w bi_w = b_u->buf_w[i_w]; - - if ( ai_w != bi_w ) { - return (ai_w < bi_w) ? 0 : 2; - } - } - return 1; - } - } - } - } else { - if ( _(u3a_is_atom(b)) ) { - return 2; - } else { - u3_atom c = u3r_nord(u3a_h(a), u3a_h(b)); - - if ( 1 == c ) { - return u3r_nord(u3a_t(a), u3a_t(b)); - } else { - return c; - } - } - } - } -} - -/* u3r_sing_c(): cord/C-string value equivalence. -*/ -c3_o -u3r_sing_c(const c3_c* a_c, - u3_noun b) -{ - c3_assert(u3_none != b); - - if ( !_(u3a_is_atom(b)) ) { - return c3n; - } - else { - c3_w w_sof = strlen(a_c); - c3_w i_w; - - if ( w_sof != u3r_met(3, b) ) { - return c3n; - } - for ( i_w = 0; i_w < w_sof; i_w++ ) { - if ( u3r_byte(i_w, b) != a_c[i_w] ) { - return c3n; - } - } - return c3y; - } -} - -/* u3r_bush(): -** -** Factor [a] as a bush [b.[p q] c]. -*/ -c3_o -u3r_bush(u3_noun a, - u3_noun* b, - u3_noun* c) -{ - c3_assert(u3_none != a); - - if ( _(u3a_is_atom(a)) ) { - return c3n; - } - else { - *b = u3a_h(a); - - if ( _(u3a_is_atom(*b)) ) { - return c3n; - } else { - *c = u3a_t(a); - return c3y; - } - } -} - -/* u3r_bite(): retrieve/default $bloq and $step from $bite. -*/ -c3_o -u3r_bite(u3_noun bite, u3_atom* bloq, u3_atom *step) -{ - u3_noun hed, tal; - - if ( c3n == u3r_cell(bite, &hed, &tal) ) { - *bloq = bite; - *step = 1; - return c3y; - } - else if ( (c3n == u3a_is_atom(hed)) - || (c3n == u3a_is_atom(tal)) ) - { - return c3n; - } - else { - *bloq = hed; - *step = tal; - return c3y; - } -} - -/* u3r_cell(): -** -** Factor (a) as a cell (b c). -*/ -c3_o -u3r_cell(u3_noun a, - u3_noun* b, - u3_noun* c) -{ - c3_assert(u3_none != a); - - if ( _(u3a_is_atom(a)) ) { - return c3n; - } - else { - if ( b ) *b = u3a_h(a); - if ( c ) *c = u3a_t(a); - return c3y; - } -} - -/* u3r_p(): -** -** & [0] if [a] is of the form [b *c]. -*/ -c3_o -u3r_p(u3_noun a, - u3_noun b, - u3_noun* c) -{ - u3_noun feg, nux; - - if ( (c3y == u3r_cell(a, &feg, &nux)) && - (c3y == u3r_sing(feg, b)) ) - { - if ( c ) *c = nux; - return c3y; - } - else return c3n; -} - -/* u3r_pq(): -** -** & [0] if [a] is of the form [b *c d]. -*/ -c3_o -u3r_pq(u3_noun a, - u3_noun b, - u3_noun* c, - u3_noun* d) -{ - u3_noun nux; - - if ( (c3y == u3r_p(a, b, &nux)) && - (c3y == u3r_cell(nux, c, d)) ) - { - return c3y; - } - else return c3n; -} - -/* u3r_pqr(): -** -** & [0] if [a] is of the form [b *c *d *e]. -*/ -c3_o -u3r_pqr(u3_noun a, - u3_noun b, - u3_noun* c, - u3_noun* d, - u3_noun* e) -{ - u3_noun nux; - - if ( (c3y == u3r_p(a, b, &nux)) && - (c3y == u3r_trel(nux, c, d, e)) ) - { - return c3y; - } - else return c3n; -} - -/* u3r_pqrs(): -** -** & [0] if [a] is of the form [b *c *d *e *f]. -*/ -c3_o -u3r_pqrs(u3_noun a, - u3_noun b, - u3_noun* c, - u3_noun* d, - u3_noun* e, - u3_noun* f) -{ - u3_noun nux; - - if ( (c3y == u3r_p(a, b, &nux)) && - (c3y == u3r_qual(nux, c, d, e, f)) ) - { - return c3y; - } - else return c3n; -} - -/* u3r_trel(): -** -** Factor (a) as a trel (b c d). -*/ -c3_o -u3r_trel(u3_noun a, - u3_noun *b, - u3_noun *c, - u3_noun *d) -{ - u3_noun guf; - - if ( (c3y == u3r_cell(a, b, &guf)) && - (c3y == u3r_cell(guf, c, d)) ) { - return c3y; - } - else { - return c3n; - } -} - -/* u3r_qual(): -** -** Factor (a) as a qual (b c d e). -*/ -c3_o -u3r_qual(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d, - u3_noun* e) -{ - u3_noun guf; - - if ( (c3y == u3r_cell(a, b, &guf)) && - (c3y == u3r_trel(guf, c, d, e)) ) { - return c3y; - } - else return c3n; -} - -/* u3r_quil(): -** -** Factor (a) as a quil (b c d e f). -*/ -c3_o -u3r_quil(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d, - u3_noun* e, - u3_noun* f) -{ - u3_noun guf; - - if ( (c3y == u3r_cell(a, b, &guf)) && - (c3y == u3r_qual(guf, c, d, e, f)) ) { - return c3y; - } - else return c3n; -} - -/* u3r_hext(): -** -** Factor (a) as a hext (b c d e f g) -*/ -c3_o -u3r_hext(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d, - u3_noun* e, - u3_noun* f, - u3_noun* g) -{ - u3_noun guf; - - if ( (c3y == u3r_cell(a, b, &guf)) && - (c3y == u3r_quil(guf, c, d, e, f, g)) ) { - return c3y; - } - else return c3n; -} - -/* u3r_met(): -** -** Return the size of (b) in bits, rounded up to -** (1 << a_y). -** -** For example, (a_y == 3) returns the size in bytes. -** NB: (a_y) must be < 37. -*/ -c3_w -u3r_met(c3_y a_y, - u3_atom b) -{ - c3_assert(u3_none != b); - c3_assert(_(u3a_is_atom(b))); - - if ( b == 0 ) { - return 0; - } - else { - /* gal_w: number of words besides (daz_w) in (b). - ** daz_w: top word in (b). - */ - c3_w gal_w; - c3_w daz_w; - - if ( _(u3a_is_cat(b)) ) { - gal_w = 0; - daz_w = b; - } - else { - u3a_atom* b_u = u3a_to_ptr(b); - - gal_w = (b_u->len_w) - 1; - daz_w = b_u->buf_w[gal_w]; - } - - switch ( a_y ) { - case 0: - case 1: - case 2: { - /* col_w: number of bits in (daz_w) - ** bif_w: number of bits in (b) - */ - c3_w bif_w, col_w; - - if ( gal_w > ((UINT32_MAX - 35) >> 5) ) { - return u3m_bail(c3__fail); - } - - col_w = c3_bits_word(daz_w); - bif_w = col_w + (gal_w << 5); - - return (bif_w + ((1 << a_y) - 1)) >> a_y; - } - - STATIC_ASSERT((UINT32_MAX > ((c3_d)u3a_maximum << 2)), - "met overflow"); - - case 3: return (gal_w << 2) + ((c3_bits_word(daz_w) + 7) >> 3); - - case 4: return (gal_w << 1) + ((c3_bits_word(daz_w) + 15) >> 4); - - default: { - c3_y gow_y = (a_y - 5); - - return ((gal_w + 1) + ((1 << gow_y) - 1)) >> gow_y; - } - } - } -} - -/* u3r_bit(): -** -** Return bit (a_w) of (b). -*/ -c3_b -u3r_bit(c3_w a_w, - u3_atom b) -{ - c3_assert(u3_none != b); - c3_assert(_(u3a_is_atom(b))); - - if ( _(u3a_is_cat(b)) ) { - if ( a_w >= 31 ) { - return 0; - } - else return (1 & (b >> a_w)); - } - else { - u3a_atom* b_u = u3a_to_ptr(b); - c3_y vut_y = (a_w & 31); - c3_w pix_w = (a_w >> 5); - - if ( pix_w >= b_u->len_w ) { - return 0; - } - else { - c3_w nys_w = b_u->buf_w[pix_w]; - - return (1 & (nys_w >> vut_y)); - } - } -} - -/* u3r_byte(): -** -** Return byte (a_w) of (b). -*/ -c3_y -u3r_byte(c3_w a_w, - u3_atom b) -{ - c3_assert(u3_none != b); - c3_assert(_(u3a_is_atom(b))); - - if ( _(u3a_is_cat(b)) ) { - if ( a_w > 3 ) { - return 0; - } - else return (255 & (b >> (a_w << 3))); - } - else { - u3a_atom* b_u = u3a_to_ptr(b); - c3_y vut_y = (a_w & 3); - c3_w pix_w = (a_w >> 2); - - if ( pix_w >= b_u->len_w ) { - return 0; - } - else { - c3_w nys_w = b_u->buf_w[pix_w]; - - return (255 & (nys_w >> (vut_y << 3))); - } - } -} - -/* u3r_bytes(): -** -** Copy bytes (a_w) through (a_w + b_w - 1) from (d) to (c). -*/ -void -u3r_bytes(c3_w a_w, - c3_w b_w, - c3_y* c_y, - u3_atom d) -{ - c3_assert(u3_none != d); - c3_assert(_(u3a_is_atom(d))); - - if ( _(u3a_is_cat(d)) ) { - c3_w e_w = d >> (c3_min(a_w, 4) << 3); - c3_w m_w = c3_min(b_w, 4); - memcpy(c_y, (c3_y*)&e_w, m_w); - if ( b_w > 4 ) { - memset(c_y + 4, 0, b_w - 4); - } - } - else { - u3a_atom* d_u = u3a_to_ptr(d); - c3_w n_w = d_u->len_w << 2; - c3_y* x_y = (c3_y*)d_u->buf_w + a_w; - - if ( a_w >= n_w ) { - memset(c_y, 0, b_w); - } - else { - c3_w z_w = c3_min(b_w, n_w - a_w); - memcpy(c_y, x_y, z_w); - if ( b_w > n_w - a_w ) { - memset(c_y + z_w, 0, b_w + a_w - n_w); - } - } - } -} - -/* u3r_bytes_fit(): -** -** Copy (len_w) bytes of (a) into (buf_y) if it fits, returning overage -*/ -c3_w -u3r_bytes_fit(c3_w len_w, c3_y *buf_y, u3_atom a) -{ - c3_w met_w = u3r_met(3, a); - if ( met_w <= len_w ) { - u3r_bytes(0, len_w, buf_y, a); - return 0; - } - else { - return len_w - met_w; - } -} - -/* u3r_bytes_alloc(): -** -** Copy (len_w) bytes starting at (a_w) from (b) into a fresh allocation. -*/ -c3_y* -u3r_bytes_alloc(c3_w a_w, - c3_w len_w, - u3_atom b) -{ - c3_y* b_y = u3a_malloc(len_w); - u3r_bytes(a_w, a_w + len_w, b_y, b); - return b_y; -} - -/* u3r_bytes_all(): -** -** Allocate and return a new byte array with all the bytes of (a), -** storing the length in (len_w). -*/ -c3_y* -u3r_bytes_all(c3_w* len_w, u3_atom a) -{ - c3_w met_w = *len_w = u3r_met(3, a); - return u3r_bytes_alloc(0, met_w, a); -} - -/* u3r_mp(): -** -** Copy (b) into (a_mp). -*/ -void -u3r_mp(mpz_t a_mp, - u3_atom b) -{ - c3_assert(u3_none != b); - c3_assert(_(u3a_is_atom(b))); - - if ( _(u3a_is_cat(b)) ) { - mpz_init_set_ui(a_mp, b); - } - else { - u3a_atom* b_u = u3a_to_ptr(b); - c3_w len_w = b_u->len_w; - c3_d bit_d = (c3_d)len_w << 5; - - // avoid reallocation on import, if possible - // - mpz_init2(a_mp, (c3_w)c3_min(bit_d, UINT32_MAX)); - mpz_import(a_mp, len_w, -1, sizeof(c3_w), 0, 0, b_u->buf_w); - } -} - -/* u3r_short(): -** -** Return short (a_w) of (b). -*/ -c3_s -u3r_short(c3_w a_w, - u3_atom b) -{ - c3_assert( u3_none != b ); - c3_assert( c3y == u3a_is_atom(b) ); - - if ( c3y == u3a_is_cat(b) ) { - switch ( a_w ) { - case 0: return b & 0xffff; - case 1: return b >> 16; - default: return 0; - } - } - else { - u3a_atom* b_u = u3a_to_ptr(b); - c3_w nix_w = a_w >> 1; - - if ( nix_w >= b_u->len_w ) { - return 0; - } - else { - c3_w wor_w = b_u->buf_w[nix_w]; - - return ( a_w & 1 ) ? (wor_w >> 16) : (wor_w & 0xffff); - } - } -} - -/* u3r_word(): -** -** Return word (a_w) of (b). -*/ -c3_w -u3r_word(c3_w a_w, - u3_atom b) -{ - c3_assert(u3_none != b); - c3_assert(_(u3a_is_atom(b))); - - if ( _(u3a_is_cat(b)) ) { - if ( a_w > 0 ) { - return 0; - } - else return b; - } - else { - u3a_atom* b_u = u3a_to_ptr(b); - - if ( a_w >= b_u->len_w ) { - return 0; - } - else return b_u->buf_w[a_w]; - } -} - -/* u3r_word_fit(): -** -** Fill (out_w) with (a) if it fits, returning success. -*/ -c3_t -u3r_word_fit(c3_w *out_w, u3_atom a) -{ - if ( u3r_met(5, a) > 1 ) { - return 0; - } - else { - *out_w = u3r_word(0, a); - return 1; - } -} - -/* u3r_chub(): -** -** Return double-word (a_w) of (b). -*/ -c3_d -u3r_chub(c3_w a_w, - u3_atom b) -{ - c3_w wlo_w = u3r_word(a_w * 2, b); - c3_w whi_w = u3r_word(1 + (a_w * 2), b); - - return (((uint64_t)whi_w) << 32ULL) | ((uint64_t)wlo_w); -} - -/* u3r_words(): -** -** Copy words (a_w) through (a_w + b_w - 1) from (d) to (c). -*/ -void -u3r_words(c3_w a_w, - c3_w b_w, - c3_w* c_w, - u3_atom d) -{ - c3_assert(u3_none != d); - c3_assert(_(u3a_is_atom(d))); - - if ( b_w == 0 ) { - return; - } - if ( _(u3a_is_cat(d)) ) { - if ( a_w == 0 ) { - *c_w = d; - memset((c3_y*)(c_w + 1), 0, (b_w - 1) << 2); - } - else { - memset((c3_y*)c_w, 0, b_w << 2); - } - } - else { - u3a_atom* d_u = u3a_to_ptr(d); - if ( a_w >= d_u->len_w ) { - memset((c3_y*)c_w, 0, b_w << 2); - } - else { - c3_w z_w = c3_min(b_w, d_u->len_w - a_w); - c3_w* x_w = d_u->buf_w + a_w; - memcpy((c3_y*)c_w, (c3_y*)x_w, z_w << 2); - if ( b_w > d_u->len_w - a_w ) { - memset((c3_y*)(c_w + z_w), 0, (b_w + a_w - d_u->len_w) << 2); - } - } - } -} - -/* u3r_chubs(): -** -** Copy double-words (a_w) through (a_w + b_w - 1) from (d) to (c). -*/ -void -u3r_chubs(c3_w a_w, - c3_w b_w, - c3_d* c_d, - u3_atom d) -{ - /* XX: assumes little-endian - */ - u3r_words(a_w * 2, b_w * 2, (c3_w *)c_d, d); -} - -/* u3r_safe_byte(): validate and retrieve byte. -*/ -c3_o -u3r_safe_byte(u3_noun dat, c3_y* out_y) -{ - if ( (c3n == u3a_is_atom(dat)) - || (1 < u3r_met(3, dat)) ) - { - return c3n; - } - - *out_y = u3r_byte(0, dat); - return c3y; -} - -/* u3r_safe_word(): validate and retrieve word. -*/ -c3_o -u3r_safe_word(u3_noun dat, c3_w* out_w) -{ - if ( (c3n == u3a_is_atom(dat)) - || (1 < u3r_met(5, dat)) ) - { - return c3n; - } - - *out_w = u3r_word(0, dat); - return c3y; -} - -/* u3r_safe_chub(): validate and retrieve chub. -*/ -c3_o -u3r_safe_chub(u3_noun dat, c3_d* out_d) -{ - if ( (c3n == u3a_is_atom(dat)) - || (1 < u3r_met(6, dat)) ) - { - return c3n; - } - - *out_d = u3r_chub(0, dat); - return c3y; -} - -/* u3r_chop_bits(): -** -** XOR `wid_d` bits from`src_w` at `bif_g` to `dst_w` at `bif_g` -** -** NB: [dst_w] must have space for [bit_g + wid_d] bits -*/ -void -u3r_chop_bits(c3_g bif_g, - c3_d wid_d, - c3_g bit_g, - c3_w* dst_w, - const c3_w* src_w) -{ - c3_y fib_y = 32 - bif_g; - c3_y tib_y = 32 - bit_g; - - // we need to chop words - // - if ( wid_d >= tib_y ) { - // align *dst_w - // - if ( bit_g ) { - c3_w low_w = src_w[0] >> bif_g; - - if ( bif_g > bit_g ) { - low_w ^= src_w[1] << fib_y; - } - - *dst_w++ ^= low_w << bit_g; - - wid_d -= tib_y; - bif_g += tib_y; - src_w += !!(bif_g >> 5); - bif_g &= 31; - fib_y = 32 - bif_g; - } - - { - size_t i_i, byt_i = wid_d >> 5; - - if ( !bif_g ) { - for ( i_i = 0; i_i < byt_i; i_i++ ) { - dst_w[i_i] ^= src_w[i_i]; - } - } - else { - for ( i_i = 0; i_i < byt_i; i_i++ ) { - dst_w[i_i] ^= (src_w[i_i] >> bif_g) ^ (src_w[i_i + 1] << fib_y); - } - } - - src_w += byt_i; - dst_w += byt_i; - wid_d &= 31; - bit_g = 0; - } - } - - // we need to chop (more) bits - // - if ( wid_d ) { - c3_w hig_w = src_w[0] >> bif_g; - - if ( wid_d > fib_y ) { - hig_w ^= src_w[1] << fib_y; - } - - *dst_w ^= (hig_w & ((1 << wid_d) - 1)) << bit_g; - } -} - -/* u3r_chop_words(): -** -** Into the bloq space of `met`, from position `fum` for a -** span of `wid`, to position `tou`, XOR from `src_w` -** into `dst_w`. -** -** NB: [dst_w] must have space for [tou_w + wid_w] bloqs -*/ -void -u3r_chop_words(c3_g met_g, - c3_w fum_w, - c3_w wid_w, - c3_w tou_w, - c3_w* dst_w, - c3_w len_w, - const c3_w* src_w) -{ - // operate on words - // - if ( met_g >= 5 ) { - size_t i_i, wid_i; - - { - c3_g hut_g = met_g - 5; - size_t fum_i = (size_t)fum_w << hut_g; - size_t tou_i = (size_t)tou_w << hut_g; - size_t tot_i; - - wid_i = (size_t)wid_w << hut_g; - tot_i = fum_i + wid_i; - - // since [dst_w] must have space for (tou_w + wid_w) bloqs, - // neither conversion can overflow - // - if ( (fum_i >> hut_g != fum_w) || (tot_i - wid_i != fum_i) ) { - u3m_bail(c3__fail); - return; - } - else if ( fum_i >= len_w ) { - return; - } - - if ( tot_i > len_w ) { - wid_i -= tot_i - len_w; - } - - src_w += fum_i; - dst_w += tou_i; - } - - for ( i_i = 0; i_i < wid_i; i_i++ ) { - dst_w[i_i] ^= src_w[i_i]; - } - } - // operate on bits - // - else { - c3_d wid_d = (c3_d)wid_w << met_g; - c3_g bif_g, bit_g; - - { - c3_d len_d = (c3_d)len_w << 5; - c3_d fum_d = (c3_d)fum_w << met_g; - c3_d tou_d = (c3_d)tou_w << met_g; - c3_d tot_d = fum_d + wid_d; - - // see above - // - if ( (fum_d >> met_g != fum_w) || (tot_d - wid_d != fum_d) ) { - u3m_bail(c3__fail); - return; - } - else if ( fum_d > len_d ) { - return; - } - - if ( tot_d > len_d ) { - wid_d -= tot_d - len_d; - } - - src_w += fum_d >> 5; - dst_w += tou_d >> 5; - bif_g = fum_d & 31; - bit_g = tou_d & 31; - } - - u3r_chop_bits(bif_g, wid_d, bit_g, dst_w, src_w); - } -} - -/* u3r_chop(): -** -** Into the bloq space of `met`, from position `fum` for a -** span of `wid`, to position `tou`, XOR from atom `src` -** into `dst_w`. -** -** NB: [dst_w] must have space for [tou_w + wid_w] bloqs -*/ -void -u3r_chop(c3_g met_g, - c3_w fum_w, - c3_w wid_w, - c3_w tou_w, - c3_w* dst_w, - u3_atom src) -{ - c3_w* src_w; - c3_w len_w; - - if ( _(u3a_is_cat(src)) ) { - len_w = src ? 1 : 0; - src_w = &src; - } - else { - u3a_atom* src_u = u3a_to_ptr(src); - - c3_assert(u3_none != src); - c3_assert(_(u3a_is_atom(src))); - - len_w = src_u->len_w; - src_w = src_u->buf_w; - } - - u3r_chop_words(met_g, fum_w, wid_w, tou_w, dst_w, len_w, src_w); -} - -/* u3r_string(): `a` as malloced C string. -*/ -c3_c* -u3r_string(u3_atom a) -{ - c3_w met_w = u3r_met(3, a); - c3_c* str_c = c3_malloc(met_w + 1); - - u3r_bytes(0, met_w, (c3_y*)str_c, a); - str_c[met_w] = 0; - return str_c; -} - -/* u3r_tape(): `a`, a list of bytes, as malloced C string. -*/ -c3_y* -u3r_tape(u3_noun a) -{ - u3_noun b; - c3_w i_w; - c3_y *a_y; - - for ( i_w = 0, b=a; c3y == u3a_is_cell(b); i_w++, b=u3a_t(b) ) - ; - a_y = c3_malloc(i_w + 1); - - for ( i_w = 0, b=a; c3y == u3a_is_cell(b); i_w++, b=u3a_t(b) ) { - a_y[i_w] = u3a_h(b); - } - a_y[i_w] = 0; - - return a_y; -} - -/* u3r_mug_both(): Join two mugs. -*/ -c3_l -u3r_mug_both(c3_l lef_l, c3_l rit_l) -{ - c3_y len_y = 4 + ((c3_bits_word(rit_l) + 0x7) >> 3); - c3_w syd_w = 0xdeadbeef; - c3_w i_w = 0; - c3_y buf_y[8]; - - buf_y[0] = lef_l & 0xff; - buf_y[1] = (lef_l >> 8) & 0xff; - buf_y[2] = (lef_l >> 16) & 0xff; - buf_y[3] = (lef_l >> 24) & 0xff; - buf_y[4] = rit_l & 0xff; - buf_y[5] = (rit_l >> 8) & 0xff; - buf_y[6] = (rit_l >> 16) & 0xff; - buf_y[7] = (rit_l >> 24) & 0xff; - - while ( i_w < 8 ) { - c3_w haz_w; - c3_l ham_l; - - MurmurHash3_x86_32(buf_y, len_y, syd_w, &haz_w); - ham_l = (haz_w >> 31) ^ (haz_w & 0x7fffffff); - - if ( 0 == ham_l ) { - syd_w++; i_w++; - } - else { - return ham_l; - } - } - - return 0xfffe; -} - -/* u3r_mug_bytes(): Compute the mug of `buf`, `len`, LSW first. -*/ -c3_l -u3r_mug_bytes(const c3_y *buf_y, - c3_w len_w) -{ - c3_w syd_w = 0xcafebabe; - c3_w i_w = 0; - - while ( i_w < 8 ) { - c3_w haz_w; - c3_l ham_l; - - MurmurHash3_x86_32(buf_y, len_w, syd_w, &haz_w); - ham_l = (haz_w >> 31) ^ (haz_w & 0x7fffffff); - - if ( 0 == ham_l ) { - syd_w++; i_w++; - } - else { - return ham_l; - } - } - - return 0x7fff; -} - -/* u3r_mug_c(): Compute the mug of `a`, LSB first. -*/ -c3_l -u3r_mug_c(const c3_c* a_c) -{ - return u3r_mug_bytes((c3_y*)a_c, strlen(a_c)); -} - -/* u3r_mug_cell(): Compute the mug of the cell `[hed tel]`. -*/ -c3_l -u3r_mug_cell(u3_noun hed, - u3_noun tel) -{ - c3_w lus_w = u3r_mug(hed); - c3_w biq_w = u3r_mug(tel); - - return u3r_mug_both(lus_w, biq_w); -} - -/* u3r_mug_chub(): Compute the mug of `num`, LSW first. -*/ -c3_l -u3r_mug_chub(c3_d num_d) -{ - c3_w buf_w[2]; - - buf_w[0] = (c3_w)(num_d & 0xffffffffULL); - buf_w[1] = (c3_w)(num_d >> 32); - - return u3r_mug_words(buf_w, 2); -} - -/* u3r_mug_words(): 31-bit nonzero MurmurHash3 on raw words. -*/ -c3_l -u3r_mug_words(const c3_w* key_w, c3_w len_w) -{ - c3_w byt_w; - - // ignore trailing zeros - // - while ( len_w && !key_w[len_w - 1] ) { - len_w--; - } - - // calculate byte-width a la u3r_met(3, ...) - // - if ( !len_w ) { - byt_w = 0; - } - else { - c3_w gal_w = len_w - 1; - c3_w daz_w = key_w[gal_w]; - - byt_w = (gal_w << 2) + ((c3_bits_word(daz_w) + 7) >> 3); - } - - // XX: assumes little-endian - // - return u3r_mug_bytes((c3_y*)key_w, byt_w); -} - -/* _cr_mug: stack frame for recording cell traversal -** !mug == head-frame -*/ -typedef struct { - c3_l mug_l; - u3_cell cel; -} _cr_mugf; - -/* _cr_mug_next(): advance mug calculation, pushing cells onto the stack. -*/ -static inline c3_l -_cr_mug_next(u3a_pile* pil_u, u3_noun veb) -{ - while ( 1 ) { - // veb is a direct atom, mug is not memoized - // - if ( c3y == u3a_is_cat(veb) ) { - return (c3_l)u3r_mug_words(&veb, 1); - } - // veb is indirect, a pointer into the loom - // - else { - u3a_noun* veb_u = u3a_to_ptr(veb); - - // veb has already been mugged, return memoized value - // - // XX add debug assertion that mug is 31-bit? - // - if ( veb_u->mug_w ) { - return (c3_l)veb_u->mug_w; - } - // veb is an indirect atom, mug its bytes and memoize - // - else if ( c3y == u3a_is_atom(veb) ) { - u3a_atom* vat_u = (u3a_atom*)veb_u; - c3_l mug_l = u3r_mug_words(vat_u->buf_w, vat_u->len_w); - vat_u->mug_w = mug_l; - return mug_l; - } - // veb is a cell, push a stack frame to mark head-recursion - // and read the head - // - else { - u3a_cell* cel_u = (u3a_cell*)veb_u; - _cr_mugf* fam_u = u3a_push(pil_u); - - fam_u->mug_l = 0; - fam_u->cel = veb; - - veb = cel_u->hed; - continue; - } - } - } -} - -/* u3r_mug(): statefully mug a noun with 31-bit murmur3. -*/ -c3_l -u3r_mug(u3_noun veb) -{ - u3a_pile pil_u; - _cr_mugf* fam_u; - c3_l mug_l; - - // sanity check - // - c3_assert( u3_none != veb ); - - u3a_pile_prep(&pil_u, sizeof(*fam_u)); - - // commence mugging - // - mug_l = _cr_mug_next(&pil_u, veb); - - // process cell results - // - if ( c3n == u3a_pile_done(&pil_u) ) { - fam_u = u3a_peek(&pil_u); - - do { - // head-frame: stash mug and continue into the tail - // - if ( !fam_u->mug_l ) { - u3a_cell* cel_u = u3a_to_ptr(fam_u->cel); - - fam_u->mug_l = mug_l; - mug_l = _cr_mug_next(&pil_u, cel_u->tel); - fam_u = u3a_peek(&pil_u); - } - // tail-frame: calculate/memoize cell mug and pop the stack - // - else { - u3a_cell* cel_u = u3a_to_ptr(fam_u->cel); - - mug_l = u3r_mug_both(fam_u->mug_l, mug_l); - cel_u->mug_w = mug_l; - fam_u = u3a_pop(&pil_u); - } - } - while ( c3n == u3a_pile_done(&pil_u) ); - } - - return mug_l; -} diff --git a/pkg/urbit/noun/serial.c b/pkg/urbit/noun/serial.c deleted file mode 100644 index 26cc05f24..000000000 --- a/pkg/urbit/noun/serial.c +++ /dev/null @@ -1,966 +0,0 @@ -/* noun/serial.c -** -*/ - -#include "all.h" -#include "ur/ur.h" -#include -#include - -/* _cs_jam_buf: struct for tracking the fibonacci-allocated jam of a noun -*/ -struct _cs_jam_fib { - u3i_slab* sab_u; - u3p(u3h_root) har_p; - c3_w a_w; - c3_w b_w; - c3_w bit_w; -}; - -/* _cs_jam_fib_grow(): reallocate buffer with fibonacci growth -*/ -static void -_cs_jam_fib_grow(struct _cs_jam_fib* fib_u, c3_w mor_w) -{ - c3_w wan_w = fib_u->bit_w + mor_w; - - // check for c3_w overflow - // - if ( wan_w < mor_w ) { - u3m_bail(c3__fail); - } - - if ( wan_w > fib_u->a_w ) { - c3_w old_w = fib_u->sab_u->len_w; - c3_w c_w = 0; - - // fibonacci growth - // - while ( c_w < wan_w ) { - c_w = fib_u->a_w + fib_u->b_w; - fib_u->b_w = fib_u->a_w; - fib_u->a_w = c_w; - } - - u3i_slab_grow(fib_u->sab_u, 0, c_w); - } -} - -/* _cs_jam_fib_chop(): chop [met_w] bits of [a] into [fib_u] -*/ -static void -_cs_jam_fib_chop(struct _cs_jam_fib* fib_u, c3_w met_w, u3_noun a) -{ - c3_w bit_w = fib_u->bit_w; - _cs_jam_fib_grow(fib_u, met_w); - fib_u->bit_w += met_w; - - { - c3_w* buf_w = fib_u->sab_u->buf_w; - u3r_chop(0, 0, met_w, bit_w, buf_w, a); - } -} - -/* _cs_jam_fib_mat(): length-prefixed encode (mat) [a] into [fib_u] -*/ -static void -_cs_jam_fib_mat(struct _cs_jam_fib* fib_u, u3_noun a) -{ - if ( 0 == a ) { - _cs_jam_fib_chop(fib_u, 1, 1); - } - else { - c3_w a_w = u3r_met(0, a); - c3_w b_w = c3_bits_word(a_w); - - _cs_jam_fib_chop(fib_u, b_w+1, 1 << b_w); - _cs_jam_fib_chop(fib_u, b_w-1, a_w & ((1 << (b_w-1)) - 1)); - _cs_jam_fib_chop(fib_u, a_w, a); - } -} - -/* _cs_jam_fib_atom_cb(): encode atom or backref -*/ -static void -_cs_jam_fib_atom_cb(u3_atom a, void* ptr_v) -{ - struct _cs_jam_fib* fib_u = ptr_v; - u3_weak b = u3h_git(fib_u->har_p, a); - - // if [a] has no backref, encode atom and put cursor into [har_p] - // - if ( u3_none == b ) { - u3h_put(fib_u->har_p, a, u3i_words(1, &(fib_u->bit_w))); - _cs_jam_fib_chop(fib_u, 1, 0); - _cs_jam_fib_mat(fib_u, a); - } - else { - c3_w a_w = u3r_met(0, a); - c3_w b_w = u3r_met(0, b); - - // if [a] is smaller than the backref, encode atom - // - if ( a_w <= b_w ) { - _cs_jam_fib_chop(fib_u, 1, 0); - _cs_jam_fib_mat(fib_u, a); - } - // otherwise, encode backref - // - else { - _cs_jam_fib_chop(fib_u, 2, 3); - _cs_jam_fib_mat(fib_u, b); - } - } -} - -/* _cs_jam_fib_cell_cb(): encode cell or backref -*/ -static c3_o -_cs_jam_fib_cell_cb(u3_noun a, void* ptr_v) -{ - struct _cs_jam_fib* fib_u = ptr_v; - u3_weak b = u3h_git(fib_u->har_p, a); - - // if [a] has no backref, encode cell and put cursor into [har_p] - // - if ( u3_none == b ) { - u3h_put(fib_u->har_p, a, u3i_words(1, &(fib_u->bit_w))); - _cs_jam_fib_chop(fib_u, 2, 1); - return c3y; - } - // otherwise, encode backref and shortcircuit traversal - // - else { - _cs_jam_fib_chop(fib_u, 2, 3); - _cs_jam_fib_mat(fib_u, b); - return c3n; - } -} - -/* u3s_jam_fib(): jam without atom allocation. -** -** returns atom-suitable words, and *bit_w will have -** the length (in bits). return should be freed with u3a_wfree(). -*/ -c3_w -u3s_jam_fib(u3i_slab* sab_u, u3_noun a) -{ - struct _cs_jam_fib fib_u; - fib_u.har_p = u3h_new(); - fib_u.sab_u = sab_u; - - // fib(12) is small enough to be reasonably fast to allocate. - // fib(11) is needed to get fib(13). - // - // - fib_u.a_w = ur_fib12; - fib_u.b_w = ur_fib11; - fib_u.bit_w = 0; - u3i_slab_init(sab_u, 0, fib_u.a_w); - - u3a_walk_fore(a, &fib_u, _cs_jam_fib_atom_cb, _cs_jam_fib_cell_cb); - - u3h_free(fib_u.har_p); - return fib_u.bit_w; -} - -typedef struct _jam_xeno_s { - u3p(u3h_root) har_p; - ur_bsw_t rit_u; -} _jam_xeno_t; - -/* _cs_coin_chub(): shortcircuit u3i_chubs(). -*/ -static inline u3_atom -_cs_coin_chub(c3_d a_d) -{ - return ( 0x7fffffffULL >= a_d ) ? a_d : u3i_chubs(1, &a_d); -} - -/* _cs_jam_xeno_atom(): encode in/direct atom in bitstream. -*/ -static inline void -_cs_jam_bsw_atom(ur_bsw_t* rit_u, c3_w met_w, u3_atom a) -{ - if ( c3y == u3a_is_cat(a) ) { - // XX need a ur_bsw_atom32() - // - ur_bsw_atom64(rit_u, (c3_y)met_w, (c3_d)a); - } - else { - u3a_atom* vat_u = u3a_to_ptr(a); - // XX assumes little-endian - // XX need a ur_bsw_atom_words() - // - c3_y* byt_y = (c3_y*)vat_u->buf_w; - ur_bsw_atom_bytes(rit_u, (c3_d)met_w, byt_y); - } -} - -/* _cs_jam_bsw_back(): encode in/direct backref in bitstream. -*/ -static inline void -_cs_jam_bsw_back(ur_bsw_t* rit_u, c3_w met_w, u3_atom a) -{ - c3_d bak_d = ( c3y == u3a_is_cat(a) ) - ? (c3_d)a - : u3r_chub(0, a); - - // XX need a ur_bsw_back32() - // - ur_bsw_back64(rit_u, (c3_y)met_w, bak_d); -} - -/* _cs_jam_xeno_atom(): encode atom or backref in bitstream. -*/ -static void -_cs_jam_xeno_atom(u3_atom a, void* ptr_v) -{ - _jam_xeno_t* jam_u = ptr_v; - ur_bsw_t* rit_u = &(jam_u->rit_u); - u3_weak bak = u3h_git(jam_u->har_p, a); - c3_w met_w = u3r_met(0, a); - - if ( u3_none == bak ) { - u3h_put(jam_u->har_p, a, _cs_coin_chub(rit_u->bits)); - _cs_jam_bsw_atom(rit_u, met_w, a); - } - else { - c3_w bak_w = u3r_met(0, bak); - - if ( met_w <= bak_w ) { - _cs_jam_bsw_atom(rit_u, met_w, a); - } - else { - _cs_jam_bsw_back(rit_u, bak_w, bak); - } - } -} - -/* _cs_jam_xeno_cell(): encode cell or backref in bitstream. -*/ -static c3_o -_cs_jam_xeno_cell(u3_noun a, void* ptr_v) -{ - _jam_xeno_t* jam_u = ptr_v; - ur_bsw_t* rit_u = &(jam_u->rit_u); - u3_weak bak = u3h_git(jam_u->har_p, a); - - if ( u3_none == bak ) { - u3h_put(jam_u->har_p, a, _cs_coin_chub(rit_u->bits)); - ur_bsw_cell(rit_u); - return c3y; - } - else { - _cs_jam_bsw_back(rit_u, u3r_met(0, bak), bak); - return c3n; - } -} - -/* u3s_jam_xeno(): jam with off-loom buffer (re-)allocation. -*/ -c3_d -u3s_jam_xeno(u3_noun a, c3_d* len_d, c3_y** byt_y) -{ - _jam_xeno_t jam_u = {0}; - ur_bsw_init(&jam_u.rit_u, ur_fib11, ur_fib12); - jam_u.har_p = u3h_new(); - - u3a_walk_fore(a, &jam_u, _cs_jam_xeno_atom, _cs_jam_xeno_cell); - - u3h_free(jam_u.har_p); - return ur_bsw_done(&jam_u.rit_u, len_d, byt_y); -} - -/* _cs_cue: stack frame for tracking intermediate cell results -*/ -typedef struct _cs_cue { - u3_weak hed; // head of a cell or u3_none - u3_atom wid; // bitwidth of [hed] or 0 - u3_atom cur; // bit-cursor position -} _cs_cue; - -/* _cs_rub: rub, TRANSFER [cur], RETAIN [a] -*/ -static inline u3_noun -_cs_rub(u3_atom cur, u3_atom a) -{ - u3_noun pro = u3qe_rub(cur, a); - u3z(cur); - return pro; -} - -/* _cs_cue_next(): advance into [a], reading next value -** TRANSFER [cur], RETAIN [a] -*/ -static inline u3_noun -_cs_cue_next(u3a_pile* pil_u, - u3p(u3h_root) har_p, - u3_atom cur, - u3_atom a, - u3_atom* wid) -{ - while ( 1 ) { - // read tag bit at cur - // - c3_y tag_y = u3qc_cut(0, cur, 1, a); - - // low bit unset, (1 + cur) points to an atom - // - // produce atom and the width we read - // - if ( 0 == tag_y ) { - u3_noun bur = _cs_rub(u3i_vint(cur), a); - u3_noun pro = u3k(u3t(bur)); - - u3h_put(har_p, cur, u3k(pro)); - *wid = u3qa_inc(u3h(bur)); - - u3z(bur); - return pro; - } - else { - // read tag bit at (1 + cur) - // - { - u3_noun x = u3qa_inc(cur); - tag_y = u3qc_cut(0, x, 1, a); - u3z(x); - } - - // next bit set, (2 + cur) points to a backref - // - // produce referenced value and the width we read - // - if ( 1 == tag_y ) { - u3_noun bur = _cs_rub(u3ka_add(2, cur), a); - u3_noun pro = u3x_good(u3h_get(har_p, u3t(bur))); - - *wid = u3qa_add(2, u3h(bur)); - - u3z(bur); - return pro; - } - // next bit unset, (2 + cur) points to the head of a cell - // - // push a head-frame onto the road stack and read the head - // - else { - _cs_cue* fam_u = u3a_push(pil_u); - - // NB: fam_u->wid unused in head-frame - // - fam_u->hed = u3_none; - fam_u->cur = cur; - - cur = u3qa_add(2, cur); - continue; - } - } - } -} - -u3_noun -u3s_cue(u3_atom a) -{ - // pro: cue'd noun product - // wid: bitwidth read to produce [pro] - // fam_u: stack frame - // har_p: backreference table - // pil_u: stack control structure - // - u3_noun pro; - u3_atom wid, cur = 0; - _cs_cue* fam_u; - u3p(u3h_root) har_p = u3h_new(); - u3a_pile pil_u; - - // initialize stack control - // - u3a_pile_prep(&pil_u, sizeof(*fam_u)); - - // commence cueing at bit-position 0 - // - pro = _cs_cue_next(&pil_u, har_p, 0, a, &wid); - - // process cell results - // - if ( c3n == u3a_pile_done(&pil_u) ) { - fam_u = u3a_peek(&pil_u); - - do { - // head-frame: stash [pro] and [wid]; continue into the tail - // - if ( u3_none == fam_u->hed ) { - // NB: fam_u->wid unused in head-frame - // - fam_u->hed = pro; - fam_u->wid = wid; - - // continue reading at the bit-position after [pro] - { - u3_noun cur = u3ka_add(2, u3qa_add(wid, fam_u->cur)); - pro = _cs_cue_next(&pil_u, har_p, cur, a, &wid); - } - - fam_u = u3a_peek(&pil_u); - } - // tail-frame: cons cell, recalculate [wid], and pop the stack - // - else { - pro = u3nc(fam_u->hed, pro); - u3h_put(har_p, fam_u->cur, u3k(pro)); - u3z(fam_u->cur); - wid = u3ka_add(2, u3ka_add(wid, fam_u->wid)); - fam_u = u3a_pop(&pil_u); - } - } while ( c3n == u3a_pile_done(&pil_u) ); - } - - u3z(wid); - u3h_free(har_p); - - return pro; -} - -/* -** stack frame for recording head vs tail iteration -** -** $? [u3_none bits=@] -** [hed=* bits=@] -*/ -typedef struct _cue_frame_s { - u3_weak ref; - c3_d bit_d; -} _cue_frame_t; - -/* _cs_cue_xeno_next(): read next value from bitstream, dictionary off-loom. -*/ -static inline ur_cue_res_e -_cs_cue_xeno_next(u3a_pile* pil_u, - ur_bsr_t* red_u, - ur_dict32_t* dic_u, - u3_noun* out) -{ - ur_root_t* rot_u = 0; - - while ( 1 ) { - c3_d len_d, bit_d = red_u->bits; - ur_cue_tag_e tag_e; - ur_cue_res_e res_e; - - if ( ur_cue_good != (res_e = ur_bsr_tag(red_u, &tag_e)) ) { - return res_e; - } - - switch ( tag_e ) { - default: c3_assert(0); - - case ur_jam_cell: { - _cue_frame_t* fam_u = u3a_push(pil_u); - - fam_u->ref = u3_none; - fam_u->bit_d = bit_d; - continue; - } - - case ur_jam_back: { - if ( ur_cue_good != (res_e = ur_bsr_rub_len(red_u, &len_d)) ) { - return res_e; - } - else if ( 62 < len_d ) { - return ur_cue_meme; - } - else { - c3_d bak_d = ur_bsr64_any(red_u, len_d); - c3_w bak_w; - - if ( !ur_dict32_get(rot_u, dic_u, bak_d, &bak_w) ) { - return ur_cue_back; - } - - *out = u3k((u3_noun)bak_w); - return ur_cue_good; - } - } - - case ur_jam_atom: { - if ( ur_cue_good != (res_e = ur_bsr_rub_len(red_u, &len_d)) ) { - return res_e; - } - - if ( 31 >= len_d ) { - *out = (u3_noun)ur_bsr32_any(red_u, len_d); - } - else { - c3_d byt_d = (len_d + 0x7) >> 3; - u3i_slab sab_u; - - if ( 0xffffffffULL < byt_d) { - return ur_cue_meme; - } - else { - u3i_slab_init(&sab_u, 3, byt_d); - ur_bsr_bytes_any(red_u, len_d, sab_u.buf_y); - *out = u3i_slab_mint_bytes(&sab_u); - } - } - - ur_dict32_put(rot_u, dic_u, bit_d, *out); - return ur_cue_good; - } - } - } -} - -struct _u3_cue_xeno { - ur_dict32_t dic_u; -}; - -/* _cs_cue_xeno(): cue on-loom, with off-loom dictionary in handle. -*/ -static u3_weak -_cs_cue_xeno(u3_cue_xeno* sil_u, - c3_d len_d, - const c3_y* byt_y) -{ - ur_bsr_t red_u = {0}; - ur_dict32_t* dic_u = &sil_u->dic_u; - u3a_pile pil_u; - _cue_frame_t* fam_u; - ur_cue_res_e res_e; - u3_noun ref; - - // initialize stack control - // - u3a_pile_prep(&pil_u, sizeof(*fam_u)); - - // init bitstream-reader - // - if ( ur_cue_good != (res_e = ur_bsr_init(&red_u, len_d, byt_y)) ) { - return c3n; - } - // bit-cursor (and backreferences) must fit in 62-bit direct atoms - // - else if ( 0x7ffffffffffffffULL < len_d ) { - return c3n; - } - - // advance into stream - // - res_e = _cs_cue_xeno_next(&pil_u, &red_u, dic_u, &ref); - - // process cell results - // - if ( (c3n == u3a_pile_done(&pil_u)) - && (ur_cue_good == res_e) ) - { - fam_u = u3a_peek(&pil_u); - - do { - // f is a head-frame; stash result and read the tail from the stream - // - if ( u3_none == fam_u->ref ) { - fam_u->ref = ref; - res_e = _cs_cue_xeno_next(&pil_u, &red_u, dic_u, &ref); - fam_u = u3a_peek(&pil_u); - } - // f is a tail-frame; pop the stack and continue - // - else { - ur_root_t* rot_u = 0; - - ref = u3nc(fam_u->ref, ref); - ur_dict32_put(rot_u, dic_u, fam_u->bit_d, ref); - fam_u = u3a_pop(&pil_u); - } - } - while ( (c3n == u3a_pile_done(&pil_u)) - && (ur_cue_good == res_e) ); - } - - if ( ur_cue_good == res_e ) { - return ref; - } - // on failure, unwind the stack and dispose of intermediate nouns - // - else if ( c3n == u3a_pile_done(&pil_u) ) { - do { - if ( u3_none != fam_u->ref ) { - u3z(fam_u->ref); - } - fam_u = u3a_pop(&pil_u); - } - while ( c3n == u3a_pile_done(&pil_u) ); - } - - return u3_none; -} - -/* u3s_cue_xeno_init_with(): initialize a cue_xeno handle as specified. -*/ -u3_cue_xeno* -u3s_cue_xeno_init_with(c3_d pre_d, c3_d siz_d) -{ - u3_cue_xeno* sil_u; - - c3_assert( &(u3H->rod_u) == u3R ); - - sil_u = c3_calloc(sizeof(*sil_u)); - ur_dict32_grow((ur_root_t*)0, &sil_u->dic_u, pre_d, siz_d); - - return sil_u; -} - -/* u3s_cue_xeno_init(): initialize a cue_xeno handle. -*/ -u3_cue_xeno* -u3s_cue_xeno_init(void) -{ - return u3s_cue_xeno_init_with(ur_fib10, ur_fib11); -} - -/* u3s_cue_xeno_init(): cue on-loom, with off-loom dictionary in handle. -*/ -u3_weak -u3s_cue_xeno_with(u3_cue_xeno* sil_u, - c3_d len_d, - const c3_y* byt_y) -{ - u3_weak som; - - c3_assert( &(u3H->rod_u) == u3R ); - - som = _cs_cue_xeno(sil_u, len_d, byt_y); - ur_dict32_wipe(&sil_u->dic_u); - return som; -} - -/* u3s_cue_xeno_init(): dispose cue_xeno handle. -*/ -void -u3s_cue_xeno_done(u3_cue_xeno* sil_u) -{ - ur_dict_free((ur_dict_t*)&sil_u->dic_u); - c3_free(sil_u); -} - -/* u3s_cue_xeno(): cue on-loom, with off-loom dictionary. -*/ -u3_weak -u3s_cue_xeno(c3_d len_d, - const c3_y* byt_y) -{ - u3_cue_xeno* sil_u; - u3_weak som; - - c3_assert( &(u3H->rod_u) == u3R ); - - sil_u = u3s_cue_xeno_init(); - som = _cs_cue_xeno(sil_u, len_d, byt_y); - u3s_cue_xeno_done(sil_u); - return som; -} - -/* _cs_cue_need(): bail on ur_cue_* read failures. -*/ -static inline void -_cs_cue_need(ur_cue_res_e res_e) -{ - if ( ur_cue_good == res_e ) { - return; - } - else { - c3_m mot_m = (ur_cue_meme == res_e) ? c3__meme : c3__exit; - u3m_bail(mot_m); - } -} - -/* _cs_cue_get(): u3h_get wrapper handling allocation and refcounts. -*/ -static inline u3_weak -_cs_cue_get(u3p(u3h_root) har_p, c3_d key_d) -{ - u3_atom key = _cs_coin_chub(key_d); - u3_weak pro = u3h_get(har_p, key); - u3z(key); - return pro; -} - -/* _cs_cue_put(): u3h_put wrapper handling allocation and refcounts. -*/ -static inline u3_noun -_cs_cue_put(u3p(u3h_root) har_p, c3_d key_d, u3_noun val) -{ - u3_atom key = _cs_coin_chub(key_d); - u3h_put(har_p, key, u3k(val)); - u3z(key); - return val; -} - -/* _cs_cue_bytes_next(): read next value from bitstream. -*/ -static inline u3_noun -_cs_cue_bytes_next(u3a_pile* pil_u, - u3p(u3h_root) har_p, - ur_bsr_t* red_u) -{ - while ( 1 ) { - c3_d len_d, bit_d = red_u->bits; - ur_cue_tag_e tag_e; - - _cs_cue_need(ur_bsr_tag(red_u, &tag_e)); - - switch ( tag_e ) { - default: c3_assert(0); - - case ur_jam_cell: { - _cue_frame_t* fam_u = u3a_push(pil_u); - - fam_u->ref = u3_none; - fam_u->bit_d = bit_d; - continue; - } - - case ur_jam_back: { - _cs_cue_need(ur_bsr_rub_len(red_u, &len_d)); - - if ( 62 < len_d ) { - return u3m_bail(c3__meme); - } - else { - c3_d bak_d = ur_bsr64_any(red_u, len_d); - u3_weak bak = _cs_cue_get(har_p, bak_d); - return u3x_good(bak); - } - } - - case ur_jam_atom: { - u3_atom vat; - - _cs_cue_need(ur_bsr_rub_len(red_u, &len_d)); - - if ( 31 >= len_d ) { - vat = (u3_noun)ur_bsr32_any(red_u, len_d); - } - else { - u3i_slab sab_u; - u3i_slab_init(&sab_u, 0, len_d); - - ur_bsr_bytes_any(red_u, len_d, sab_u.buf_y); - vat = u3i_slab_mint_bytes(&sab_u); - } - - return _cs_cue_put(har_p, bit_d, vat); - } - } - } -} - -/* u3s_cue_bytes(): cue bytes onto the loom. -*/ -u3_noun -u3s_cue_bytes(c3_d len_d, const c3_y* byt_y) -{ - ur_bsr_t red_u = {0}; - u3a_pile pil_u; - _cue_frame_t* fam_u; - u3p(u3h_root) har_p; - u3_noun ref; - - // initialize stack control - // - u3a_pile_prep(&pil_u, sizeof(*fam_u)); - - // initialize a hash table for dereferencing backrefs - // - har_p = u3h_new(); - - // init bitstream-reader - // - _cs_cue_need(ur_bsr_init(&red_u, len_d, byt_y)); - - // bit-cursor (and backreferences) must fit in 62-bit direct atoms - // - if ( 0x7ffffffffffffffULL < len_d ) { - return u3m_bail(c3__meme); - } - - // advance into stream - // - ref = _cs_cue_bytes_next(&pil_u, har_p, &red_u); - - // process cell results - // - if ( c3n == u3a_pile_done(&pil_u) ) { - fam_u = u3a_peek(&pil_u); - - do { - // f is a head-frame; stash result and read the tail from the stream - // - if ( u3_none == fam_u->ref ) { - fam_u->ref = ref; - ref = _cs_cue_bytes_next(&pil_u, har_p, &red_u); - fam_u = u3a_peek(&pil_u); - } - // f is a tail-frame; pop the stack and continue - // - else { - ref = u3nc(fam_u->ref, ref); - _cs_cue_put(har_p, fam_u->bit_d, ref); - fam_u = u3a_pop(&pil_u); - } - } - while ( c3n == u3a_pile_done(&pil_u) ); - } - - u3h_free(har_p); - - return ref; -} - -/* u3s_cue_atom(): cue atom. -*/ -u3_noun -u3s_cue_atom(u3_atom a) -{ - c3_w len_w = u3r_met(3, a); - c3_y* byt_y; - - // XX assumes little-endian - // - if ( c3y == u3a_is_cat(a) ) { - byt_y = (c3_y*)&a; - } - else { - u3a_atom* vat_u = u3a_to_ptr(a); - byt_y = (c3_y*)vat_u->buf_w; - } - - return u3s_cue_bytes((c3_d)len_w, byt_y); -} - -#define DIGIT(a) ( ((a) >= '0') && ((a) <= '9') ) -#define BLOCK(a) ( ('.' == (a)[0]) \ - && DIGIT(a[1]) \ - && DIGIT(a[2]) \ - && DIGIT(a[3]) ) - -/* u3s_sift_ud_bytes: parse @ud -*/ -u3_weak -u3s_sift_ud_bytes(c3_w len_w, c3_y* byt_y) -{ - c3_y num_y = len_w % 4; // leading digits length - c3_s val_s = 0; // leading digits value - - // +ape:ag: just 0 - // - if ( !len_w ) return u3_none; - if ( '0' == *byt_y ) return ( 1 == len_w ) ? (u3_noun)0 : u3_none; - - // +ted:ab: leading nonzero (checked above), plus up to 2 digits - // -#define NEXT() do { \ - if ( !DIGIT(*byt_y) ) return u3_none; \ - val_s *= 10; \ - val_s += *byt_y++ - '0'; \ - } while (0) - - switch ( num_y ) { - case 3: NEXT(); - case 2: NEXT(); - case 1: NEXT(); break; - case 0: return u3_none; - } - -#undef NEXT - - len_w -= num_y; - - // +tid:ab: dot-prefixed 3-digit blocks - // - // avoid gmp allocation if possible - // - 19 decimal digits fit in 64 bits - // - 18 digits is 24 bytes with separators - // - if ( ((1 == num_y) && (24 >= len_w)) - || (20 >= len_w) ) - { - c3_d val_d = val_s; - - while ( len_w ) { - if ( !BLOCK(byt_y) ) return u3_none; - - byt_y++; - - val_d *= 10; - val_d += *byt_y++ - '0'; - val_d *= 10; - val_d += *byt_y++ - '0'; - val_d *= 10; - val_d += *byt_y++ - '0'; - - len_w -= 4; - } - - return u3i_chub(val_d); - } - - { - // avoid gmp realloc if possible - // - mpz_t a_mp; - { - c3_d bit_d = (c3_d)(len_w / 4) * 10; - mpz_init2(a_mp, (c3_w)c3_min(bit_d, UINT32_MAX)); - mpz_set_ui(a_mp, val_s); - } - - while ( len_w ) { - if ( !BLOCK(byt_y) ) { - mpz_clear(a_mp); - return u3_none; - } - - byt_y++; - - val_s = *byt_y++ - '0'; - val_s *= 10; - val_s += *byt_y++ - '0'; - val_s *= 10; - val_s += *byt_y++ - '0'; - - mpz_mul_ui(a_mp, a_mp, 1000); - mpz_add_ui(a_mp, a_mp, val_s); - - len_w -= 4; - } - - return u3i_mp(a_mp); - } -} - -#undef BLOCK -#undef DIGIT - -/* u3s_sift_ud: parse @ud. -*/ -u3_weak -u3s_sift_ud(u3_atom a) -{ - c3_w len_w = u3r_met(3, a); - c3_y* byt_y; - - // XX assumes little-endian - // - if ( c3y == u3a_is_cat(a) ) { - byt_y = (c3_y*)&a; - } - else { - u3a_atom* vat_u = u3a_to_ptr(a); - byt_y = (c3_y*)vat_u->buf_w; - } - - return u3s_sift_ud_bytes(len_w, byt_y); -} diff --git a/pkg/urbit/noun/trace.c b/pkg/urbit/noun/trace.c deleted file mode 100644 index 841d51ca7..000000000 --- a/pkg/urbit/noun/trace.c +++ /dev/null @@ -1,675 +0,0 @@ -/* g/t.c - -** -** This file is in the public domain. -*/ -#include "all.h" -#include "vere/vere.h" -#include -#include -#include - -static c3_o _ct_lop_o; - -/* u3t_push(): push on trace stack. -*/ -void -u3t_push(u3_noun mon) -{ - u3R->bug.tax = u3nc(mon, u3R->bug.tax); -} - -/* u3t_mean(): push `[%mean roc]` on trace stack. -*/ -void -u3t_mean(u3_noun roc) -{ - u3R->bug.tax = u3nc(u3nc(c3__mean, roc), u3R->bug.tax); -} - -/* u3t_drop(): drop from meaning stack. -*/ -void -u3t_drop(void) -{ - c3_assert(_(u3du(u3R->bug.tax))); - { - u3_noun tax = u3R->bug.tax; - - u3R->bug.tax = u3k(u3t(tax)); - u3z(tax); - } -} - -/* u3t_slog(): print directly. -*/ -void -u3t_slog(u3_noun hod) -{ - if ( 0 != u3C.slog_f ) { - u3C.slog_f(hod); - } - else { - u3z(hod); - } -} - -/* u3t_heck(): profile point. -*/ -void -u3t_heck(u3_atom cog) -{ -#if 0 - u3R->pro.cel_d++; -#else - c3_w len_w = u3r_met(3, cog); - c3_c* str_c = alloca(1 + len_w); - - u3r_bytes(0, len_w, (c3_y *)str_c, cog); - str_c[len_w] = 0; - - // Profile sampling, because it allocates on the home road, - // only works on when we're not at home. - // - if ( &(u3H->rod_u) != u3R ) { - u3a_road* rod_u; - - rod_u = u3R; - u3R = &(u3H->rod_u); - { - if ( 0 == u3R->pro.day ) { - u3R->pro.day = u3do("doss", 0); - } - u3R->pro.day = u3dc("pi-heck", u3i_string(str_c), u3R->pro.day); - } - u3R = rod_u; - } -#endif -} - -#if 0 -static void -_ct_sane(u3_noun lab) -{ - if ( u3_nul != lab ) { - c3_assert(c3y == u3du(lab)); - c3_assert(c3y == u3ud(u3h(lab))); - _ct_sane(u3t(lab)); - } -} -#endif - -#if 1 -/* _t_samp_process(): process raw sample data from live road. -*/ -static u3_noun -_t_samp_process(u3_road* rod_u) -{ - u3_noun pef = u3_nul; // (list (pair path (map path ,@ud))) - u3_noun muf = u3_nul; // (map path ,@ud) - c3_w len_w = 0; - - // Accumulate a label/map stack which collapses recursive segments. - // - while ( rod_u ) { - u3_noun don = rod_u->pro.don; - - while ( u3_nul != don ) { - // Get surface allocated label - // - // u3_noun lab = u3nc(u3i_string("foobar"), 0); - u3_noun laj = u3h(don), - lab = u3a_take(laj); - u3a_wash(laj); - - // Add the label to the traced label stack, trimming recursion. - // - { - u3_noun old; - - if ( u3_none == (old = u3kdb_get(u3k(muf), u3k(lab))) ) { - muf = u3kdb_put(muf, u3k(lab), len_w); - pef = u3nc(u3nc(lab, u3k(muf)), pef); - len_w += 1; - } - else { - u3_assure(u3a_is_cat(old)); - - u3z(muf); - while ( len_w > (old + 1) ) { - u3_noun t_pef = u3k(u3t(pef)); - - len_w -= 1; - u3z(pef); - pef = t_pef; - } - muf = u3k(u3t(u3h(pef))); - u3z(lab); - } - } - don = u3t(don); - } - rod_u = u3tn(u3_road, rod_u->par_p); - } - u3z(muf); - - // Lose the maps and save a pure label stack in original order. - // - { - u3_noun pal = u3_nul; - - while ( u3_nul != pef ) { - u3_noun h_pef = u3h(pef); - u3_noun t_pef = u3k(u3t(pef)); - - pal = u3nc(u3k(u3h(h_pef)), pal); - - u3z(pef); - pef = t_pef; - } - - // u3l_log("sample: stack length %d", u3kb_lent(u3k(pal))); - return pal; - } -} -#endif - -/* u3t_samp(): sample. -*/ -void -u3t_samp(void) -{ - if ( c3y == _ct_lop_o ) { - // _ct_lop_o here is a mutex for modifying pro.don. we - // do not want to sample in the middle of doing that, as - // it can cause memory errors. - return; - } - - c3_w old_wag = u3C.wag_w; - u3C.wag_w &= ~u3o_debug_cpu; - u3C.wag_w &= ~u3o_trace; - - static int home = 0; - static int away = 0; - - // Profile sampling, because it allocates on the home road, - // only works on when we're not at home. - // - if ( &(u3H->rod_u) != u3R ) { - home++; - c3_l mot_l; - u3a_road* rod_u; - - if ( _(u3T.mal_o) ) { - mot_l = c3_s3('m','a','l'); - } - else if ( _(u3T.coy_o) ) { - mot_l = c3_s3('c','o','y'); - } - else if ( _(u3T.euq_o) ) { - mot_l = c3_s3('e','u','q'); - } - else if ( _(u3T.far_o) ) { - mot_l = c3_s3('f','a','r'); - } - else if ( _(u3T.noc_o) ) { - c3_assert(!_(u3T.glu_o)); - mot_l = c3_s3('n','o','c'); - } - else if ( _(u3T.glu_o) ) { - mot_l = c3_s3('g','l','u'); - } - else { - mot_l = c3_s3('f','u','n'); - } - - rod_u = u3R; - u3R = &(u3H->rod_u); - { - u3_noun lab = _t_samp_process(rod_u); - - c3_assert(u3R == &u3H->rod_u); - if ( 0 == u3R->pro.day ) { - /* bunt a +doss - */ - u3R->pro.day = u3nt(u3nq(0, 0, 0, u3nq(0, 0, 0, 0)), 0, 0); - } - u3R->pro.day = u3dt("pi-noon", mot_l, lab, u3R->pro.day); - } - u3R = rod_u; - } - else { - away++; - // fprintf(stderr,"home: %06d away: %06d\r\n", home, away); - } - u3C.wag_w = old_wag; -} - -/* u3t_come(): push on profile stack; return yes if active push. RETAIN. -*/ -c3_o -u3t_come(u3_noun lab) -{ - if ( (u3_nul == u3R->pro.don) || !_(u3r_sing(lab, u3h(u3R->pro.don))) ) { - u3a_gain(lab); - _ct_lop_o = c3y; - u3R->pro.don = u3nc(lab, u3R->pro.don); - _ct_lop_o = c3n; - return c3y; - } - else return c3n; -} - -/* u3t_flee(): pop off profile stack. -*/ -void -u3t_flee(void) -{ - _ct_lop_o = c3y; - u3_noun don = u3R->pro.don; - u3R->pro.don = u3k(u3t(don)); - _ct_lop_o = c3n; - u3z(don); -} - -/* u3t_trace_open(): opens a trace file and writes the preamble. -*/ -void -u3t_trace_open(c3_c* dir_c) -{ - c3_c fil_c[2048]; - snprintf(fil_c, 2048, "%s/.urb/put/trace", dir_c); - - struct stat st; - if ( -1 == stat(fil_c, &st) ) { - c3_mkdir(fil_c, 0700); - } - - c3_c lif_c[2056]; - snprintf(lif_c, 2056, "%s/%d.json", fil_c, u3_Host.tra_u.fun_w); - - u3_Host.tra_u.fil_u = c3_fopen(lif_c, "w"); - u3_Host.tra_u.nid_w = (int)getpid(); - - fprintf(u3_Host.tra_u.fil_u, "[ "); - - // We have two "threads", the event processing and the nock stuff. - // tid 1 = event processing - // tid 2 = nock processing - fprintf(u3_Host.tra_u.fil_u, - "{\"name\": \"process_name\", \"ph\": \"M\", \"pid\": %d, \"args\": " - "{\"name\": \"urbit\"}},\n", - u3_Host.tra_u.nid_w); - fprintf(u3_Host.tra_u.fil_u, - "{\"name\": \"thread_name\", \"ph\": \"M\", \"pid\": %d, \"tid\": 1, " - "\"args\": {\"name\": \"Event Processing\"}},\n", - u3_Host.tra_u.nid_w); - fprintf(u3_Host.tra_u.fil_u, - "{\"name\": \"thread_sort_index\", \"ph\": \"M\", \"pid\": %d, " - "\"tid\": 1, \"args\": {\"sort_index\": 1}},\n", - u3_Host.tra_u.nid_w); - fprintf(u3_Host.tra_u.fil_u, - "{\"name\": \"thread_name\", \"ph\": \"M\", \"pid\": %d, \"tid\": 2, " - "\"args\": {\"name\": \"Nock\"}},\n", - u3_Host.tra_u.nid_w); - fprintf(u3_Host.tra_u.fil_u, - "{\"name\": \"thread_sort_index\", \"ph\": \"M\", \"pid\": %d, " - "\"tid\": 2, \"args\": {\"sort_index\": 2}},\n", - u3_Host.tra_u.nid_w); - u3_Host.tra_u.con_w = 5; -} - -/* u3t_trace_close(): closes a trace file. optional. -*/ -void -u3t_trace_close() -{ - if (!u3_Host.tra_u.fil_u) - return; - - // We don't terminate the JSON because of the file format. - fclose(u3_Host.tra_u.fil_u); - u3_Host.tra_u.con_w = 0; - u3_Host.tra_u.fun_w++; -} - -/* u3t_trace_time(): microsecond clock -*/ -c3_d u3t_trace_time() -{ - struct timeval tim_tv; - gettimeofday(&tim_tv, 0); - return 1000000ULL * tim_tv.tv_sec + tim_tv.tv_usec; -} - -/* u3t_nock_trace_push(): push a trace onto the trace stack; returns yes if pushed. - * - * The trace stack is a stack of [path time-entered]. - */ -c3_o -u3t_nock_trace_push(u3_noun lab) -{ - if (!u3_Host.tra_u.fil_u) - return c3n; - - if ( (u3_nul == u3R->pro.trace) || - !_(u3r_sing(lab, u3h(u3h(u3R->pro.trace)))) ) { - u3a_gain(lab); - c3_d time = u3t_trace_time(); - u3R->pro.trace = u3nc(u3nc(lab, u3i_chubs(1, &time)), u3R->pro.trace); - return c3y; - } - else { - return c3n; - } -} - -/* u3t_nock_trace_pop(): pops a trace from the trace stack. - * - * When we remove the trace from the stack, we check to see if the sample is - * large enough to process, as we'll otherwise keep track of individual +add - * calls. If it is, we write it out to the tracefile. - */ -void -u3t_nock_trace_pop() -{ - if (!u3_Host.tra_u.fil_u) - return; - - u3_noun trace = u3R->pro.trace; - u3R->pro.trace = u3k(u3t(trace)); - - u3_noun item = u3h(trace); - u3_noun lab = u3h(item); - c3_d start_time = u3r_chub(0, u3t(item)); - - // 33microseconds (a 30th of a millisecond). - c3_d duration = u3t_trace_time() - start_time; - if (duration > 33) { - c3_c* name = u3m_pretty_path(lab); - - fprintf(u3_Host.tra_u.fil_u, - "{\"cat\": \"nock\", \"name\": \"%s\", \"ph\":\"%c\", \"pid\": %d, " - "\"tid\": 2, \"ts\": %" PRIu64 ", \"dur\": %" PRIu64 "}, \n", - name, - 'X', - u3_Host.tra_u.nid_w, - start_time, - duration); - - c3_free(name); - u3_Host.tra_u.con_w++; - } - - u3z(trace); -} - -/* u3t_event_trace(): dumps a simple event from outside nock. -*/ -void -u3t_event_trace(const c3_c* name, c3_c type) -{ - if (!u3_Host.tra_u.fil_u) - return; - - fprintf(u3_Host.tra_u.fil_u, - "{\"cat\": \"event\", \"name\": \"%s\", \"ph\":\"%c\", \"pid\": %d, " - "\"tid\": 1, \"ts\": %" PRIu64 ", \"id\": \"0x100\"}, \n", - name, - type, - u3_Host.tra_u.nid_w, - u3t_trace_time()); - u3_Host.tra_u.con_w++; -} - -/* u3t_print_steps: print step counter. -*/ -void -u3t_print_steps(FILE* fil_u, c3_c* cap_c, c3_d sep_d) -{ - c3_assert( 0 != fil_u ); - - c3_w gib_w = (sep_d / 1000000000ULL); - c3_w mib_w = (sep_d % 1000000000ULL) / 1000000ULL; - c3_w kib_w = (sep_d % 1000000ULL) / 1000ULL; - c3_w bib_w = (sep_d % 1000ULL); - - // XX prints to stderr since it's called on shutdown, daemon may be gone - // - if ( sep_d ) { - if ( gib_w ) { - fprintf(fil_u, "%s: G/%d.%03d.%03d.%03d\r\n", - cap_c, gib_w, mib_w, kib_w, bib_w); - } - else if ( mib_w ) { - fprintf(fil_u, "%s: M/%d.%03d.%03d\r\n", cap_c, mib_w, kib_w, bib_w); - } - else if ( kib_w ) { - fprintf(fil_u, "%s: K/%d.%03d\r\n", cap_c, kib_w, bib_w); - } - else if ( bib_w ) { - fprintf(fil_u, "%s: %d\r\n", cap_c, bib_w); - } - } -} - -/* u3t_damp(): print and clear profile data. -*/ -void -u3t_damp(FILE* fil_u) -{ - c3_assert( 0 != fil_u ); - - if ( 0 != u3R->pro.day ) { - u3_noun wol = u3do("pi-tell", u3R->pro.day); - - // XX prints to stderr since it's called on shutdown, daemon may be gone - // - { - u3_noun low = wol; - - while ( u3_nul != low ) { - c3_c* str_c = (c3_c*)u3r_tape(u3h(low)); - fputs(str_c, fil_u); - fputs("\r\n", fil_u); - - c3_free(str_c); - low = u3t(low); - } - - u3z(wol); - } - - /* bunt a +doss - */ - u3R->pro.day = u3nt(u3nq(0, 0, 0, u3nq(0, 0, 0, 0)), 0, 0); - } - - u3t_print_steps(fil_u, "nocks", u3R->pro.nox_d); - u3t_print_steps(fil_u, "cells", u3R->pro.cel_d); - - u3R->pro.nox_d = 0; - u3R->pro.cel_d = 0; -} - -/* _ct_sigaction(): profile sigaction callback. -*/ -void _ct_sigaction(c3_i x_i) -{ - u3t_samp(); -} - -/* u3t_init(): initialize tracing layer. -*/ -void -u3t_init(void) -{ - u3T.noc_o = c3n; - u3T.glu_o = c3n; - u3T.mal_o = c3n; - u3T.far_o = c3n; - u3T.coy_o = c3n; - u3T.euq_o = c3n; -} - -/* u3t_boot(): turn sampling on. -*/ -void -u3t_boot(void) -{ - if ( u3C.wag_w & u3o_debug_cpu ) { - _ct_lop_o = c3n; -#if defined(U3_OS_PROF) - // skip profiling if we don't yet have an arvo kernel - // - if ( 0 == u3A->roc ) { - return; - } - - // Register _ct_sigaction to be called on `SIGPROF`. - { - struct sigaction sig_s = {{0}}; - sig_s.sa_handler = _ct_sigaction; - sigemptyset(&(sig_s.sa_mask)); - sigaction(SIGPROF, &sig_s, 0); - } - - // Unblock `SIGPROF` for this thread (we will block it again when `u3t_boff` is called). - { - sigset_t set; - sigemptyset(&set); - sigaddset(&set, SIGPROF); - if ( 0 != pthread_sigmask(SIG_UNBLOCK, &set, NULL) ) { - u3l_log("trace: thread mask SIGPROF: %s", strerror(errno)); - } - } - - // Ask for SIGPROF to be sent every 10ms. - { - struct itimerval itm_v = {{0}}; - itm_v.it_interval.tv_usec = 10000; - itm_v.it_value = itm_v.it_interval; - setitimer(ITIMER_PROF, &itm_v, 0); - } -#endif - } -} - -/* u3t_boff(): turn profile sampling off. -*/ -void -u3t_boff(void) -{ - if ( u3C.wag_w & u3o_debug_cpu ) { -#if defined(U3_OS_PROF) - // Mask SIGPROF signals in this thread (and this is the only - // thread that unblocked them). - { - sigset_t set; - sigemptyset(&set); - sigaddset(&set, SIGPROF); - if ( 0 != pthread_sigmask(SIG_BLOCK, &set, NULL) ) { - u3l_log("trace: thread mask SIGPROF: %s", strerror(errno)); - } - } - - // Disable the SIGPROF timer. - { - struct itimerval itm_v = {{0}}; - setitimer(ITIMER_PROF, &itm_v, 0); - } - - // Ignore SIGPROF signals. - { - struct sigaction sig_s = {{0}}; - sigemptyset(&(sig_s.sa_mask)); - sig_s.sa_handler = SIG_IGN; - sigaction(SIGPROF, &sig_s, 0); - } -#endif - } -} - - -/* u3t_slog_cap(): slog a tank with a caption with -** a given priority c3_l (assumed 0-3). -*/ -void -u3t_slog_cap(c3_l pri_l, u3_noun cap, u3_noun tan) -{ - u3t_slog( - u3nc( - pri_l, - u3nt( - c3__rose, - u3nt(u3nt(':', ' ', u3_nul), u3_nul, u3_nul), - u3nt(cap, tan, u3_nul) - ) - ) - ); -} - - -/* u3t_slog_trace(): given a c3_l priority pri and a raw stack tax -** flop the order into start-to-end, render, and slog each item -** until done. -*/ -void -u3t_slog_trace(c3_l pri_l, u3_noun tax) -{ - // render the stack - // Note: ton is a reference to a data struct - // we have just allocated - // lit is a used as a moving cursor pointer through - // that allocated struct - // once we finish lit will be null, but ton will still - // point to the whole valid allocated data structure - // and thus we can free it safely at the end of the func - // to clean up after ourselves. - // Note: flop reverses the stack trace list 'tax' - u3_noun ton = u3dc("mook", 2, u3kb_flop(tax)); - u3_noun lit = u3t(ton); - - // print the stack one stack item at a time - while ( u3_nul != lit ) { - u3t_slog(u3nc(pri_l, u3k(u3h(lit)) )); - lit = u3t(lit); - } - - u3z(ton); -} - - -/* u3t_slog_nara(): slog only the deepest road's trace with -** c3_l priority pri -*/ -void -u3t_slog_nara(c3_l pri_l) -{ - u3_noun tax = u3k(u3R->bug.tax); - u3t_slog_trace(pri_l, tax); -} - - -/* u3t_slog_hela(): join all roads' traces together into one tax -** and pass it to slog_trace along with the given c3_l priority pri_l -*/ -void -u3t_slog_hela(c3_l pri_l) -{ - // rod_u protects us from mutating the global state - u3_road* rod_u = u3R; - - // inits to the the current road's trace - u3_noun tax = u3k(rod_u->bug.tax); - - // while there is a parent road ref ... - while ( &(u3H->rod_u) != rod_u ) { - // ... point at the next road and append its stack to tax - rod_u = u3tn(u3_road, rod_u->par_p); - tax = u3kb_weld(tax, u3k(rod_u->bug.tax)); - } - - u3t_slog_trace(pri_l, tax); -} - diff --git a/pkg/urbit/noun/urth.c b/pkg/urbit/noun/urth.c deleted file mode 100644 index 30ab44817..000000000 --- a/pkg/urbit/noun/urth.c +++ /dev/null @@ -1,908 +0,0 @@ -/* noun/urth.c -** -*/ -#include "all.h" -#include "ur/ur.h" -#include -#include -#include -#include - -/* _cu_atom_to_ref(): allocate indirect atom off-loom. -*/ -static inline ur_nref -_cu_atom_to_ref(ur_root_t* rot_u, u3a_atom* vat_u) -{ - ur_nref ref; - c3_d val_d; - - switch ( vat_u->len_w ) { - case 2: { - val_d = ((c3_d)vat_u->buf_w[1]) << 32 - | ((c3_d)vat_u->buf_w[0]); - ref = ur_coin64(rot_u, val_d); - } break; - - case 1: { - val_d = (c3_d)vat_u->buf_w[0]; - ref = ur_coin64(rot_u, val_d); - } break; - - default: { - // XX assumes little-endian - // - c3_y* byt_y = (c3_y*)vat_u->buf_w; - c3_d len_d = ((c3_d)vat_u->len_w) << 2; - - c3_assert( len_d ); - - // NB: this call will account for any trailing null bytes - // caused by an overestimate in [len_d] - // - ref = ur_coin_bytes(rot_u, len_d, byt_y); - } break; - } - - return ref; -} - -/* _cu_box_check(): check loom allocation box for relocation pointer. -*/ -static inline c3_o -_cu_box_check(u3a_noun* som_u, ur_nref* ref) -{ - u3a_box* box_u = u3a_botox(som_u); - c3_w* box_w = (void*)box_u; - - if ( 0xffffffff == box_w[0] ) { - *ref = ( ((c3_d)box_w[2]) << 32 - | ((c3_d)box_w[1]) ); - return c3y; - } - - return c3n; -} - -/* _cu_box_stash(): overwrite an allocation box with relocation pointer. -*/ -static inline void -_cu_box_stash(u3a_noun* som_u, ur_nref ref) -{ - u3a_box* box_u = u3a_botox(som_u); - c3_w* box_w = (void*)box_u; - - // overwrite u3a_atom with reallocated reference - // - box_w[0] = 0xffffffff; - box_w[1] = ref & 0xffffffff; - box_w[2] = ref >> 32; -} - -/* -** stack frame for recording head vs tail iteration -** -** $? [LOM_HEAD cell=*] -** [ref=* cell=*] -*/ - -#define LOM_HEAD 0xffffffffffffffffULL - -typedef struct _cu_frame_s -{ - ur_nref ref; - u3a_cell* cel_u; -} _cu_frame; - -typedef struct _cu_stack_s -{ - c3_w pre_w; - c3_w siz_w; - c3_w fil_w; - _cu_frame* fam_u; -} _cu_stack; - -/* _cu_from_loom_next(): advance off-loom reallocation traversal. -*/ -static inline ur_nref -_cu_from_loom_next(_cu_stack* tac_u, ur_root_t* rot_u, u3_noun a) -{ - while ( 1 ) { - // u3 direct == ur direct - // - if ( c3y == u3a_is_cat(a) ) { - return (ur_nref)a; - } - else { - u3a_noun* som_u = u3a_to_ptr(a); - ur_nref ref; - - // check for relocation pointers - // - if ( c3y == _cu_box_check(som_u, &ref) ) { - return ref; - } - // reallocate indirect atoms, stashing relocation pointers - // - else if ( c3y == u3a_is_atom(a) ) { - ref = _cu_atom_to_ref(rot_u, (u3a_atom*)som_u); - _cu_box_stash(som_u, ref); - return ref; - } - else { - u3a_cell* cel_u = (u3a_cell*)som_u; - - // reallocate the stack if full - // - if ( tac_u->fil_w == tac_u->siz_w ) { - c3_w nex_w = tac_u->pre_w + tac_u->siz_w; - tac_u->fam_u = c3_realloc(tac_u->fam_u, nex_w * sizeof(*tac_u->fam_u)); - tac_u->pre_w = tac_u->siz_w; - tac_u->siz_w = nex_w; - } - - // push a head-frame and continue into the head - // - { - _cu_frame* fam_u = &(tac_u->fam_u[tac_u->fil_w++]); - fam_u->ref = LOM_HEAD; - fam_u->cel_u = cel_u; - } - - a = cel_u->hed; - continue; - } - } - } -} - -/* _cu_from_loom(): reallocate [a] off loom, in [r]. -*/ -static ur_nref -_cu_from_loom(ur_root_t* rot_u, u3_noun a) -{ - _cu_stack tac_u = {0}; - ur_nref ref; - - tac_u.pre_w = ur_fib10; - tac_u.siz_w = ur_fib11; - tac_u.fam_u = c3_malloc(tac_u.siz_w * sizeof(*tac_u.fam_u)); - - ref = _cu_from_loom_next(&tac_u, rot_u, a); - - // incorporate reallocated ref, accounting for cells - // - while ( tac_u.fil_w ) { - // peek at the top of the stack - // - _cu_frame* fam_u = &(tac_u.fam_u[tac_u.fil_w - 1]); - - // [fam_u] is a head-frame; stash ref and continue into the tail - // - if ( LOM_HEAD == fam_u->ref ) { - fam_u->ref = ref; - ref = _cu_from_loom_next(&tac_u, rot_u, fam_u->cel_u->tel); - } - // [fam_u] is a tail-frame; cons refs and pop the stack - // - else { - ref = ur_cons(rot_u, fam_u->ref, ref); - _cu_box_stash((u3a_noun*)fam_u->cel_u, ref); - tac_u.fil_w--; - } - } - - c3_free(tac_u.fam_u); - - return ref; -} - -/* _cu_vec: parameters for cold-state hamt walk. -*/ -typedef struct _cu_vec_s { - ur_nvec_t* vec_u; - ur_root_t* rot_u; -} _cu_vec; - -/* _cu_hamt_walk(): reallocate key/value pair in hamt walk. -*/ -static void -_cu_hamt_walk(u3_noun kev, void* ptr) -{ - _cu_vec* dat_u = (_cu_vec*)ptr; - ur_nvec_t* vec_u = dat_u->vec_u; - ur_root_t* rot_u = dat_u->rot_u; - - vec_u->refs[vec_u->fill++] = _cu_from_loom(rot_u, kev); -} - -/* _cu_all_from_loom(): reallocate essential persistent state off-loom. -** -** NB: destroys the loom. -*/ -static ur_nref -_cu_all_from_loom(ur_root_t* rot_u, ur_nvec_t* cod_u) -{ - ur_nref ken = _cu_from_loom(rot_u, u3A->roc); - c3_w cod_w = u3h_wyt(u3R->jed.cod_p); - _cu_vec dat_u = { .vec_u = cod_u, .rot_u = rot_u }; - - ur_nvec_init(cod_u, cod_w); - u3h_walk_with(u3R->jed.cod_p, _cu_hamt_walk, &dat_u); - - return ken; -} - -typedef struct _cu_loom_s { - ur_dict32_t map_u; // direct->indirect mapping - u3_atom *vat; // indirect atoms - u3_noun *cel; // cells -} _cu_loom; - -/* _cu_ref_to_noun(): lookup/allocate [ref] on the loom. -*/ -static u3_noun -_cu_ref_to_noun(ur_root_t* rot_u, ur_nref ref, _cu_loom* lom_u) -{ - switch ( ur_nref_tag(ref) ) { - default: c3_assert(0); - - // all ur indirect atoms have been pre-reallocated on the loom. - // - case ur_iatom: return lom_u->vat[ur_nref_idx(ref)]; - - - // cells were allocated off-loom in cons-order, and are traversed - // in the same order: we've already relocated any one we could need here. - // - case ur_icell: return lom_u->cel[ur_nref_idx(ref)]; - - // u3 direct atoms are 31-bit, while ur direct atoms are 62-bit; - // we use a hashtable to deduplicate the non-overlapping space - // - case ur_direct: { - u3_atom vat; - - if ( 0x7fffffffULL >= ref ) { - return (u3_atom)ref; - } - else if ( ur_dict32_get(rot_u, &lom_u->map_u, ref, (c3_w*)&vat) ) { - return vat; - } - else { - { - c3_w wor_w[2] = { ref & 0xffffffff, ref >> 32 }; - vat = (c3_w)u3i_words(2, wor_w); - } - - ur_dict32_put(0, &lom_u->map_u, ref, (c3_w)vat); - return vat; - } - } break; - } -} - -/* _cu_all_to_loom(): reallocate all of [rot_u] on the loom, restore roots. -** NB: requires all roots to be cells -** does *not* track refcounts, which must be -** subsequently reconstructed via tracing. -*/ -static void -_cu_all_to_loom(ur_root_t* rot_u, ur_nref ken, ur_nvec_t* cod_u) -{ - _cu_loom lom_u = {0}; - c3_d i_d, fil_d; - - ur_dict32_grow(0, &lom_u.map_u, ur_fib11, ur_fib12); - - // allocate all atoms on the loom. - // - { - c3_d* len_d = rot_u->atoms.lens; - c3_y** byt_y = rot_u->atoms.bytes; - - fil_d = rot_u->atoms.fill; - lom_u.vat = calloc(fil_d, sizeof(u3_atom)); - - for ( i_d = 0; i_d < fil_d; i_d++ ) { - lom_u.vat[i_d] = u3i_bytes(len_d[i_d], byt_y[i_d]); - } - } - - // allocate all cells on the loom. - // - { - ur_nref* hed = rot_u->cells.heads; - ur_nref* tal = rot_u->cells.tails; - u3_noun cel; - - fil_d = rot_u->cells.fill; - lom_u.cel = c3_calloc(fil_d * sizeof(u3_noun)); - - for ( i_d = 0; i_d < fil_d; i_d++ ) { - cel = u3nc(_cu_ref_to_noun(rot_u, hed[i_d], &lom_u), - _cu_ref_to_noun(rot_u, tal[i_d], &lom_u)); - lom_u.cel[i_d] = cel; - u3r_mug(cel); - } - } - - // restore kernel reference (always a cell) - // - u3A->roc = lom_u.cel[ur_nref_idx(ken)]; - - // restore cold jet state (always cells) - // - { - c3_d max_d = cod_u->fill; - c3_d i_d; - ur_nref ref; - u3_noun kev; - - for ( i_d = 0; i_d < max_d; i_d++) { - ref = cod_u->refs[i_d]; - kev = lom_u.cel[ur_nref_idx(ref)]; - u3h_put(u3R->jed.cod_p, u3h(kev), u3k(u3t(kev))); - u3z(kev); - } - } - - // dispose of relocation pointers - // - c3_free(lom_u.cel); - c3_free(lom_u.vat); - ur_dict_free((ur_dict_t*)&lom_u.map_u); -} - -/* _cu_realloc(): hash-cons roots off-loom, reallocate on loom. -*/ -static ur_nref -_cu_realloc(FILE* fil_u, ur_root_t** tor_u, ur_nvec_t* doc_u) -{ -#ifdef U3_MEMORY_DEBUG - c3_assert(0); -#endif - - // bypassing page tracking as an optimization - // - // NB: u3e_yolo() will mark all as dirty, and - // u3e_save() will reinstate protection flags - // - if ( c3n == u3e_yolo() ) { - if ( fil_u ) { - fprintf(fil_u, "uniq: unable to bypass page tracking, continuing\r\n"); - } - } - - // stash event number - // - c3_d eve_d = u3A->eve_d; - - // reallocate kernel and cold jet state - // - ur_root_t* rot_u = ur_root_init(); - ur_nvec_t cod_u; - ur_nref ken = _cu_all_from_loom(rot_u, &cod_u); - - // print [rot_u] measurements - // - if ( fil_u ) { - ur_root_info(fil_u, rot_u); - fprintf(fil_u, "\r\n"); - } - - // reinitialize loom - // - // NB: hot jet state is not yet re-established - // - u3m_pave(c3y); - - // reallocate all nouns on the loom - // - _cu_all_to_loom(rot_u, ken, &cod_u); - - // allocate new hot jet state - // - u3j_boot(c3y); - - // establish correct refcounts via tracing - // - u3m_grab(u3_none); - - // re-establish warm jet state - // - u3j_ream(); - - // restore event number - // - u3A->eve_d = eve_d; - - // mark all pages dirty - // - u3e_foul(); - - *tor_u = rot_u; - *doc_u = cod_u; - - return ken; -} - -/* u3u_meld(): globally deduplicate memory. -*/ -#ifdef U3_MEMORY_DEBUG -void -u3u_meld(void) -{ - fprintf(stderr, "u3: unable to meld under U3_MEMORY_DEBUG\r\n"); -} -#else -void -u3u_meld(void) -{ - ur_root_t* rot_u; - ur_nvec_t cod_u; - - c3_assert( &(u3H->rod_u) == u3R ); - - _cu_realloc(stderr, &rot_u, &cod_u); - - // dispose off-loom structures - // - ur_nvec_free(&cod_u); - ur_root_free(rot_u); -} -#endif - -/* _cu_rock_path(): format rock path. -*/ -static c3_o -_cu_rock_path(c3_c* dir_c, c3_d eve_d, c3_c** out_c) -{ - c3_w nam_w = 1 + snprintf(0, 0, "%s/.urb/roc/%" PRIu64 ".jam", dir_c, eve_d); - c3_c* nam_c = c3_malloc(nam_w); - c3_i ret_i; - - ret_i = snprintf(nam_c, nam_w, "%s/.urb/roc/%" PRIu64 ".jam", dir_c, eve_d); - - if ( ret_i < 0 ) { - fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): %s\r\n", - dir_c, eve_d, strerror(errno)); - c3_free(nam_c); - return c3n; - } - else if ( ret_i >= nam_w ) { - fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): truncated\r\n", - dir_c, eve_d); - c3_free(nam_c); - return c3n; - } - - *out_c = nam_c; - return c3y; -} - -/* _cu_rock_path_make(): format rock path, creating directory if necessary.. -*/ -static c3_o -_cu_rock_path_make(c3_c* dir_c, c3_d eve_d, c3_c** out_c) -{ - c3_w nam_w = 1 + snprintf(0, 0, "%s/.urb/roc/%" PRIu64 ".jam", dir_c, eve_d); - c3_c* nam_c = c3_malloc(nam_w); - c3_i ret_i; - - // create $pier/.urb/roc, if it doesn't exist - // - // NB, $pier/.urb is guaranteed to already exist - // - { - ret_i = snprintf(nam_c, nam_w, "%s/.urb/roc", dir_c); - - if ( ret_i < 0 ) { - fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): %s\r\n", - dir_c, eve_d, strerror(errno)); - c3_free(nam_c); - return c3n; - } - else if ( ret_i >= nam_w ) { - fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): truncated\r\n", - dir_c, eve_d); - c3_free(nam_c); - return c3n; - } - - if ( c3_mkdir(nam_c, 0700) - && (EEXIST != errno) ) - { - fprintf(stderr, "rock: directory create failed (%s, %" PRIu64 "): %s\r\n", - dir_c, eve_d, strerror(errno)); - c3_free(nam_c); - return c3n; - } - } - - ret_i = snprintf(nam_c, nam_w, "%s/.urb/roc/%" PRIu64 ".jam", dir_c, eve_d); - - if ( ret_i < 0 ) { - fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): %s\r\n", - dir_c, eve_d, strerror(errno)); - c3_free(nam_c); - return c3n; - } - else if ( ret_i >= nam_w ) { - fprintf(stderr, "rock: path format failed (%s, %" PRIu64 "): truncated\r\n", - dir_c, eve_d); - c3_free(nam_c); - return c3n; - } - - *out_c = nam_c; - return c3y; -} - -static c3_o -_cu_rock_save(c3_c* dir_c, c3_d eve_d, c3_d len_d, c3_y* byt_y) -{ - c3_i fid_i; - - // open rock file, creating the containing directory if necessary - // - { - c3_c* nam_c; - - if ( c3n == _cu_rock_path_make(dir_c, eve_d, &nam_c) ) { - return c3n; - } - - if ( -1 == (fid_i = c3_open(nam_c, O_RDWR | O_CREAT | O_TRUNC, 0644)) ) { - fprintf(stderr, "rock: c3_open failed (%s, %" PRIu64 "): %s\r\n", - dir_c, eve_d, strerror(errno)); - c3_free(nam_c); - return c3n; - } - - c3_free(nam_c); - } - - // write jam-buffer into [fid_i] - // - // XX deduplicate with _write() wrapper in term.c - // - { - ssize_t ret_i; - - while ( len_d > 0 ) { - c3_w lop_w = 0; - // retry interrupt/async errors - // - do { - // abort pathological retry loop - // - if ( 100 == ++lop_w ) { - fprintf(stderr, "rock: write loop: %s\r\n", strerror(errno)); - close(fid_i); - // XX unlink file? - // - return c3n; - } - - ret_i = write(fid_i, byt_y, len_d); - } - while ( (ret_i < 0) - && ( (errno == EINTR) - || (errno == EAGAIN) - || (errno == EWOULDBLOCK) )); - - // assert on true errors - // - // NB: can't call u3l_log here or we would re-enter _write() - // - if ( ret_i < 0 ) { - fprintf(stderr, "rock: write failed %s\r\n", strerror(errno)); - close(fid_i); - // XX unlink file? - // - return c3n; - } - // continue partial writes - // - else { - len_d -= ret_i; - byt_y += ret_i; - } - } - } - - close(fid_i); - - return c3y; -} - -/* u3u_cram(): globably deduplicate memory, and write a rock to disk. -*/ -#ifdef U3_MEMORY_DEBUG -c3_o -u3u_cram(c3_c* dir_c, c3_d eve_d) -{ - fprintf(stderr, "u3: unable to cram under U3_MEMORY_DEBUG\r\n"); - return c3n; -} -#else -c3_o -u3u_cram(c3_c* dir_c, c3_d eve_d) -{ - c3_o ret_o = c3y; - c3_d len_d; - c3_y* byt_y; - - c3_assert( &(u3H->rod_u) == u3R ); - - { - ur_root_t* rot_u; - ur_nvec_t cod_u; - ur_nref ken = _cu_realloc(stderr, &rot_u, &cod_u); - - { - ur_nref roc = u3_nul; - c3_d max_d = cod_u.fill; - c3_d i_d; - - // cons vector of cold jet-state entries onto a list - // - for ( i_d = 0; i_d < max_d; i_d++) { - roc = ur_cons(rot_u, cod_u.refs[i_d], roc); - } - - { - c3_c* has_c = "hashboard"; - ur_nref has = ur_coin_bytes(rot_u, strlen(has_c), (c3_y*)has_c); - roc = ur_cons(rot_u, has, roc); - } - - roc = ur_cons(rot_u, ur_coin64(rot_u, c3__arvo), - ur_cons(rot_u, ken, roc)); - - ur_jam(rot_u, roc, &len_d, &byt_y); - } - - // dispose off-loom structures - // - ur_nvec_free(&cod_u); - ur_root_free(rot_u); - } - - // write jam-buffer into pier - // - if ( c3n == _cu_rock_save(dir_c, eve_d, len_d, byt_y) ) { - ret_o = c3n; - } - - c3_free(byt_y); - - return ret_o; -} -#endif - -/* u3u_mmap_read(): open and mmap the file at [pat_c] for reading. -*/ -c3_o -u3u_mmap_read(c3_c* cap_c, c3_c* pat_c, c3_d* out_d, c3_y** out_y) -{ - c3_i fid_i; - c3_d len_d; - - // open file - // - if ( -1 == (fid_i = c3_open(pat_c, O_RDONLY, 0644)) ) { - fprintf(stderr, "%s: c3_open failed (%s): %s\r\n", - cap_c, pat_c, strerror(errno)); - return c3n; - } - - // measure file - // - { - struct stat buf_b; - - if ( -1 == fstat(fid_i, &buf_b) ) { - fprintf(stderr, "%s: stat failed (%s): %s\r\n", - cap_c, pat_c, strerror(errno)); - close(fid_i); - return c3n; - } - - len_d = buf_b.st_size; - } - - // mmap file - // - { - void* ptr_v; - - if ( MAP_FAILED == (ptr_v = mmap(0, len_d, PROT_READ, MAP_SHARED, fid_i, 0)) ) { - fprintf(stderr, "%s: mmap failed (%s): %s\r\n", - cap_c, pat_c, strerror(errno)); - close(fid_i); - return c3n; - } - - *out_d = len_d; - *out_y = (c3_y*)ptr_v; - } - - // close file - // - close(fid_i); - - return c3y; -} - -/* u3u_mmap(): open/create file-backed mmap at [pat_c] for read/write. -*/ -c3_o -u3u_mmap(c3_c* cap_c, c3_c* pat_c, c3_d len_d, c3_y** out_y) -{ - c3_i fid_i; - - // open file - // - if ( -1 == (fid_i = c3_open(pat_c, O_RDWR | O_CREAT | O_TRUNC, 0644)) ) { - fprintf(stderr, "%s: c3_open failed (%s): %s\r\n", - cap_c, pat_c, strerror(errno)); - return c3n; - } - - // grow [fid_i] to [len_w] - // - // XX build with _FILE_OFFSET_BITS == 64 ? - // - if ( 0 != ftruncate(fid_i, len_d) ) { - fprintf(stderr, "%s: ftruncate grow %s: %s\r\n", - cap_c, pat_c, strerror(errno)); - close(fid_i); - return c3n; - } - - // mmap file - // - { - void* ptr_v; - - if ( MAP_FAILED == (ptr_v = mmap(0, len_d, PROT_READ|PROT_WRITE, MAP_SHARED, fid_i, 0)) ) { - fprintf(stderr, "%s: mmap failed (%s): %s\r\n", - cap_c, pat_c, strerror(errno)); - close(fid_i); - return c3n; - } - - *out_y = (c3_y*)ptr_v; - } - - // close file - // - close(fid_i); - - return c3y; -} - -/* u3u_mmap_save(): sync file-backed mmap. -*/ -c3_o -u3u_mmap_save(c3_c* cap_c, c3_c* pat_c, c3_d len_d, c3_y* byt_y) -{ - if ( 0 != msync(byt_y, len_d, MS_SYNC) ) { - fprintf(stderr, "%s: msync %s: %s\r\n", cap_c, pat_c, strerror(errno)); - return c3n; - } - - return c3y; -} - -/* u3u_munmap(): unmap the region at [byt_y]. -*/ -c3_o -u3u_munmap(c3_d len_d, c3_y* byt_y) -{ - if ( 0 != munmap(byt_y, len_d) ) { - return c3n; - } - - return c3y; -} - -/* u3u_uncram(): restore persistent state from a rock. -*/ -c3_o -u3u_uncram(c3_c* dir_c, c3_d eve_d) -{ - c3_c* nam_c; - c3_d len_d; - c3_y* byt_y; - - // load rock file into buffer - // - if ( c3n == _cu_rock_path(dir_c, eve_d, &nam_c) ) { - fprintf(stderr, "uncram: failed to make rock path (%s, %" PRIu64 ")\r\n", - dir_c, eve_d); - return c3n; - } - else if ( c3n == u3u_mmap_read("rock", nam_c, &len_d, &byt_y) ) { - c3_free(nam_c); - return c3n; - } - - // bypassing page tracking as an optimization - // - // NB: u3e_yolo() will mark all as dirty, and - // u3e_save() will reinstate protection flags - // - if ( c3n == u3e_yolo() ) { - fprintf(stderr, "uncram: unable to bypass page tracking, continuing\r\n"); - } - - // reinitialize loom - // - // NB: hot jet state is not yet re-established - // - u3m_pave(c3y); - - // cue rock, restore persistent state - // - // XX errors are fatal, barring a full "u3m_reboot"-type operation. - // - { - // XX tune the initial dictionary size for less reallocation - // - u3_cue_xeno* sil_u = u3s_cue_xeno_init_with(ur_fib33, ur_fib34); - u3_weak ref = u3s_cue_xeno_with(sil_u, len_d, byt_y); - u3_noun roc, doc, tag, cod; - - u3s_cue_xeno_done(sil_u); - - if ( u3_none == ref ) { - fprintf(stderr, "uncram: failed to cue rock\r\n"); - c3_free(nam_c); - return c3n; - } - else if ( c3n == u3r_pq(ref, c3__arvo, &roc, &doc) - || (c3n == u3r_cell(doc, &tag, &cod)) - || (c3n == u3r_sing_c("hashboard", tag)) ) - { - fprintf(stderr, "uncram: failed: invalid rock format\r\n"); - u3z(ref); - c3_free(nam_c); - return c3n; - } - - u3A->roc = u3k(roc); - u3j_load(u3k(cod)); - - u3z(ref); - } - - u3u_munmap(len_d, byt_y); - - // allocate new hot jet state; re-establish warm - // - u3j_boot(c3y); - u3j_ream(); - - // restore event number - // - u3A->eve_d = eve_d; - - // mark all pages dirty - // - u3e_foul(); - - // leave rocks on disk - // - // if ( 0 != c3_unlink(nam_c) ) { - // fprintf(stderr, "uncram: failed to delete rock (%s, %" PRIu64 "): %s\r\n", - // dir_c, eve_d, strerror(errno)); - // c3_free(nam_c); - // return c3n; - // } - - c3_free(nam_c); - - return c3y; -} diff --git a/pkg/urbit/noun/vortex.c b/pkg/urbit/noun/vortex.c deleted file mode 100644 index 7b6eb0da4..000000000 --- a/pkg/urbit/noun/vortex.c +++ /dev/null @@ -1,349 +0,0 @@ -/* g/v.c -** -*/ -#include "all.h" -#include - -#define _CVX_LOAD 4 -#define _CVX_PEEK 22 -#define _CVX_POKE 23 -#define _CVX_WISH 10 - -/* u3v_life(): execute initial lifecycle, producing Arvo core. -*/ -u3_noun -u3v_life(u3_noun eve) -{ - u3_noun lyf = u3nt(2, u3nc(0, 3), u3nc(0, 2)); - u3_noun gat = u3n_nock_on(eve, lyf); - u3_noun cor = u3k(u3x_at(7, gat)); - - u3z(gat); - return cor; -} - -/* u3v_boot(): evaluate boot sequence, making a kernel -*/ -c3_o -u3v_boot(u3_noun eve) -{ - // ensure zero-initialized kernel - // - u3A->roc = 0; - - { - u3_noun pro = u3m_soft(0, u3v_life, eve); - - if ( u3_blip != u3h(pro) ) { - u3z(pro); - return c3n; - } - - u3A->roc = u3k(u3t(pro)); - u3z(pro); - } - - return c3y; -} - -/* _cv_lite(): load lightweight, core-only pill. -*/ -static u3_noun -_cv_lite(u3_noun pil) -{ - u3_noun eve, pro; - - { - u3_noun hed, tal; - u3x_cell(pil, &hed, &tal); - u3_assent( u3r_sing_c("ivory", hed) ); - eve = tal; - } - - u3l_log("lite: arvo formula %x", u3r_mug(pil)); - pro = u3v_life(u3k(eve)); - u3l_log("lite: core %x", u3r_mug(pro)); - - u3z(pil); - return pro; -} - -/* u3v_boot_lite(): light bootstrap sequence, just making a kernel. -*/ -c3_o -u3v_boot_lite(u3_noun pil) -{ - // ensure zero-initialized kernel - // - u3A->roc = 0; - - { - u3_noun pro = u3m_soft(0, _cv_lite, pil); - - if ( u3_blip != u3h(pro) ) { - u3z(pro); - return c3n; - } - - u3A->roc = u3k(u3t(pro)); - u3z(pro); - } - - u3l_log("lite: final state %x", u3r_mug(u3A->roc)); - - return c3y; -} - -/* _cv_nock_wish(): call wish through hardcoded interface. -*/ -static u3_noun -_cv_nock_wish(u3_noun txt) -{ - u3_noun fun, pro; - - fun = u3n_nock_on(u3k(u3A->roc), u3k(u3x_at(_CVX_WISH, u3A->roc))); - pro = u3n_slam_on(fun, txt); - - return pro; -} - -/* u3v_wish(): text expression with cache. -*/ -u3_noun -u3v_wish(const c3_c* str_c) -{ - u3t_event_trace("u3v_wish", 'b'); - u3_noun txt = u3i_string(str_c); - u3_weak exp = u3kdb_get(u3k(u3A->yot), u3k(txt)); - - if ( u3_none == exp ) { - exp = _cv_nock_wish(u3k(txt)); - - // It's probably not a good idea to use u3v_wish() - // outside the top level... (as the result is uncached) - // - if ( u3R == &u3H->rod_u ) { - u3A->yot = u3kdb_put(u3A->yot, u3k(txt), u3k(exp)); - } - } - - u3t_event_trace("u3v_wish", 'e'); - - u3z(txt); - return exp; -} - -/* u3v_do(): use a kernel gate. -*/ -u3_noun -u3v_do(const c3_c* txt_c, u3_noun sam) -{ - u3_noun gat = u3v_wish(txt_c); - u3_noun pro; - -#if 0 - if ( &u3H->rod_u == u3R ) { - pro = u3m_soft_slam(gat, sam); - } - else { - pro = u3n_slam_on(gat, sam); - } -#else - pro = u3n_slam_on(gat, sam); -#endif - - return pro; -} - -/* _cv_scot(): print atom. -*/ -static u3_noun -_cv_scot(u3_noun dim) -{ - return u3do("scot", dim); -} - -/* u3v_time(): set the reck time. -*/ -void -u3v_time(u3_noun now) -{ - u3z(u3A->now); - u3A->now = now; -} - -#if 0 -/* _cv_time_bump(): advance the reck time by a small increment. -*/ -static void -_cv_time_bump(u3_reck* rec_u) -{ - c3_d bum_d = (1ULL << 48ULL); - - u3A->now = u3ka_add(u3A->now, u3i_chubs(1, &bum_d)); -} -#endif - -/* u3v_lily(): parse little atom. -*/ -c3_o -u3v_lily(u3_noun fot, u3_noun txt, c3_l* tid_l) -{ - c3_w wad_w; - u3_noun uco = u3dc("slaw", fot, u3k(txt)); - u3_noun p_uco, q_uco; - - if ( (c3n == u3r_cell(uco, &p_uco, &q_uco)) || - (u3_nul != p_uco) || - (c3n == u3r_safe_word(q_uco, &wad_w)) || - (wad_w & 0x80000000) ) - { - u3l_log("strange lily %s", u3r_string(txt)); - u3z(txt); u3z(uco); return c3n; - } - else { - *tid_l = (c3_l)wad_w; - u3z(txt); u3z(uco); return c3y; - } -} - -/* u3v_peek(): query the reck namespace (protected). -*/ -u3_noun -u3v_peek(u3_noun sam) -{ - u3_noun fun = u3n_nock_on(u3k(u3A->roc), u3k(u3x_at(_CVX_PEEK, u3A->roc))); - return u3n_slam_on(fun, sam); -} - -/* u3v_soft_peek(): softly query the reck namespace. -*/ -u3_noun -u3v_soft_peek(c3_w mil_w, u3_noun sam) -{ - u3_noun gon = u3m_soft(mil_w, u3v_peek, sam); - u3_noun tag, dat; - u3x_cell(gon, &tag, &dat); - - // read failed, produce trace - // - // NB, reads *should not* fail deterministically - // - if ( u3_blip != tag ) { - return u3nc(c3n, gon); - } - - // read succeeded, produce result - // - { - u3_noun pro = u3nc(c3y, u3k(dat)); - u3z(gon); - return pro; - } -} - -/* u3v_poke(): insert and apply an input ovum (protected). -*/ -u3_noun -u3v_poke(u3_noun ovo) -{ - u3_noun fun = u3n_nock_on(u3k(u3A->roc), u3k(u3x_at(_CVX_POKE, u3A->roc))); - u3_noun sam = u3nc(u3k(u3A->now), ovo); - u3_noun pro; - - { - c3_w cod_w = u3a_lush(u3h(u3t(ovo))); - pro = u3n_slam_on(fun, sam); - u3a_lop(cod_w); - } - - return pro; -} - -/* u3v_tank(): dump single tank. -*/ -void -u3v_tank(u3_noun blu, c3_l tab_l, u3_noun tac) -{ - u3v_punt(blu, tab_l, u3nc(tac, u3_nul)); -} - -/* u3v_punt(): dump tank list. -*/ -void -u3v_punt(u3_noun blu, c3_l tab_l, u3_noun tac) -{ -#if 0 - u3_noun blu = u3_term_get_blew(0); -#endif - c3_l col_l = u3h(blu); - u3_noun cat = tac; - - // We are calling nock here, but hopefully need no protection. - // - while ( c3y == u3r_du(cat) ) { - u3_noun wol = u3dc("wash", u3nc(tab_l, col_l), u3k(u3h(cat))); - - u3m_wall(wol); - cat = u3t(cat); - } - u3z(tac); - u3z(blu); -} - -/* u3v_sway(): print trace. -*/ -void -u3v_sway(u3_noun blu, c3_l tab_l, u3_noun tax) -{ - u3_noun mok = u3dc("mook", 2, tax); - - u3v_punt(blu, tab_l, u3k(u3t(mok))); - u3z(mok); -} - -/* u3v_mark(): mark arvo kernel. -*/ -c3_w -u3v_mark(FILE* fil_u) -{ - u3v_arvo* arv_u = &(u3H->arv_u); - c3_w tot_w = 0; - - tot_w += u3a_maid(fil_u, " kernel", u3a_mark_noun(arv_u->roc)); - tot_w += u3a_maid(fil_u, " date", u3a_mark_noun(arv_u->now)); - tot_w += u3a_maid(fil_u, " wish cache", u3a_mark_noun(arv_u->yot)); - return u3a_maid(fil_u, "total arvo stuff", tot_w); -} - -/* u3v_reclaim(): clear ad-hoc persistent caches to reclaim memory. -*/ -void -u3v_reclaim(void) -{ - // clear the u3v_wish cache - // - // NB: this would leak if not on the home road - // - if ( &(u3H->rod_u) == u3R ) { - u3z(u3A->yot); - u3A->yot = u3_nul; - } -} - -/* u3v_rewrite_compact(): rewrite arvo kernel for compaction. -*/ -void -u3v_rewrite_compact() -{ - u3v_arvo* arv_u = &(u3H->arv_u); - - u3a_rewrite_noun(arv_u->roc); - u3a_rewrite_noun(arv_u->now); - u3a_rewrite_noun(arv_u->yot); - - arv_u->roc = u3a_rewritten_noun(arv_u->roc); - arv_u->now = u3a_rewritten_noun(arv_u->now); - arv_u->yot = u3a_rewritten_noun(arv_u->yot); -} - diff --git a/pkg/urbit/noun/xtract.c b/pkg/urbit/noun/xtract.c deleted file mode 100644 index dd3fd0f9d..000000000 --- a/pkg/urbit/noun/xtract.c +++ /dev/null @@ -1,131 +0,0 @@ -/* g/x.c -** -*/ -#include "all.h" - -/* u3x_good(): test for u3_none. -*/ -u3_noun -u3x_good(u3_weak som) -{ - return ( u3_none == som ) ? u3m_bail(c3__exit) : som; -} - -/* u3x_at (u3at): fragment. -*/ -u3_noun -u3x_at(u3_noun axe, u3_noun som) -{ - return u3x_good(u3r_at(axe, som)); -} - -/* u3x_mean(): -** -** Attempt to deconstruct `a` by axis, noun pairs; 0 terminates. -** Axes must be sorted in tree order. -*/ -void -u3x_mean(u3_noun som, ...) -{ - c3_o ret_o; - va_list ap; - - va_start(ap, som); - ret_o = u3r_vmean(som, ap); - va_end(ap); - - if ( c3n == ret_o ) { - u3m_bail(c3__exit); - } -} - -/* u3x_bite(): xtract/default $bloq and $step from $bite. -*/ -void -u3x_bite(u3_noun bite, u3_atom* bloq, u3_atom *step) -{ - if ( c3n == u3r_bite(bite, bloq, step) ) { - u3m_bail(c3__exit); - } -} - -/* u3x_cell(): -** -** Divide `a` as a cell `[b c]`. -*/ -void -u3x_cell(u3_noun a, - u3_noun* b, - u3_noun* c) -{ - if ( c3n == u3r_cell(a, b, c) ) { - u3m_bail(c3__exit); - } -} - -/* u3x_trel(): -** -** Divide `a` as a trel `[b c d]`, or bail. -*/ -void -u3x_trel(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d) -{ - if ( c3n == u3r_trel(a, b, c, d) ) { - u3m_bail(c3__exit); - } -} - -/* u3x_qual(): -** -** Divide `a` as a quadruple `[b c d e]`. -*/ -void -u3x_qual(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d, - u3_noun* e) -{ - if ( c3n == u3r_qual(a, b, c, d, e) ) { - u3m_bail(c3__exit); - } -} - -/* u3x_quil(): -** -** Divide `a` as a quintuple `[b c d e f]`. -*/ -void -u3x_quil(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d, - u3_noun* e, - u3_noun* f) -{ - if ( c3n == u3r_quil(a, b, c, d, e, f) ) { - u3m_bail(c3__exit); - } -} - -/* u3x_hext(): -** -** Divide `a` as a hextuple `[b c d e f g]`. -*/ -void -u3x_hext(u3_noun a, - u3_noun* b, - u3_noun* c, - u3_noun* d, - u3_noun* e, - u3_noun* f, - u3_noun* g) -{ - if ( c3n == u3r_hext(a, b, c, d, e, f, g) ) { - u3m_bail(c3__exit); - } -} - diff --git a/pkg/urbit/noun/zave.c b/pkg/urbit/noun/zave.c deleted file mode 100644 index ec42c8929..000000000 --- a/pkg/urbit/noun/zave.c +++ /dev/null @@ -1,89 +0,0 @@ -/* g/z.c -** -*/ -#include "all.h" - -/* u3z_key(): construct a memo cache-key. Arguments retained. -*/ -u3_noun -u3z_key(c3_m fun, u3_noun one) -{ - return u3nc(fun, u3k(one)); -} -u3_noun -u3z_key_2(c3_m fun, u3_noun one, u3_noun two) -{ - return u3nt(fun, u3k(one), u3k(two)); -} -u3_noun -u3z_key_3(c3_m fun, u3_noun one, u3_noun two, u3_noun tri) -{ - return u3nq(fun, u3k(one), u3k(two), u3k(tri)); -} -u3_noun -u3z_key_4(c3_m fun, u3_noun one, u3_noun two, u3_noun tri, u3_noun qua) -{ - return u3nc(fun, u3nq(u3k(one), u3k(two), u3k(tri), u3k(qua))); -} -u3_noun -u3z_key_5(c3_m fun, u3_noun one, u3_noun two, u3_noun tri, u3_noun qua, u3_noun qin) -{ - return u3nc(fun, u3nq(u3k(one), u3k(two), u3k(tri), u3nc(u3k(qua), u3k(qin)))); -} - -/* u3z_find(): find in memo cache. Arguments retained. -*/ -u3_weak -u3z_find(u3_noun key) -{ - return u3h_get(u3R->cax.har_p, key); -} -u3_weak -u3z_find_m(c3_m fun, u3_noun one) -{ - u3_noun key = u3nc(fun, u3k(one)); - u3_weak val; - - val = u3h_get(u3R->cax.har_p, key); - u3z(key); - return val; -} - -/* u3z_save(): save in memo cache. TRANSFER key; RETAIN val -*/ -u3_noun -u3z_save(u3_noun key, u3_noun val) -{ - u3h_put(u3R->cax.har_p, key, u3k(val)); - u3z(key); - return val; -} - -/* u3z_save_m(): save in memo cache. Arguments retained. -*/ -u3_noun -u3z_save_m(c3_m fun, u3_noun one, u3_noun val) -{ - u3_noun key = u3nc(fun, u3k(one)); - - u3h_put(u3R->cax.har_p, key, u3k(val)); - u3z(key); - return val; -} - -/* u3z_uniq(): uniquify with memo cache. -*/ -u3_noun -u3z_uniq(u3_noun som) -{ - u3_noun key = u3nc(c3__uniq, u3k(som)); - u3_noun val = u3h_get(u3R->cax.har_p, key); - - if ( u3_none != val ) { - u3z(key); u3z(som); return val; - } - else { - u3h_put(u3R->cax.har_p, key, u3k(som)); - return som; - } -} diff --git a/pkg/urbit/shell.nix b/pkg/urbit/shell.nix deleted file mode 100644 index 62e0f72cd..000000000 --- a/pkg/urbit/shell.nix +++ /dev/null @@ -1,8 +0,0 @@ -let - - pkgs = import ../../default.nix { }; - -in pkgs.shellFor { - name = "urbit"; - packages = ps: [ ps.urbit ]; -} diff --git a/pkg/urbit/tests/ames_tests.c b/pkg/urbit/tests/ames_tests.c deleted file mode 100644 index 0907898d4..000000000 --- a/pkg/urbit/tests/ames_tests.c +++ /dev/null @@ -1,48 +0,0 @@ -#include "all.h" -#include "vere/vere.h" - -/* _setup(): prepare for tests. -*/ -static void -_setup(void) -{ - u3m_init(1 << 22); - u3m_pave(c3y); -} - -/* _test_ames(): spot check ames helpers -*/ -static void -_test_ames(void) -{ - u3_lane lan_u; - lan_u.pip_w = 0x7f000001; - lan_u.por_s = 12345; - - u3_noun lan = u3_ames_encode_lane(lan_u); - u3_lane nal_u = u3_ames_decode_lane(u3k(lan)); - u3_lane nal_u2 = u3_ames_decode_lane(lan); - - if ( !(lan_u.pip_w == nal_u.pip_w && lan_u.por_s == nal_u.por_s) ) { - fprintf(stderr, "ames: lane fail (a)\r\n"); - fprintf(stderr, "pip: %d, por: %d\r\n", nal_u.pip_w, nal_u.por_s); - exit(1); - } -} - -/* main(): run all test cases. -*/ -int -main(int argc, char* argv[]) -{ - _setup(); - - _test_ames(); - - // GC - // - u3m_grab(u3_none); - - fprintf(stderr, "ames okeedokee\n"); - return 0; -} diff --git a/pkg/urbit/tests/boot_tests.c b/pkg/urbit/tests/boot_tests.c deleted file mode 100644 index 1897bbe93..000000000 --- a/pkg/urbit/tests/boot_tests.c +++ /dev/null @@ -1,68 +0,0 @@ -#include "all.h" -#include "ur/ur.h" -#include "vere/ivory.h" -#include "vere/vere.h" - -/* _setup(): prepare for tests. -*/ -static void -_setup(void) -{ - c3_d len_d = u3_Ivory_pill_len; - c3_y* byt_y = u3_Ivory_pill; - u3_cue_xeno* sil_u; - u3_weak pil; - - u3C.wag_w |= u3o_hashless; - u3m_boot_lite(1 << 26); - sil_u = u3s_cue_xeno_init_with(ur_fib27, ur_fib28); - if ( u3_none == (pil = u3s_cue_xeno_with(sil_u, len_d, byt_y)) ) { - printf("*** fail _setup 1\n"); - exit(1); - } - u3s_cue_xeno_done(sil_u); - if ( c3n == u3v_boot_lite(pil) ) { - printf("*** fail _setup 2\n"); - exit(1); - } -} - -/* _test_lily(): test small noun parsing. -*/ -static void -_test_lily() -{ - c3_l lit_l; - c3_w big_w[] = {0, 0, 1}; - u3_noun big = u3i_words(3, big_w); - u3_noun cod = u3dc("scot", c3__uv, big); - - if ( c3y == u3v_lily(c3__uv, cod, &lit_l) ) { - printf("*** fail _test_lily-1\n"); - exit(1); - } - cod = u3dc("scot", c3__ud, 0x7fffffff); - if ( (c3n == u3v_lily(c3__ud, cod, &lit_l)) || - (0x7fffffff != lit_l) ) { - printf("*** fail _test_lily-2a\n"); - exit(1); - } - cod = u3dc("scot", c3__ux, u3i_word(0x80000000)); - if ( c3y == u3v_lily(c3__ux, cod, &lit_l) ) { - printf("*** fail _test_lily-2b\n"); - exit(1); - } -} - -/* main(): run all test cases. -*/ -int -main(int argc, char* argv[]) -{ - _setup(); - - _test_lily(); - - fprintf(stderr, "test boot: ok\n"); - return 0; -} diff --git a/pkg/urbit/tests/hashtable_tests.c b/pkg/urbit/tests/hashtable_tests.c deleted file mode 100644 index 3b36dc887..000000000 --- a/pkg/urbit/tests/hashtable_tests.c +++ /dev/null @@ -1,245 +0,0 @@ -#include "all.h" -#include "vere/vere.h" - -// defined in noun/hashtable.c -c3_w _ch_skip_slot(c3_w mug_w, c3_w lef_w); - -/* _setup(): prepare for tests. -*/ -static void -_setup(void) -{ - u3m_init(1 << 26); - u3m_pave(c3y); -} - -/* _test_bit_manipulation(): -*/ -static c3_i -_test_bit_manipulation() -{ - c3_i ret_i = 1; - - if ( sizeof(u3_noun) != sizeof(u3h_slot) ) { - fprintf(stderr, "bit manipulation: wrong size\r\n"); - ret_i = 0; - } - - u3h_slot a = 0; - - if (u3h_slot_is_null(a) != c3y) { - fprintf(stderr, "bit manipulation: nullity\r\n"); - ret_i = 0; - } - - a = u3h_noun_be_warm(a); - if (u3h_slot_is_warm(a) != c3y) { - fprintf(stderr, "bit manipulation: warmth\r\n"); - ret_i = 0; - } - - if (u3h_slot_is_null(a) != c3n) { - fprintf(stderr, "bit manipulation: nullity 2\r\n"); - ret_i = 0; - } - - a = u3h_noun_be_cold(a); - if (u3h_slot_is_warm(a) != c3n) { - fprintf(stderr, "bit manipulation: coldness\r\n"); - ret_i = 0; - } - - return ret_i; -} - -/* _test_no_cache(): test a hashtable without caching. -*/ -static c3_i -_test_no_cache(void) -{ - c3_i ret_i = 1; - c3_w max_w = 1000; - c3_w i_w; - - u3p(u3h_root) har_p = u3h_new(); - - for ( i_w = 0; i_w < max_w; i_w++ ) { - u3h_put(har_p, i_w, i_w + max_w); - } - - for ( i_w = 0; i_w < max_w; i_w++ ) { - if ( (i_w + max_w) != u3h_get(har_p, i_w) ) { - fprintf(stderr, "bit test_no_cache: get failed\r\n"); - ret_i = 0; - } - } - - u3h_free(har_p); - return ret_i; -} - -/* _test_skip_slot(): -*/ -static c3_i -_test_skip_slot(void) -{ - c3_i ret_i = 1; - - // root table - { - c3_w mug_w = 0x17 << 25; - c3_w res_w = _ch_skip_slot(mug_w, 25); - - if ( (0x18 << 25) != res_w ) { - fprintf(stderr, "bit skip_slot (a): failed\r\n"); - ret_i = 0; - } - } - - { - c3_w mug_w = 63 << 25; // 6 bits, all ones - c3_w res_w = _ch_skip_slot(mug_w, 25); - - if ( 0 != res_w ) { - fprintf(stderr, "bit skip_slot (b): failed\r\n"); - ret_i = 0; - } - } - - // child nodes - { - c3_w mug_w = 17 << 20; - c3_w res_w = _ch_skip_slot(mug_w, 20); - - if ( (18 << 20) != res_w ) { - fprintf(stderr, "bit skip_slot (c): failed\r\n"); - ret_i = 0; - } - } - - { - c3_w mug_w = 31 << 20; // 5 bits, all ones - c3_w res_w = _ch_skip_slot(mug_w, 20); - c3_assert((1 << 25) == res_w); - - if ( (1 << 25) != res_w ) { - fprintf(stderr, "bit skip_slot (d): failed\r\n"); - ret_i = 0; - } - } - - return ret_i; -} - -/* _test_cache_trimming(): ensure a caching hashtable removes stale items. -*/ -static c3_i -_test_cache_trimming(void) -{ - c3_i ret_i = 1; - c3_w max_w = 2000000; // big number - //c3_w max_w = 348000; // caused a leak before - c3_w i_w, fil_w = max_w / 10; - - u3p(u3h_root) har_p = u3h_new_cache(fil_w); - u3h_root* har_u = u3to(u3h_root, har_p); - - for ( i_w = 0; i_w < max_w; i_w++ ) { - u3_noun cel = u3nc(i_w, i_w); - u3h_put(har_p, cel, cel); - } - - { - // last thing we put in is still there - c3_w las_w = max_w - 1; - u3_noun key = u3nc(las_w, las_w); - u3_noun val = u3h_get(har_p, key); - u3z(key); - - if ( las_w != u3t(val) ) { - fprintf(stderr, "cache_trimming (a): fail\r\n"); - ret_i = 0; - } - - if ( fil_w != har_u->use_w ) { - fprintf(stderr, "cache_trimming (b): fail %d != %d\r\n", - fil_w, har_u->use_w ); - ret_i = 0; - } - - u3z(val); - } - - u3h_free(har_p); - return ret_i; -} - -/* _test_cache_replace_value(): -*/ -static c3_i -_test_cache_replace_value(void) -{ - c3_i ret_i = 1; - c3_w max_w = 100; - c3_w i_w; - - u3p(u3h_root) har_p = u3h_new_cache(max_w); - u3h_root* har_u = u3to(u3h_root, har_p); - - for ( i_w = 0; i_w < max_w; i_w++ ) { - u3h_put(har_p, i_w, i_w + max_w); - } - - for ( i_w = 0; i_w < max_w; i_w++ ) { - u3h_put(har_p, i_w, i_w + max_w + 1); - } - - if ( (2 * max_w) != u3h_get(har_p, max_w - 1) ) { - fprintf(stderr, "cache_replace (a): fail\r\n"); - ret_i = 0; - } - if ( max_w != har_u->use_w ) { - fprintf(stderr, "cache_replace (b): fail\r\n"); - fprintf(stderr, "cache_replace (b): fail %d %d\r\n", - max_w, har_u->use_w ); - ret_i = 0; - } - - u3h_free(har_p); - return ret_i; -} - -static c3_i -_test_hashtable(void) -{ - c3_i ret_i = 1; - - ret_i &= _test_bit_manipulation(); - ret_i &= _test_no_cache(); - ret_i &= _test_skip_slot(); - ret_i &= _test_cache_trimming(); - ret_i &= _test_cache_replace_value(); - - return ret_i; -} - -/* main(): run all test cases. -*/ -int -main(int argc, char* argv[]) -{ - _setup(); - - if ( !_test_hashtable() ) { - fprintf(stderr, "test_hashtable: failed\r\n"); - exit(1); - } - - // GC - // - u3m_grab(u3_none); - - fprintf(stderr, "test_hashtable: ok\r\n"); - - return 0; -} diff --git a/pkg/urbit/tests/jam_tests.c b/pkg/urbit/tests/jam_tests.c deleted file mode 100644 index fd416945d..000000000 --- a/pkg/urbit/tests/jam_tests.c +++ /dev/null @@ -1,265 +0,0 @@ -#include "all.h" -#include "ur/ur.h" - -/* _setup(): prepare for tests. -*/ -static void -_setup(void) -{ - u3m_init(1 << 24); - u3m_pave(c3y); - u3e_init(); -} - -static void -_byte_print(c3_d out_d, - c3_y* out_y, - c3_w len_w, - const c3_y* byt_y) -{ - c3_d i_d; - - fprintf(stderr, " actual: { "); - for ( i_d = 0; i_d < out_d; i_d++ ) { - fprintf(stderr, "0x%x, ", out_y[i_d]); - } - fprintf(stderr, "}\r\n"); - fprintf(stderr, " expect: { "); - for ( i_d = 0; i_d < len_w; i_d++ ) { - fprintf(stderr, "0x%x, ", byt_y[i_d]); - } - fprintf(stderr, "}\r\n"); -} - -static c3_i -_test_jam_spec(const c3_c* cap_c, - u3_noun ref, - c3_w len_w, - const c3_y* byt_y) -{ - c3_i ret_i = 1; - c3_d out_d; - c3_y* out_y; - - { - u3s_jam_xeno(ref, &out_d, &out_y); - - if ( 0 != memcmp(out_y, byt_y, len_w) ) { - fprintf(stderr, "\033[31mjam xeno %s fail\033[0m\r\n", cap_c); - _byte_print(out_d, out_y, len_w, byt_y); - ret_i = 0; - } - - free(out_y); - } - - { - u3i_slab sab_u; - c3_w bit_w = u3s_jam_fib(&sab_u, ref); - - out_d = ((c3_d)bit_w + 0x7) >> 3; - // XX assumes little-endian - // - out_y = sab_u.buf_y; - - if ( 0 != memcmp(out_y, byt_y, len_w) ) { - fprintf(stderr, "\033[31mjam fib %s fail\033[0m\r\n", cap_c); - _byte_print(out_d, out_y, len_w, byt_y); - ret_i = 0; - } - - u3i_slab_free(&sab_u); - } - - return ret_i; -} - -static c3_i -_test_cue_spec(const c3_c* cap_c, - u3_noun ref, - c3_w len_w, - const c3_y* byt_y) -{ - c3_i ret_i = 1; - - { - u3_noun pro = u3m_soft(0, u3s_cue_atom, u3i_bytes(len_w, byt_y)); - u3_noun tag, out; - - u3x_cell(pro, &tag, &out); - - if ( u3_blip != tag ) { - fprintf(stderr, "\033[31mcue %s fail 1\033[0m\r\n", cap_c); - ret_i = 0; - } - else if ( c3n == u3r_sing(ref, out) ) { - fprintf(stderr, "\033[31mcue %s fail 2\033[0m\r\n", cap_c); - u3m_p("ref", ref); - u3m_p("out", out); - ret_i = 0; - } - - u3z(pro); - } - - { - u3_noun out; - - if ( u3_none == (out = u3s_cue_xeno(len_w, byt_y)) ) { - fprintf(stderr, "\033[31mcue %s fail 3\033[0m\r\n", cap_c); - ret_i = 0; - } - else if ( c3n == u3r_sing(ref, out) ) { - fprintf(stderr, "\033[31mcue %s fail 4\033[0m\r\n", cap_c); - u3m_p("ref", ref); - u3m_p("out", out); - ret_i = 0; - } - - u3z(out); - } - - return ret_i; -} - -static c3_i -_test_jam_roundtrip(void) -{ - c3_i ret_i = 1; - -# define TEST_CASE(a, b) \ - const c3_c* cap_c = a; \ - u3_noun ref = b; \ - ret_i &= _test_jam_spec(cap_c, ref, sizeof(res_y), res_y); \ - ret_i &= _test_cue_spec(cap_c, ref, sizeof(res_y), res_y); \ - u3z(ref); - - { - c3_y res_y[1] = { 0x2 }; - TEST_CASE("0", 0); - } - - { - c3_y res_y[1] = { 0xc }; - TEST_CASE("1", 1); - } - - { - c3_y res_y[1] = { 0x48 }; - TEST_CASE("2", 2); - } - - { - c3_y res_y[6] = { 0xc0, 0x37, 0xb, 0x9b, 0xa3, 0x3 }; - TEST_CASE("%fast", c3__fast); - } - - { - c3_y res_y[6] = { 0xc0, 0x37, 0xab, 0x63, 0x63, 0x3 }; - TEST_CASE("%full", c3__full); - } - - { - c3_y res_y[1] = { 0x29 }; - TEST_CASE("[0 0]", u3nc(0, 0)); - } - - { - c3_y res_y[2] = { 0x31, 0x3 }; - TEST_CASE("[1 1]", u3nc(1, 1)); - } - - { - c3_y res_y[2] = { 0x31, 0x12 }; - TEST_CASE("[1 2]", u3nc(1, 2)); - } - - { - c3_y res_y[2] = { 0x21, 0xd1 }; - TEST_CASE("[2 3]", u3nc(2, 3)); - } - - { - c3_y res_y[11] = { 0x1, 0xdf, 0x2c, 0x6c, 0x8e, 0xe, 0x7c, 0xb3, 0x3a, 0x36, 0x36 }; - TEST_CASE("[%fast %full]", u3nc(c3__fast, c3__full)); - } - - { - c3_y res_y[2] = { 0x71, 0xcc }; - TEST_CASE("[1 1 1]", u3nc(1, u3nc(1, 1))); - } - - { - c3_y res_y[3] = { 0x71, 0x48, 0x34 }; - TEST_CASE("[1 2 3]", u3nt(1, 2, 3)); - } - - { - c3_y res_y[12] = { 0x1, 0xdf, 0x2c, 0x6c, 0x8e, 0x1e, 0xf0, 0xcd, 0xea, 0xd8, 0xd8, 0x93 }; - TEST_CASE("[%fast %full %fast]", u3nc(c3__fast, u3nc(c3__full, c3__fast))); - } - - { - c3_y res_y[3] = { 0xc5, 0x48, 0x34 }; - TEST_CASE("[[1 2] 3]", u3nc(u3nc(1, 2), 3)); - } - - { - c3_y res_y[5] = { 0xc5, 0xc8, 0x26, 0x27, 0x1 }; - TEST_CASE("[[1 2] [1 2] 1 2]", u3nt(u3nc(1, 2), u3nc(1, 2), u3nc(1, 2))); - } - - { - c3_y res_y[6] = { 0xa5, 0x35, 0x19, 0xf3, 0x18, 0x5 }; - TEST_CASE("[[0 0] [[0 0] 1 1] 1 1]", u3nc(u3nc(0, 0), u3nc(u3nc(u3nc(0, 0), u3nc(1, 1)), u3nc(1, 1)))); - } - - { - c3_y res_y[14] = { 0x15, 0x17, 0xb2, 0xd0, 0x85, 0x59, 0xb8, 0x61, 0x87, 0x5f, 0x10, 0x54, 0x55, 0x5 }; - TEST_CASE("deep", u3nc(u3nc(u3nc(1, u3nc(u3nc(2, u3nc(u3nc(3, u3nc(u3nc(4, u3nc(u3nt(5, 6, u3nc(7, u3nc(u3nc(8, 0), 0))), 0)), 0)), 0)), 0)), 0), 0)); - } - - { - c3_y inp_y[33] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; - c3_y res_y[35] = { 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8 }; - TEST_CASE("wide", u3i_bytes(sizeof(inp_y), inp_y)); - } - - { - c3_y inp_y[16] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xa8, 0xab, 0x60, 0xef, 0x2d, 0xd, 0x0, 0x0, 0x80 }; - c3_y res_y[19] = { 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x50, 0x57, 0xc1, 0xde, 0x5b, 0x1a, 0x0, 0x0, 0x0, 0x1 }; - TEST_CASE("date", u3i_bytes(sizeof(inp_y), inp_y)); - } - - { - u3_noun a = u3i_string("abcdefjhijklmnopqrstuvwxyz"); - c3_y res_y[32] = { - 0x1, 0xf8, 0xc, 0x13, 0x1b, 0x23, 0x2b, 0x33, 0x53, 0x43, 0x4b, - 0x53, 0x5b, 0x63, 0x6b, 0x73, 0x7b, 0x83, 0x8b, 0x93, 0x9b, 0xa3, - 0xab, 0xb3, 0xbb, 0xc3, 0xcb, 0xd3, 0x87, 0xc, 0x3d, 0x9 - }; - TEST_CASE("alpha", u3nq(u3k(a), 2, 3, a)); - } - - return ret_i; -} - -/* main(): run all test cases. -*/ -int -main(int argc, char* argv[]) -{ - _setup(); - - if ( !_test_jam_roundtrip() ) { - fprintf(stderr, "test jam: failed\r\n"); - exit(1); - } - - // GC - // - u3m_grab(u3_none); - - fprintf(stderr, "test jam: ok\r\n"); - return 0; -} diff --git a/pkg/urbit/tests/jet_tests.c b/pkg/urbit/tests/jet_tests.c deleted file mode 100644 index 4904a959d..000000000 --- a/pkg/urbit/tests/jet_tests.c +++ /dev/null @@ -1,541 +0,0 @@ -#include "all.h" - -/* _setup(): prepare for tests. -*/ -static void -_setup(void) -{ - u3m_init(1 << 20); - u3m_pave(c3y); -} - -static inline c3_i -_ud_good(c3_w num_w, const c3_c* num_c) -{ - u3_weak out; - if ( num_w != (out = u3s_sift_ud_bytes(strlen(num_c), (c3_y*)num_c)) ) { - if ( u3_none == out ) { - fprintf(stderr, "sift_ud: %s fail; expected %u\r\n", num_c, num_w); - } - else { - fprintf(stderr, "sift_ud: %s wrong; expected %u: actual %u\r\n", num_c, num_w, out); - } - return 0; - } - - return 1; -} - -static inline c3_i -_ud_fail(const c3_c* num_c) -{ - u3_weak out; - if ( u3_none != (out = u3s_sift_ud_bytes(strlen(num_c), (c3_y*)num_c)) ) { - u3m_p("out", out); - fprintf(stderr, "sift_ud: %s expected fail\r\n", num_c); - return 0; - } - - return 1; -} - -static c3_i -_test_sift_ud(void) -{ - c3_i ret_i = 1; - - ret_i &= _ud_good(0, "0"); - ret_i &= _ud_good(1, "1"); - ret_i &= _ud_good(12, "12"); - ret_i &= _ud_good(123, "123"); - ret_i &= _ud_good(1234, "1.234"); - ret_i &= _ud_good(12345, "12.345"); - ret_i &= _ud_good(123456, "123.456"); - ret_i &= _ud_good(1234567, "1.234.567"); - ret_i &= _ud_good(12345678, "12.345.678"); - ret_i &= _ud_good(123456789, "123.456.789"); - ret_i &= _ud_good(100000000, "100.000.000"); - ret_i &= _ud_good(101101101, "101.101.101"); - ret_i &= _ud_good(201201201, "201.201.201"); - ret_i &= _ud_good(302201100, "302.201.100"); - - ret_i &= _ud_fail("01"); - ret_i &= _ud_fail("02"); - ret_i &= _ud_fail("003"); - ret_i &= _ud_fail("1234"); - ret_i &= _ud_fail("1234.5"); - ret_i &= _ud_fail("1234.567.8"); - ret_i &= _ud_fail("1234.56..78."); - ret_i &= _ud_fail("123.45a"); - ret_i &= _ud_fail(".123.456"); - - { - c3_c* num_c = "4.294.967.296"; - u3_weak out = u3s_sift_ud_bytes(strlen(num_c), (c3_y*)num_c); - u3_atom pro = u3qc_bex(32); - - if ( u3_none == out ) { - fprintf(stderr, "sift_ud: (bex 32) fail\r\n"); - ret_i = 0; - } - - if ( c3n == u3r_sing(pro, out) ) { - u3m_p("out", out); - fprintf(stderr, "sift_ud: (bex 32) wrong\r\n"); - ret_i = 0; - } - - u3z(out); u3z(pro); - } - - - { - c3_c* num_c = "340.282.366.920.938.463.463.374.607.431.768.211.456"; - u3_weak out = u3s_sift_ud_bytes(strlen(num_c), (c3_y*)num_c); - u3_atom pro = u3qc_bex(128); - - if ( u3_none == out ) { - fprintf(stderr, "sift_ud: (bex 128) fail\r\n"); - ret_i = 0; - } - - if ( c3n == u3r_sing(pro, out) ) { - u3m_p("out", out); - fprintf(stderr, "sift_ud: (bex 128) wrong\r\n"); - ret_i = 0; - } - - u3z(out); u3z(pro); - } - - return ret_i; -} - -static c3_i -_test_en_base16(void) -{ - c3_i ret_i = 1; - - { - u3_atom dat = 0xaa; - u3_atom pro = u3qe_en_base16(u3r_met(3, dat), dat); - - if ( c3n == u3r_sing_c("aa", pro) ) { - fprintf(stderr, "en_base16: fail (a)\r\n"); - ret_i = 0; - } - - u3z(pro); - } - - { - u3_atom dat = 0x1234; - u3_atom pro = u3qe_en_base16(u3r_met(3, dat), dat); - - if ( c3n == u3r_sing_c("1234", pro) ) { - fprintf(stderr, "en_base16: fail (b)\r\n"); - ret_i = 0; - } - - u3z(pro); - } - - { - u3_atom dat = 0xf012; - u3_atom pro = u3qe_en_base16(u3r_met(3, dat), dat); - - if ( c3n == u3r_sing_c("f012", pro) ) { - fprintf(stderr, "en_base16: fail (c)\r\n"); - ret_i = 0; - } - - u3z(pro); - } - - { - u3_atom dat = 0x10b; - u3_atom pro = u3qe_en_base16(u3r_met(3, dat), dat); - - if ( c3n == u3r_sing_c("010b", pro) ) { - fprintf(stderr, "en_base16: fail (d)\r\n"); - ret_i = 0; - } - - u3z(pro); - } - - { - u3_atom pro = u3qe_en_base16(3, 0x1234); - - if ( c3n == u3r_sing_c("001234", pro) ) { - fprintf(stderr, "en_base16: fail (e)\r\n"); - ret_i = 0; - } - - u3z(pro); - } - - { - u3_atom pro = u3qe_en_base16(1, 0x1234); - - if ( c3n == u3r_sing_c("34", pro) ) { - fprintf(stderr, "en_base16: fail (f)\r\n"); - ret_i = 0; - } - - u3z(pro); - } - - return ret_i; -} - - -static c3_i -_test_de_base16(void) -{ - c3_i ret_i = 1; - - { - u3_noun inp = u3i_string("aa"); - u3_noun pro = u3qe_de_base16(inp); - u3_atom len, dat; - - if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) { - fprintf(stderr, "de_base16: fail cell (a)\r\n"); - ret_i = 0; - } - - if ( 1 != len ) { - fprintf(stderr, "de_base16: fail len (a)\r\n"); - ret_i = 0; - } - - if ( 0xaa != dat ) { - fprintf(stderr, "de_base16: fail dat (a)\r\n"); - ret_i = 0; - } - - u3z(inp); u3z(pro); - } - - { - u3_noun inp = u3i_string("1234"); - u3_noun pro = u3qe_de_base16(inp); - u3_atom len, dat; - - if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) { - fprintf(stderr, "de_base16: fail cell (b)\r\n"); - ret_i = 0; - } - - if ( 2 != len ) { - fprintf(stderr, "de_base16: fail len (b)\r\n"); - ret_i = 0; - } - - if ( 0x1234 != dat ) { - fprintf(stderr, "de_base16: fail dat (b)\r\n"); - ret_i = 0; - } - - u3z(inp); u3z(pro); - } - - { - u3_noun inp = u3i_string("f012"); - u3_noun pro = u3qe_de_base16(inp); - u3_atom len, dat; - - if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) { - fprintf(stderr, "de_base16: fail cell (c)\r\n"); - ret_i = 0; - } - - if ( 2 != len ) { - fprintf(stderr, "de_base16: fail len (c)\r\n"); - ret_i = 0; - } - - if ( 0xf012 != dat ) { - fprintf(stderr, "de_base16: fail dat (c)\r\n"); - ret_i = 0; - } - - u3z(inp); u3z(pro); - } - - { - u3_noun inp = u3i_string("010b"); - u3_noun pro = u3qe_de_base16(inp); - u3_atom len, dat; - - if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) { - fprintf(stderr, "de_base16: fail cell (d)\r\n"); - ret_i = 0; - } - - if ( 2 != len ) { - fprintf(stderr, "de_base16: fail len (d)\r\n"); - ret_i = 0; - } - - if ( 0x10b != dat ) { - fprintf(stderr, "de_base16: fail dat (d)\r\n"); - ret_i = 0; - } - - u3z(inp); u3z(pro); - } - - { - u3_noun inp = u3i_string("10b"); - u3_noun pro = u3qe_de_base16(inp); - u3_atom len, dat; - - if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) { - fprintf(stderr, "de_base16: fail cell (e)\r\n"); - ret_i = 0; - } - - if ( 2 != len ) { - fprintf(stderr, "de_base16: fail len (e)\r\n"); - ret_i = 0; - } - - if ( 0x10b != dat ) { - fprintf(stderr, "de_base16: fail dat (e)\r\n"); - ret_i = 0; - } - - u3z(inp); u3z(pro); - } - - { - u3_noun inp = u3i_string("001234"); - u3_noun pro = u3qe_de_base16(inp); - u3_atom len, dat; - - if ( c3n == u3r_pq(pro, u3_nul, &len, &dat) ) { - fprintf(stderr, "de_base16: fail cell (f)\r\n"); - ret_i = 0; - } - - if ( 3 != len ) { - fprintf(stderr, "de_base16: fail len (f)\r\n"); - ret_i = 0; - } - - if ( 0x1234 != dat ) { - fprintf(stderr, "de_base16: fail dat (f)\r\n"); - ret_i = 0; - } - - u3z(inp); u3z(pro); - } - - return ret_i; -} - -static c3_i -_test_base16(void) -{ - c3_i ret_i = 1; - - ret_i &= _test_en_base16(); - ret_i &= _test_de_base16(); - - return ret_i; -} - -static c3_w -_fein_ob_w(c3_w inp_w) -{ - u3_atom inp = u3i_word(inp_w); - u3_atom act = u3qe_fein_ob(inp); - c3_w act_w = u3r_word(0, act); - u3z(inp); u3z(act); - return act_w; -} - -static c3_i -_expect_fein_ob_w(c3_w inp_w, c3_w exp_w) -{ - c3_w act_w = _fein_ob_w(inp_w); - - if ( act_w != exp_w ) { - fprintf(stderr, "fein: inp=0x%08x exp=0x%08x act=0x%08x\n", - inp_w, exp_w, act_w); - return 0; - } - - return 1; -} - -static c3_i -_test_fein_ob(void) -{ - c3_i ret_i = 1; - - ret_i &= _expect_fein_ob_w(0, 0); - ret_i &= _expect_fein_ob_w(0xffff, 0xffff); - ret_i &= _expect_fein_ob_w(0x1b08f, 0x76b920e5); - ret_i &= _expect_fein_ob_w(0x10000, 0x423e60bf); - ret_i &= _expect_fein_ob_w(0x10001, 0xd4400acb); - ret_i &= _expect_fein_ob_w(0x10002, 0xf429043); - ret_i &= _expect_fein_ob_w(0x10000000, 0xa04bc7fa); - ret_i &= _expect_fein_ob_w(0x1234abcd, 0x686f6c25); - ret_i &= _expect_fein_ob_w(0xabcd1234, 0x4a220c8); - ret_i &= _expect_fein_ob_w(0xdeadbeef, 0x909bc4a9); - ret_i &= _expect_fein_ob_w(0xfffff, 0x6746b96b); - ret_i &= _expect_fein_ob_w(0xffffffff, 0xbba4dcce); - - return ret_i; -} - -static c3_w -_fynd_ob_w(c3_w inp_w) -{ - u3_atom inp = u3i_word(inp_w); - u3_atom act = u3qe_fynd_ob(inp); - c3_w act_w = u3r_word(0, act); - u3z(inp); u3z(act); - return act_w; -} - -static c3_i -_expect_fynd_ob_w(c3_w exp_w, c3_w inp_w) -{ - c3_w act_w = _fynd_ob_w(inp_w); - - if ( act_w != exp_w ) { - fprintf(stderr, "fynd: inp=0x%08x exp=0x%08x act=0x%08x\n", - inp_w, exp_w, act_w); - return 0; - } - - return 1; -} - -static c3_i -_test_fynd_ob(void) -{ - c3_i ret_i = 1; - - ret_i &= _expect_fynd_ob_w(0, 0); - ret_i &= _expect_fynd_ob_w(0xffff, 0xffff); - ret_i &= _expect_fynd_ob_w(0x10000, 0x423e60bf); - ret_i &= _expect_fynd_ob_w(0x10001, 0xd4400acb); - ret_i &= _expect_fynd_ob_w(0x10002, 0xf429043); - ret_i &= _expect_fynd_ob_w(0x10000000, 0xa04bc7fa); - ret_i &= _expect_fynd_ob_w(0x1234abcd, 0x686f6c25); - ret_i &= _expect_fynd_ob_w(0xabcd1234, 0x4a220c8); - ret_i &= _expect_fynd_ob_w(0xdeadbeef, 0x909bc4a9); - ret_i &= _expect_fynd_ob_w(0xfffff, 0x6746b96b); - ret_i &= _expect_fynd_ob_w(0xffffffff, 0xbba4dcce); - - return ret_i; -} - -static c3_i -_exhaust_roundtrip_fein_fynd_ob(void) -{ - c3_i ret_i = 1; - c3_w fyn_w, i_w; - - { - u3_atom fen, fyn; - - for ( i_w = 0x10000; i_w < 0x80000000; i_w++ ) { - fen = u3qe_fein_ob(i_w); - fyn = u3qe_fynd_ob(fen); - fyn_w = u3r_word(0, fyn); - - if ( i_w != fyn_w ) { - fprintf(stderr, "fein/fynd: inp=0x%08x fein=0x%08x fynd=0x%08x\n", - i_w, u3r_word(0, fen), fyn_w); - ret_i = 0; - } - u3z(fen); u3z(fyn); - - if ( !(i_w % 0x1000000) ) { - fprintf(stderr, "fein/fynd: 0x%x done\n", i_w); - } - } - } - - { - c3_w fen_w; - - do { - fen_w = _fein_ob_w(i_w); - fyn_w = _fynd_ob_w(fen_w); - if ( i_w != fyn_w ) { - fprintf(stderr, "fein/fynd: inp=0x%08x fein=0x%08x fynd=0x%08x\n", - i_w, fen_w, fyn_w); - ret_i = 0; - } - - if ( !(i_w % 0x1000000) ) { - fprintf(stderr, "fein/fynd: 0x%x done\n", i_w); - } - } - while ( ++i_w ); - } - - return ret_i; -} - -static c3_i -_test_ob(void) -{ - c3_i ret_i = 1; - ret_i &= _test_fein_ob(); - ret_i &= _test_fynd_ob(); - // disabled, takes almost ~m15 - // - // ret_i &= _exhaust_roundtrip_fein_fynd_ob(); - return ret_i; -} - -static c3_i -_test_jets(void) -{ - c3_i ret_i = 1; - - if ( !_test_sift_ud() ) { - fprintf(stderr, "test jets: sift_ud: failed\r\n"); - ret_i = 0; - } - - if ( !_test_base16() ) { - fprintf(stderr, "test jets: base16: failed\r\n"); - ret_i = 0; - } - - if ( !_test_ob() ) { - fprintf(stderr, "test jets: ob: failed\r\n"); - ret_i = 0; - } - - return ret_i; -} - -/* main(): run all test cases. -*/ -int -main(int argc, char* argv[]) -{ - _setup(); - - if ( !_test_jets() ) { - fprintf(stderr, "test jets: failed\r\n"); - exit(1); - } - - // GC - // - u3m_grab(u3_none); - - fprintf(stderr, "test jets: ok\r\n"); - return 0; -} diff --git a/pkg/urbit/tests/mug_tests.c b/pkg/urbit/tests/mug_tests.c deleted file mode 100644 index ffd051674..000000000 --- a/pkg/urbit/tests/mug_tests.c +++ /dev/null @@ -1,245 +0,0 @@ -#include "all.h" - -/* _setup(): prepare for tests. -*/ -static void -_setup(void) -{ - u3m_init(1 << 20); - u3m_pave(c3y); -} - -/* _test_mug(): spot check u3r_mug hashes. -*/ -static c3_i -_test_mug(void) -{ - c3_i ret_i = 1; - - if ( 0x4d441035 != u3r_mug_c("Hello, world!") ) { - fprintf(stderr, "fail (a)\r\n"); - ret_i = 0; - } - - { - u3_noun a = u3i_string("Hello, world!"); - - if ( 0x4d441035 != u3r_mug(a) ) { - fprintf(stderr, "fail (b)\r\n"); - ret_i = 0; - } - - u3z(a); - } - - { - c3_y byt_y[1]; - - if ( 0x79ff04e8 != u3r_mug_bytes(0, 0) ) { - fprintf(stderr, "fail (c) (0)\r\n"); - ret_i = 0; - } - - byt_y[0] = 1; - - if ( 0x715c2a60 != u3r_mug_bytes(byt_y, 1) ) { - fprintf(stderr, "fail (c) (1)\r\n"); - ret_i = 0; - } - - byt_y[0] = 2; - - if ( 0x718b9468 != u3r_mug_bytes(byt_y, 1) ) { - fprintf(stderr, "fail (c) (2)\r\n"); - ret_i = 0; - } - } - - if ( 0x3a811aec != u3r_mug_both(0x715c2a60, u3r_mug_cell(2, 3)) ) { - fprintf(stderr, "fail (d)\r\n"); - ret_i = 0; - } - - - { - if ( 0x192f5588 != u3r_mug_cell(0, 0) ) { - fprintf(stderr, "fail (e) (1)\r\n"); - ret_i = 0; - } - - if ( 0x6b32ec46 != u3r_mug_cell(1, 1) ) { - fprintf(stderr, "fail (e) (2)\r\n"); - ret_i = 0; - } - - if ( 0x2effe10 != u3r_mug_cell(2, 2) ) { - fprintf(stderr, "fail (e) (3)\r\n"); - ret_i = 0; - } - } - - { - u3_noun a = u3i_string("xxxxxxxxxxxxxxxxxxxxxxxxxxxx"); - - if ( 0x64dfda5c != u3r_mug(a) ) { - fprintf(stderr, "fail (f)\r\n"); - ret_i = 0; - } - - u3z(a); - } - - { - u3_noun a = u3qc_bex(32); - - if ( 0x7cefb7f != u3r_mug_cell(0, a) ) { - fprintf(stderr, "fail (g)\r\n"); - ret_i = 0; - } - - u3z(a); - } - - { - u3_noun a = u3ka_dec(u3qc_bex(128)); - - if ( 0x2aa06bfc != u3r_mug_cell(a, 1) ) { - fprintf(stderr, "fail (h)\r\n"); - ret_i = 0; - } - - u3z(a); - } - - { - // stick some zero bytes in a string - // - u3_noun str = u3kc_lsh(3, 1, - u3kc_mix(u3qc_bex(212), - u3i_string("abcdefjhijklmnopqrstuvwxyz"))); - - c3_w byt_w = u3r_met(3, str); - c3_w wor_w = u3r_met(5, str); - c3_y* str_y = c3_malloc(byt_w); - c3_w* str_w = c3_malloc(4 * wor_w); - c3_d str_d = 0; - - u3r_bytes(0, byt_w, str_y, str); - u3r_words(0, wor_w, str_w, str); - - str_d |= str_w[0]; - str_d |= ((c3_d)str_w[1] << 32ULL); - - if ( 0x34d08717 != u3r_mug(str) ) { - fprintf(stderr, "fail (i) (1) \r\n"); - ret_i = 0; - } - if ( 0x34d08717 != u3r_mug_bytes(str_y, byt_w) ) { - fprintf(stderr, "fail (i) (2)\r\n"); - ret_i = 0; - } - if ( 0x34d08717 != u3r_mug_words(str_w, wor_w) ) { - fprintf(stderr, "fail (i) (3)\r\n"); - ret_i = 0; - } - if ( u3r_mug_words(str_w, 2) != u3r_mug_chub(str_d) ) { - fprintf(stderr, "fail (i) (4)\r\n"); - ret_i = 0; - } - - c3_free(str_y); - c3_free(str_w); - u3z(str); - } - - { - c3_w som_w[4] = { 0, 0, 0, 1 }; - u3_noun som = u3i_words(4, som_w); - - if ( 0x519bd45c != u3r_mug(som) ) { - fprintf(stderr, "fail (j) (1)\r\n"); - ret_i = 0; - } - - if ( 0x519bd45c != u3r_mug_words(som_w, 4) ) { - fprintf(stderr, "fail (j) (2)\r\n"); - ret_i = 0; - } - - u3z(som); - } - - { - c3_w som_w[4] = { 0, 1, 0, 1 }; - u3_noun som = u3i_words(4, som_w); - - if ( 0x540eb8a9 != u3r_mug(som) ) { - fprintf(stderr, "fail (k) (1)\r\n"); - ret_i = 0; - } - - if ( 0x540eb8a9 != u3r_mug_words(som_w, 4) ) { - fprintf(stderr, "fail (k) (2)\r\n"); - ret_i = 0; - } - - u3z(som); - } - - { - c3_w som_w[4] = { 1, 1, 0, 1 }; - u3_noun som = u3i_words(4, som_w); - - if ( 0x319d28f9 != u3r_mug(som) ) { - fprintf(stderr, "fail (l) (1)\r\n"); - ret_i = 0; - } - - if ( 0x319d28f9 != u3r_mug_words(som_w, 4) ) { - fprintf(stderr, "fail (l) (2)\r\n"); - ret_i = 0; - } - - u3z(som); - } - - { - c3_w som_w[4] = { 0, 0, 0, 0xffff }; - u3_noun som = u3i_words(4, som_w); - - if ( 0x5230a260 != u3r_mug(som) ) { - fprintf(stderr, "fail (m) (1)\r\n"); - ret_i = 0; - } - - if ( 0x5230a260 != u3r_mug_words(som_w, 4) ) { - fprintf(stderr, "fail (m) (2)\r\n"); - ret_i = 0; - } - - u3z(som); - } - - return ret_i; -} - -/* main(): run all test cases. -*/ -int -main(int argc, char* argv[]) -{ - _setup(); - - if ( !_test_mug() ) { - fprintf(stderr, "test_mug: failed\r\n"); - exit(1); - } - - // GC - // - u3m_grab(u3_none); - - fprintf(stderr, "test_mug: ok\n"); - - return 0; -} diff --git a/pkg/urbit/tests/newt_tests.c b/pkg/urbit/tests/newt_tests.c deleted file mode 100644 index 6fdbdb759..000000000 --- a/pkg/urbit/tests/newt_tests.c +++ /dev/null @@ -1,353 +0,0 @@ -#include "all.h" -#include "vere/vere.h" - -/* _setup(): prepare for tests. -*/ -static void -_setup(void) -{ - u3m_init(1 << 20); - u3m_pave(c3y); -} - -/* _newt_encode(): synchronous serialization into a single buffer, for test purposes -*/ -static c3_y* -_newt_encode(u3_atom mat, c3_w* len_w) -{ - c3_w met_w = u3r_met(3, mat); - c3_y* buf_y; - - *len_w = 5 + met_w; - buf_y = c3_malloc(*len_w); - - // write header - // - buf_y[0] = 0x0; - buf_y[1] = ( met_w & 0xff); - buf_y[2] = ((met_w >> 8) & 0xff); - buf_y[3] = ((met_w >> 16) & 0xff); - buf_y[4] = ((met_w >> 24) & 0xff); - - u3r_bytes(0, met_w, buf_y + 5, mat); - u3z(mat); - - return buf_y; -} - -static c3_w -_moat_length(u3_moat* mot_u) -{ - u3_meat* met_u = mot_u->ext_u; - c3_w len_w = 0; - - while ( met_u ) { - met_u = met_u->nex_u; - len_w++; - } - - return len_w; -} - -/* _test_newt_smol(): various scenarios with small messages -*/ -static void -_test_newt_smol(void) -{ - // =(2 (jam 0)) - // - u3_atom a = u3ke_jam(0); - u3_moat mot_u; - c3_w len_w; - c3_y* buf_y; - - memset(&mot_u, 0, sizeof(u3_moat)); - - // one message one buffer - // - { - mot_u.ent_u = mot_u.ext_u = 0; - - buf_y = _newt_encode(u3k(a), &len_w); - u3_newt_decode(&mot_u, buf_y, len_w); - - if ( 1 != _moat_length(&mot_u) ) { - fprintf(stderr, "newt smol fail (a)\n"); - exit(1); - } - } - - // two messages one buffer - // - { - mot_u.ent_u = mot_u.ext_u = 0; - - buf_y = _newt_encode(u3k(a), &len_w); - - buf_y = c3_realloc(buf_y, 2 * len_w); - memcpy(buf_y + len_w, buf_y, len_w); - len_w = 2 * len_w; - - u3_newt_decode(&mot_u, buf_y, len_w); - - if ( 2 != _moat_length(&mot_u) ) { - fprintf(stderr, "newt smol fail (b)\n"); - exit(1); - } - } - - // one message two buffers - // - { - c3_y* end_y; - - mot_u.ent_u = mot_u.ext_u = 0; - - buf_y = _newt_encode(u3k(a), &len_w); - - end_y = c3_malloc(1); - end_y[0] = buf_y[len_w - 1]; - - u3_newt_decode(&mot_u, buf_y, len_w - 1); - - if ( 0 != _moat_length(&mot_u) ) { - fprintf(stderr, "newt smol fail (c)\n"); - exit(1); - } - - u3_newt_decode(&mot_u, end_y, 1); - - if ( 1 != _moat_length(&mot_u) ) { - fprintf(stderr, "newt smol fail (d)\n"); - exit(1); - } - } - - // two messages two buffers (overlapping length) - // - { - c3_y* haf_y; - c3_w haf_w, dub_w; - - mot_u.ent_u = mot_u.ext_u = 0; - - buf_y = _newt_encode(u3k(a), &len_w); - - dub_w = 2 * len_w; - haf_w = len_w / 2; - - // buf_y is all of message one, half of message two (not a full length) - // - buf_y = c3_realloc(buf_y, dub_w - haf_w); - memcpy(buf_y + len_w, buf_y, len_w - haf_w); - - // haf_y is the second half of message two - // - haf_y = c3_malloc(haf_w); - memcpy(haf_y, buf_y + (len_w - haf_w), haf_w); - - u3_newt_decode(&mot_u, buf_y, dub_w - haf_w); - - if ( 1 != _moat_length(&mot_u) ) { - fprintf(stderr, "newt smol fail (e)\n"); - exit(1); - } - - u3_newt_decode(&mot_u, haf_y, haf_w); - - if ( 2 != _moat_length(&mot_u) ) { - fprintf(stderr, "newt smol fail (f)\n"); - exit(1); - } - } - - u3z(a); -} - -/* _test_newt_vast(): various scenarios with larger messages -*/ -static void -_test_newt_vast(void) -{ - // =(53 (met 3 (jam "abcdefghijklmnopqrstuvwxyz"))) - // - u3_atom a = u3ke_jam(u3i_tape("abcdefghijklmnopqrstuvwxyz")); - u3_moat mot_u; - c3_w len_w; - c3_y* buf_y; - - memset(&mot_u, 0, sizeof(u3_moat)); - - // one message one buffer - // - { - mot_u.ent_u = mot_u.ext_u = 0; - - buf_y = _newt_encode(u3k(a), &len_w); - u3_newt_decode(&mot_u, buf_y, len_w); - - if ( 1 != _moat_length(&mot_u) ) { - fprintf(stderr, "newt vast fail (a)\n"); - exit(1); - } - } - - // two messages one buffer - // - { - mot_u.ent_u = mot_u.ext_u = 0; - - buf_y = _newt_encode(u3k(a), &len_w); - - buf_y = c3_realloc(buf_y, 2 * len_w); - memcpy(buf_y + len_w, buf_y, len_w); - len_w = 2 * len_w; - - u3_newt_decode(&mot_u, buf_y, len_w); - - if ( 2 != _moat_length(&mot_u) ) { - fprintf(stderr, "newt vast fail (b)\n"); - exit(1); - } - } - - // one message many buffers - // - { - mot_u.ent_u = mot_u.ext_u = 0; - - buf_y = _newt_encode(u3k(a), &len_w); - - { - c3_y* cop_y = c3_malloc(len_w); - c3_w haf_w = len_w / 2; - memcpy(cop_y, buf_y, len_w); - - u3_newt_decode(&mot_u, buf_y, haf_w); - - while ( haf_w < len_w ) { - c3_y* end_y = c3_malloc(1); - end_y[0] = cop_y[haf_w]; - - if ( 0 != _moat_length(&mot_u) ) { - fprintf(stderr, "newt vast fail (c) %u\n", haf_w); - exit(1); - } - - u3_newt_decode(&mot_u, end_y, 1); - haf_w++; - } - - c3_free(cop_y); - } - - if ( 1 != _moat_length(&mot_u) ) { - fprintf(stderr, "newt vast fail (d)\n"); - exit(1); - } - } - - // two messages two buffers - // - { - c3_y* haf_y; - c3_w haf_w, dub_w; - - mot_u.ent_u = mot_u.ext_u = 0; - - buf_y = _newt_encode(u3k(a), &len_w); - - dub_w = 2 * len_w; - haf_w = len_w / 2; - - // buf_y is all of message one, half of message two - // - buf_y = c3_realloc(buf_y, dub_w - haf_w); - memcpy(buf_y + len_w, buf_y, len_w - haf_w); - - // haf_y is the second half of message two - // - haf_y = c3_malloc(haf_w); - memcpy(haf_y, buf_y + (len_w - haf_w), haf_w); - - u3_newt_decode(&mot_u, buf_y, dub_w - haf_w); - - if ( 1 != _moat_length(&mot_u) ) { - fprintf(stderr, "newt vast fail (e)\n"); - exit(1); - } - - u3_newt_decode(&mot_u, haf_y, haf_w); - - if ( 2 != _moat_length(&mot_u) ) { - fprintf(stderr, "newt vast fail (f)\n"); - exit(1); - } - } - - // two messages many buffers - // - { - c3_w dub_w; - - mot_u.ent_u = mot_u.ext_u = 0; - - buf_y = _newt_encode(u3k(a), &len_w); - - dub_w = 2 * len_w; - - // buf_y is two copies of message - // - buf_y = c3_realloc(buf_y, dub_w); - memcpy(buf_y + len_w, buf_y, len_w); - - { - c3_y* cop_y = c3_malloc(dub_w); - c3_w haf_w = len_w + 1; - memcpy(cop_y, buf_y, dub_w); - - u3_newt_decode(&mot_u, buf_y, haf_w); - - while ( haf_w < dub_w ) { - c3_y* end_y = c3_malloc(1); - end_y[0] = cop_y[haf_w]; - - if ( 1 != _moat_length(&mot_u) ) { - fprintf(stderr, "newt vast fail (g) %u\n", haf_w); - exit(1); - } - - u3_newt_decode(&mot_u, end_y, 1); - haf_w++; - } - - c3_free(cop_y); - } - - if ( 2 != _moat_length(&mot_u) ) { - fprintf(stderr, "newt vast fail (h)\n"); - exit(1); - } - } - - u3z(a); -} - -/* main(): run all test cases. -*/ -int -main(int argc, char* argv[]) -{ - _setup(); - - _test_newt_smol(); - _test_newt_vast(); - - // GC - // - u3m_grab(u3_none); - - fprintf(stderr, "test_newt: ok\n"); - - return 0; -} diff --git a/pkg/urbit/tests/nock_tests.c b/pkg/urbit/tests/nock_tests.c deleted file mode 100644 index a96ed09bd..000000000 --- a/pkg/urbit/tests/nock_tests.c +++ /dev/null @@ -1,86 +0,0 @@ -#include "all.h" - -/* _setup(): prepare for tests. -*/ -static void -_setup(void) -{ - // XX at 1<<24, this succeeds on mac, but bail:exit's on linux. - // investigate possible u3n_prog corruption - // - u3m_init(1 << 25); - u3m_pave(c3y); - u3e_init(); -} - -static u3_noun -_nock_fol(u3_noun fol) -{ - return u3n_nock_on(u3_nul, fol); -} - -static c3_i -_test_nock_meme(void) -{ - // (jam !=(=(~ =|(i=@ |-(?:(=(i ^~((bex 32))) ~ [i $(i +(i))])))))) - // - const c3_y buf_y[] = { - 0xe1, 0x16, 0x1b, 0x4, 0x1b, 0xe1, 0x20, 0x58, 0x1c, 0x76, 0x4d, 0x96, 0xd8, - 0x31, 0x60, 0x0, 0x0, 0x0, 0x0, 0xd8, 0x8, 0x37, 0xce, 0xd, 0x92, 0x21, - 0x83, 0x68, 0x61, 0x87, 0x39, 0xce, 0x4d, 0xe, 0x92, 0x21, 0x87, 0x19, 0x8 - }; - u3_noun fol = u3s_cue_bytes(sizeof(buf_y), buf_y); - u3_noun gon; - c3_w i_w; - c3_i ret_i = 1; - - for ( i_w = 0; i_w < 3; i_w++ ) { - gon = u3m_soft(0, _nock_fol, u3k(fol)); - - if ( c3n == u3r_p(gon, c3__meme, 0) ) { - u3m_p("nock meme unexpected mote", u3h(gon)); - ret_i = 0; - u3z(gon); - break; - } - - u3z(gon); - } - - u3z(fol); - - return ret_i; -} - -static c3_i -_test_nock(void) -{ - c3_i ret_i = 1; - - if ( !_test_nock_meme() ) { - fprintf(stderr, "test nock meme: failed\r\n"); - ret_i = 0; - } - - return ret_i; -} - -/* main(): run all test cases. -*/ -int -main(int argc, char* argv[]) -{ - _setup(); - - if ( !_test_nock() ) { - fprintf(stderr, "test nock: failed\r\n"); - exit(1); - } - - // GC - // - u3m_grab(u3_none); - - fprintf(stderr, "test nock: ok\r\n"); - return 0; -} diff --git a/pkg/urbit/tests/noun_tests.c b/pkg/urbit/tests/noun_tests.c deleted file mode 100644 index af54cd289..000000000 --- a/pkg/urbit/tests/noun_tests.c +++ /dev/null @@ -1,1784 +0,0 @@ -#include "all.h" - -#define TRUE 1 -#define FALSE 0 - -/* _setup(): prepare for tests. -*/ -static void -_setup(void) -{ - u3m_init(1 << 20); - u3m_pave(c3y); -} - -/* _test_u3r_chop: "extract bit slices from atom" -*/ -static c3_i -_test_u3r_chop() -{ - c3_i ret_i = 1; - c3_w dst_w = 0; - u3_atom src = 0b11011; - - // bloq 0 - // - { - // read 1 bit from pos=0 (far right) - // - dst_w = 0; - u3r_chop(0, 0, 1, 0, &dst_w, src); - if ( 0x1 != dst_w ) { - fprintf(stderr, "test: u3r_chop: bloq 0, 0\r\n"); - ret_i = 0; - } - - // read 1 bit from pos=1 - // - dst_w = 0; - u3r_chop(0, 1, 1, 0, &dst_w, src); - if ( 0x1 != dst_w ) { - fprintf(stderr, "test: u3r_chop: bloq 0, 1\r\n"); - ret_i = 0; - } - - // read 1 bit from pos=2 - // - dst_w = 0; - u3r_chop(0, 2, 1, 0, &dst_w, src); - if ( 0x0 != dst_w ) { - fprintf(stderr, "test: u3r_chop: bloq 0, 2\r\n"); - ret_i = 0; - } - - // read 4 x 1 bit bloq from pos=0 - // - dst_w = 0; - u3r_chop(0, 0, 4, 0, &dst_w, src); - if ( 0b1011 != dst_w ) { - fprintf(stderr, "test: u3r_chop: bloq 0, 3\r\n"); - ret_i = 0; - } - - // read 4 x 1 bit bloq from pos=0 into offset 1 - // - dst_w = 0; - u3r_chop(0, 0, 4, 1, &dst_w, src); - if ( 0b10110 != dst_w ) { - fprintf(stderr, "test: u3r_chop: bloq 0, 4\r\n"); - ret_i = 0; - } - } - - // bloq 1 - // - { - // read 2 bit from pos=0 (far right) - // - dst_w = 0; - u3r_chop(1, 0, 1, 0, &dst_w, src); - if ( 0b11 != dst_w ) { - fprintf(stderr, "test: u3r_chop: bloq 1, 0\r\n"); - ret_i = 0; - } - - // read 2 bit from pos=1 - // - dst_w = 0; - u3r_chop(1, 1, 1, 0, &dst_w, src); - if ( 0b10 != dst_w ) { - fprintf(stderr, "test: u3r_chop: bloq 1, 1\r\n"); - ret_i = 0; - } - - // read 2 bit from pos=2 (2 bloq over) - dst_w = 0; - u3r_chop(1, 2, 1, 0, &dst_w, src); - if ( 0b01 != dst_w ) { - fprintf(stderr, "test: u3r_chop: bloq 1, 2\r\n"); - ret_i = 0; - } - } - - // bloq 3 - { - dst_w = 0; - u3r_chop(3, 0, 1, 0, &dst_w, src); - if ( 0b11011 != dst_w ) { - fprintf(stderr, "test: u3r_chop: bloq 3, 0\r\n"); - ret_i = 0; - } - } - - // read 1,8,16 bit bloqs from an indirect atom - // - { - src = u3i_string("abcdefghij"); - - // 1 bit pos=0 (far right) - // - dst_w = 0; - u3r_chop(0, 0, 1, 0, &dst_w, src); - if ( 0b1 != dst_w ) { - fprintf(stderr, "test: u3r_chop: indirect 0\r\n"); - ret_i = 0; - } - - // 8 bits pos=0 - // - dst_w = 0; - u3r_chop(0, 0, 8, 0, &dst_w, src); - if ( 0b1100001 != dst_w ) { - fprintf(stderr, "test: u3r_chop: indirect 1\r\n"); - ret_i = 0; - } - - // 1 byte pos=0 - // - dst_w = 0; - u3r_chop(3, 0, 1, 0, &dst_w, src); - if ( 0b1100001 != dst_w ) { - fprintf(stderr, "test: u3r_chop: indirect 2\r\n"); - ret_i = 0; - } - - // 1 short pos=0 - // - dst_w = 0; - u3r_chop(4, 0, 1, 0, &dst_w, src); - if ( 0b0110001001100001 != dst_w ) { - fprintf(stderr, "test: u3r_chop: indirect 3\r\n"); - ret_i = 0; - } - - u3z(src); - } - - // read lots of bits from a direct noun which holds 64 bits of data - // makes sure that we handle top 32 / bottom 32 correctly - { - c3_y inp_y[8] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }; - src = u3i_bytes(8, inp_y); - - c3_w dst_w[2] = {0}; - u3r_chop(0, 0, 63, 0, dst_w, src); - if ( (0x3020100 != dst_w[0]) || (0x7060504 != dst_w[1]) ) { - fprintf(stderr, "test: u3r_chop: indirect 4\r\n"); - ret_i = 0; - } - - u3z(src); - } - - // as above (read lots of bits from a direct noun which holds 64 bits of data - // makes sure that we handle top 32 / bottom 32 correctly) - // but with a bit more nuance - { - c3_y inp_y[8] = { 0x0, 0x0, 0x0, 0xaa, 0xff, 0x0, 0x0, 0x0 }; - src = u3i_bytes(8, (c3_y*)inp_y); - - dst_w = 0; - u3r_chop(0, 24, 16, 0, &dst_w, src); - if ( 0b1111111110101010 != dst_w ) { - fprintf(stderr, "test: u3r_chop: indirect 5\r\n"); - ret_i = 0; - } - - u3z(src); - } - - return ret_i; -} - -/* _test_chop_slow(): "golden master" for chop tests (formerly u3r_chop()) -*/ -void -_test_chop_slow(c3_g met_g, - c3_w fum_w, - c3_w wid_w, - c3_w tou_w, - c3_w* dst_w, - c3_w len_w, - c3_w* buf_w) -{ - c3_w i_w; - - if ( met_g < 5 ) { - c3_w san_w = (1 << met_g); - c3_w mek_w = ((1 << san_w) - 1); - c3_w baf_w = (fum_w << met_g); - c3_w bat_w = (tou_w << met_g); - - // XX: efficiency: poor. Iterate by words. - // - for ( i_w = 0; i_w < wid_w; i_w++ ) { - c3_w waf_w = (baf_w >> 5); - c3_g raf_g = (baf_w & 31); - c3_w wat_w = (bat_w >> 5); - c3_g rat_g = (bat_w & 31); - c3_w hop_w; - - hop_w = (waf_w >= len_w) ? 0 : buf_w[waf_w]; - hop_w = (hop_w >> raf_g) & mek_w; - - dst_w[wat_w] ^= (hop_w << rat_g); - - baf_w += san_w; - bat_w += san_w; - } - } - else { - c3_g hut_g = (met_g - 5); - c3_w san_w = (1 << hut_g); - c3_w j_w; - - for ( i_w = 0; i_w < wid_w; i_w++ ) { - c3_w wuf_w = (fum_w + i_w) << hut_g; - c3_w wut_w = (tou_w + i_w) << hut_g; - - for ( j_w = 0; j_w < san_w; j_w++ ) { - dst_w[wut_w + j_w] ^= - ((wuf_w + j_w) >= len_w) - ? 0 - : buf_w[wuf_w + j_w]; - } - } - } -} - -/* _test_chop_smol(): test permuations of chop from bloq 0-4 -*/ -static c3_i -_test_chop_smol(c3_c* cap_c, c3_y val_y) -{ - c3_i ret_i = 1; - c3_g met_g; - c3_w fum_w, wid_w, tou_w; - c3_w len_w = 34; // (rsh [0 5] (mul 2 (mul 34 (bex 4)))) - c3_w src_w[len_w]; - c3_w a_w[len_w]; - c3_w b_w[len_w]; - - memset(src_w, val_y, len_w << 2); - - for ( met_g = 0; met_g < 5; met_g++ ) { - for ( fum_w = 0; fum_w <= len_w; fum_w++ ) { - for ( wid_w = 0; wid_w <= len_w; wid_w++ ) { - for ( tou_w = 0; tou_w <= len_w; tou_w++ ) { - memset(a_w, 0, len_w << 2); - memset(b_w, 0, len_w << 2); - u3r_chop_words(met_g, fum_w, wid_w, tou_w, a_w, len_w, src_w); - _test_chop_slow(met_g, fum_w, wid_w, tou_w, b_w, len_w, src_w); - - if ( 0 != memcmp(a_w, b_w, len_w << 2) ) { - c3_g sif_g = 5 - met_g; - c3_w mas_w = (1 << met_g) - 1; - c3_w out_w = tou_w >> sif_g; - c3_w max_w = out_w + !!(fum_w & mas_w) - + (wid_w >> sif_g) + !!(wid_w & mas_w); - - fprintf(stderr, "%s (0x%x): met_g=%u fum_w=%u wid_w=%u tou_w=%u\r\n", - cap_c, val_y, - met_g, fum_w, wid_w, tou_w); - - - fprintf(stderr, "%u-%u: ", out_w, max_w - 1); - for ( ; out_w < max_w; out_w++ ) { - fprintf(stderr, "[0x%x 0x%x] ", a_w[out_w], b_w[out_w]); - } - fprintf(stderr, "\r\n"); - } - } - } - } - } - - return ret_i; -} - -/* _test_chop_huge(): test permuations of chop from bloq 5+ -*/ -static c3_i -_test_chop_huge(c3_c* cap_c, c3_y val_y) -{ - c3_i ret_i = 1; - c3_g met_g; - c3_w fum_w, wid_w, tou_w; - c3_w len_w = 192; // (rsh [0 5] (mul 2 (mul 3 (bex 10)))) - c3_w src_w[len_w]; - c3_w a_w[len_w]; - c3_w b_w[len_w]; - - memset(src_w, val_y, len_w << 2); - - for ( met_g = 5; met_g <= 10; met_g++ ) { - for ( fum_w = 0; fum_w <= 3; fum_w++ ) { - for ( wid_w = 0; wid_w <= 2; wid_w++ ) { - for ( tou_w = 0; tou_w <= 1; tou_w++ ) { - memset(a_w, 0, len_w << 2); - memset(b_w, 0, len_w << 2); - u3r_chop_words(met_g, fum_w, wid_w, tou_w, a_w, len_w, src_w); - _test_chop_slow(met_g, fum_w, wid_w, tou_w, b_w, len_w, src_w); - - if ( 0 != memcmp(a_w, b_w, len_w << 2) ) { - c3_g sif_g = met_g - 5; - c3_w mas_w = (1 << met_g) - 1; - c3_w out_w = tou_w << sif_g; - c3_w max_w = out_w + !!(fum_w & mas_w) - + (wid_w << sif_g) + !!(wid_w & mas_w); - - fprintf(stderr, "%s (0x%x): met_g=%u fum_w=%u wid_w=%u tou_w=%u\r\n", - cap_c, val_y, - met_g, fum_w, wid_w, tou_w); - - - fprintf(stderr, "%u-%u: ", out_w, max_w - 1); - for ( ; out_w < max_w; out_w++ ) { - fprintf(stderr, "[0x%x 0x%x] ", a_w[out_w], b_w[out_w]); - } - fprintf(stderr, "\r\n"); - } - } - } - } - } - - return ret_i; -} - -/* _test_u3r_chop(): bit slice XOR -*/ -static c3_i -_test_chop() -{ - return _test_u3r_chop() - & _test_chop_smol("chop smol zeros", 0x0) - & _test_chop_smol("chop smol ones", 0xff) - & _test_chop_smol("chop smol alt 1", 0xaa) - & _test_chop_smol("chop smol alt 2", 0x55) - & _test_chop_huge("chop huge zeros", 0x0) - & _test_chop_huge("chop huge ones", 0xff) - & _test_chop_huge("chop huge alt 1", 0xaa) - & _test_chop_huge("chop huge alt 2", 0x55); -} - -/* _util_rand_string(): dynamically allocated len_w random string -*/ -static c3_y* -_util_rand_string(c3_w len_w) -{ - c3_c* choice_c = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - c3_w choice_len_w = strlen(choice_c); - - c3_y* out_y = c3_malloc(len_w + 1); - - c3_w i_w; - for (i_w = 0; i_w < len_w; i_w ++){ - out_y[i_w] = choice_c[ (c3_w) rand() % choice_len_w ]; - } - out_y[i_w] = 0; - - return out_y; -} - -/* _test_noun_bits_helper(): -*/ -static void -_test_noun_bits_helper(u3_noun a, int direct_o, - int indirect_o, - int indirect_atom_o, - int cell_o) -{ -#if 0 - printf("=========== %u\n", a); - printf(" 31 bit %u\n", a & ( ((c3_w)1) << 31)); - printf(" 30 bit %u\n", a & ( ((c3_w)1) << 30)); - printf(" dir %x\n", c3y == u3a_is_cat(a)); - printf(" ind %x\n", c3y == u3a_is_dog(a)); - printf(" i cell %x\n", c3y == u3a_is_cell(a)); - printf(" i atom %x\n", c3y == u3a_is_pug(a)); -#endif - - if ( direct_o != (c3y == u3a_is_cat(a)) ) { - printf("*** _test_noun_bits_one() fail: u3a_is_direct\r\n"); - } - - if ( indirect_o != (c3y == u3a_is_dog(a)) ) { - printf("*** fail-2 u3a_is_indirect %d\r\n", c3n == u3a_is_cat(a)); - } - - if ( cell_o != (c3y == u3a_is_cell(a)) ) { - printf("*** fail-4 u3a_is_cell\r\n"); - } - - if ( indirect_atom_o != (c3y == u3a_is_pug(a)) ) { - printf("*** fail-3 u3a_is_indirect_atom\r\n"); - } -} - -/* _test_noun_bits_set(): allocate.h level 1a -*/ -static void -_test_noun_bits_set() -{ - u3_noun a = 1; - - // flip indirect bit on - a |= (1 << 31); - if ( c3n == u3a_is_dog(a) ) { - printf("*** fail-5a turn indirect bit on\r\n"); - } - - if ( c3y == u3a_is_cell(a) ) { - printf("*** fail-5b turn indirect bit on\r\n"); - } - - if ( c3n == u3a_is_pug(a) ) { - printf("*** fail-5c turn indirect bit on\r\n"); - } - - // flip all bits off - a = u3a_to_off(a); - - if ( c3y == u3a_is_dog(a) ) { - printf("*** fail-5d turn indirect bit off\r\n"); - } - - if ( c3y == u3a_is_cell(a) ) { - printf("*** fail-5e turn indirect bit on\r\n"); - } - - if ( c3y == u3a_is_pug(a)) { - printf("*** fail-5f turn indirect bit on\r\n"); - } - - // flip indirect & cell bit on - a = u3a_to_pom(a); - - if ( c3n == u3a_is_dog(a) ) { - printf("*** fail-5g turn indirect bit on\r\n"); - } - - if ( c3n == u3a_is_cell(a) ) { - printf("*** fail-5h turn indirect bit on\r\n"); - } - - if ( c3y == u3a_is_pug(a) ) { - printf("*** fail-5i turn indirect bit on\r\n"); - } -} - -/* _test_noun_bits_read(): allocate.h level 1 -*/ -static void -_test_noun_bits_read() -{ - - u3_noun a = (u3_noun)0x1; // direct atom - u3_noun b = u3a_to_pug(0x2); // indirect atom - u3_noun c = u3a_to_pom(0x3); // indirect cell - - // direct indirect indirect-atom indirect-cell - //---------------------------------------- - _test_noun_bits_helper(a, TRUE, FALSE, FALSE, FALSE); - _test_noun_bits_helper(b, FALSE, TRUE, TRUE, FALSE); - _test_noun_bits_helper(c, FALSE, TRUE, FALSE, TRUE); -} - -/* _test_imprison(): test basic data into / out of nouns -** insert and retrieve bytes with u3i_bytes()/u3r_bytes() -*/ -static void -_test_imprison() -{ - c3_c* input_c = "abcdefghij"; - c3_w out_len_w = 300; - c3_y * output_y = c3_malloc(out_len_w); - u3_noun a; - - // size 1, direct - a = u3i_bytes(1, (c3_y*)input_c); - memset(output_y, 0, out_len_w); - u3r_bytes(0, 1, output_y, a); - if (0 != memcmp(output_y, "a", 1)) { - printf("*** _test_imprison: fail-1\n"); - } - - // size 2, direct - a = u3i_bytes(2, (c3_y*)input_c); - memset(output_y, 0, out_len_w); - u3r_bytes(0, 2, output_y, a); - if (0 != memcmp(output_y, "ab", 2)) { - printf("*** _test_imprison: fail-2\n"); - } - - // size 6, direct (taken from an actual issue) - { - c3_y data_y[] = { 0x1, 0x1f, 0x8e, 0x2d, 0x2c, 0x2f }; - a = u3i_bytes(6, data_y); - memset(output_y, 0, out_len_w); - u3r_bytes(0, 6, output_y, a); - int ret; - ret = memcmp(output_y, data_y, 6); - if (0 != ret) { - printf("*** _test_imprison: fail-2.5 %x\n", ret); - printf(" %x %x %x %x %x %x\n", output_y[0], - output_y[1], - output_y[2], - output_y[3], - output_y[4], - output_y[5]); - } - } - - // size 8, direct - a = u3i_bytes(8, (c3_y*)input_c); - memset(output_y, 0, out_len_w); - u3r_bytes(0, 8, output_y, a); - if (0 != memcmp(output_y, "abcdefgh", 8)) { - printf("*** _test_imprison: fail-3\n"); - } - - // size 10, indirect - a = u3i_bytes(10, (c3_y*)input_c); - memset(output_y, 0, out_len_w); - u3r_bytes(0, 10, output_y, a); - if (0 != memcmp(output_y, "abcdefghij", 10)) { - printf("*** _test_imprison: fail-4\n"); - } - - // size 200, indirect - c3_y * rand_y = _util_rand_string(200); - a = u3i_bytes(200, rand_y); - memset(output_y, 0, out_len_w); - u3r_bytes(0, 200, output_y, a); - if (0 != memcmp(output_y, rand_y, 200)) { - printf("*** _test_imprison: fail-5\n"); - } - - c3_free(rand_y); - c3_free(output_y); -} - -/* _test_cells(): build and inspect cells: u3i_cell(), u3h(), u3t() -*/ -static void -_test_cells() -{ - // very simple cell - { - u3_noun a = (u3_noun) 0x1; - u3_noun b = (u3_noun) 0x2; - u3_noun c = u3i_cell(a, b); - - u3_noun a2 = u3h(c); - if (a2 != a){ - printf("*** _test_cells: fail-1\n"); - } - - u3_noun b2 = u3t(c); - if (b2 != b){ - printf("*** _test_cells: fail-2\n"); - } - } - - // very simple cell with indirect atoms - { - c3_w out_len_w = 200; - c3_y * rand_a = _util_rand_string(out_len_w); - c3_y * rand_b = _util_rand_string(out_len_w); - - u3_noun a = u3i_bytes(200, rand_a); - u3_noun b = u3i_bytes(200, rand_b); - u3_noun c = u3i_cell(a, b); - -#if 0 - printf("a = %x\n", a); - printf("b = %x\n", b); - printf("c = %x\n", c); - printf("a_rand = %s\n", rand_a); - printf("b_rand = %s\n", rand_b); -#endif - - u3_noun a2 = u3h(c); - c3_y * output_y = c3_malloc(out_len_w + 1); - memset(output_y, 0, out_len_w + 1); - u3r_bytes(0, out_len_w, output_y, a); - - if (0 != memcmp(output_y, rand_a, out_len_w)) { - printf("*** _test_imprison: fail-3\n"); - } - - u3_noun b2 = u3h(c); - memset(output_y, 0, out_len_w + 1); - u3r_bytes(0, out_len_w, output_y, b); - - if (0 != memcmp(output_y, rand_b, out_len_w)) { - printf("*** _test_imprison: fail-4\n"); - } - - c3_free(output_y); - c3_free(rand_a); - c3_free(rand_b); - } - - // medium complicated cell - // q - // / \ - // a1 r - // / \ - // b2 s - // / \ - // c3 d4 - { - u3_noun a = (u3_noun) 0x1; - u3_noun b = (u3_noun) 0x2; - u3_noun c = (u3_noun) 0x3; - u3_noun d = (u3_noun) 0x4; - - u3_noun s = u3i_cell(c, d); - u3_noun r = u3i_cell(b, s); - u3_noun q = u3i_cell(a, r); - - u3_noun a2 = u3h(q); - u3_noun r2 = u3t(q); - if (a2 != a){ - printf("*** _test_cells: complicated a\n"); - } - - u3_noun b2 = u3h(r2); - u3_noun s2 = u3t(r2); - if (b2 != b){ - printf("*** _test_cells: complicated b\n"); - } - - - u3_noun c2 = u3h(s2); - u3_noun d2 = u3t(s2); - if (c2 != c){ - printf("*** _test_cells: complicated c\n"); - } - - if (d2 != d){ - printf("*** _test_cells: complicated d\n"); - } - - a2 = 0; - u3r_mean(q, 2, &a2, 0); - if (a2 != a){ - printf("*** _test_cells: complicated (via u3r_mean) a\n"); - } - } - - // trel - { - // q - // / \ - // a ? - // / \ - // b c - - // Produce the triple `[a b c]`. - u3_noun a = (u3_noun) 0x1; - u3_noun b = (u3_noun) 0x2; - u3_noun c = (u3_noun) 0x3; - - u3_noun trel = u3i_trel(a, b, c); - - u3_noun a2 = u3h(trel); - u3_noun b2 = u3h(u3t(trel)); - u3_noun c2 = u3t(u3t(trel)); - - if (a2 != a){ - printf("*** trel: 1 a\n"); - } - if (b2 != b){ - printf("*** trel: 2 a\n"); - } - if (c2 != c){ - printf("*** trel: 3 a\n"); - } - } - - // qual - { - // q - // / \ - // a ? - // / \ - // b ? - // / \ - // c d - // - - // Produce the triple `[a b c]`. - u3_noun a = (u3_noun) 0x1; - u3_noun b = (u3_noun) 0x2; - u3_noun c = (u3_noun) 0x3; - u3_noun d = (u3_noun) 0x4; - - u3_noun qual = u3i_qual(a, b, c, d); - - u3_noun a2 = u3h(qual); - u3_noun b2 = u3h(u3t(qual)); - u3_noun c2 = u3h(u3t(u3t(qual))); - u3_noun d2 = u3t(u3t(u3t(qual))); - - if (a2 != a){ - printf("*** qual: 1 \n"); - } - if (b2 != b){ - printf("*** qual: 2 \n"); - } - if (c2 != c){ - printf("*** qual: 3 \n"); - } - if (d2 != d){ - printf("*** qual: 4 \n"); - } - } -} - -/* _test_cells_complex(): build cells with more complex methods -*/ -static void -_test_cells_complex() -{ - // trel - { - // q - // / \ - // a ? - // / \ - // b c - - // Produce the triple `[a b c]`. - u3_noun a = (u3_noun) 0x1; - u3_noun b = (u3_noun) 0x2; - u3_noun c = (u3_noun) 0x3; - - u3_noun q = u3i_trel(a, b, c); - - u3_noun a2 = 0; - u3_noun b2 = 0; - u3_noun c2 = 0; - - u3x_trel(q, &a2, &b2, &c2); - - if (a2 != a){ - printf("*** _test_cells_complex: trel() 1 a\n"); - } - if (b2 != b){ - printf("*** _test_cells_complex: trel() 2 a\n"); - } - if (c2 != c){ - printf("*** _test_cells_complex: trel() 3 a\n"); - } - } - - // qual - { - // q - // / \ - // a ? - // / \ - // b z - // / \ - // c d - - // Produce the qual `[a b c d]`. - u3_noun a = (u3_noun) 0x1; - u3_noun b = (u3_noun) 0x2; - u3_noun c = (u3_noun) 0x3; - u3_noun d = (u3_noun) 0x4; - - u3_noun z = u3i_cell(c, d); - u3_noun q = u3i_trel(a, b, z); - - u3_noun a2 = 0; - u3_noun b2 = 0; - u3_noun c2 = 0; - u3_noun d2 = 0; - - u3x_qual(q, &a2, &b2, &c2, &d2); - - if (a2 != a){ - printf("*** _test_cells_complex: qual() a\n"); - } - if (b2 != b){ - printf("*** _test_cells_complex: qual() b\n"); - } - if (c2 != c){ - printf("*** _test_cells_complex: qual() c\n"); - } - if (d2 != d){ - printf("*** _test_cells_complex: qual() d\n"); - } - } - - // quil - { - // q - // / \ - // a ? - // / \ - // b z - // / \ - // c ? - // / \ - // d e - - // Produce `[a b c d e]`. - u3_noun a = (u3_noun) 0x1; - u3_noun b = (u3_noun) 0x2; - u3_noun c = (u3_noun) 0x3; - u3_noun d = (u3_noun) 0x4; - u3_noun e = (u3_noun) 0x5; - - u3_noun z = u3i_trel(c, d, e); - u3_noun q = u3i_trel(a, b, z); - - u3_noun a2 = 0; - u3_noun b2 = 0; - u3_noun c2 = 0; - u3_noun d2 = 0; - u3_noun e2 = 0; - - u3x_quil(q, &a2, &b2, &c2, &d2, &e2); - - if (a2 != a){ - printf("*** _test_cells_complex: quil() a\n"); - } - if (b2 != b){ - printf("*** _test_cells_complex: quil() b\n"); - } - if (c2 != c){ - printf("*** _test_cells_complex: quil() c\n"); - } - if (d2 != d){ - printf("*** _test_cells_complex: quil() d\n"); - } - if (e2 != e){ - printf("*** _test_cells_complex: quil() e\n"); - } - } - - // hext - { - // q - // / \ - // a ? - // / \ - // b z - // / \ - // c ? - // / \ - // d . - // / \ - // e f - // - // Produce `[a b c d e f]`. - u3_noun a = (u3_noun) 0x1; - u3_noun b = (u3_noun) 0x2; - u3_noun c = (u3_noun) 0x3; - u3_noun d = (u3_noun) 0x4; - u3_noun e = (u3_noun) 0x5; - u3_noun f = (u3_noun) 0x6; - - u3_noun z = u3i_trel(d, e, f); - u3_noun q = u3i_qual(a, b, c, z); - - u3_noun a2 = 0; - u3_noun b2 = 0; - u3_noun c2 = 0; - u3_noun d2 = 0; - u3_noun e2 = 0; - u3_noun f2 = 0; - - u3x_hext(q, &a2, &b2, &c2, &d2, &e2, &f2); - - if (a2 != a){ - printf("*** _test_cells_complex: hext() a\n"); - } - if (b2 != b){ - printf("*** _test_cells_complex: hext() b\n"); - } - if (c2 != c){ - printf("*** _test_cells_complex: hext() c\n"); - } - if (d2 != d){ - printf("*** _test_cells_complex: hext() d\n"); - } - if (e2 != e){ - printf("*** _test_cells_complex: hext() e - e2 = %i\n", e2); - } - if (f2 != f){ - printf("*** _test_cells_complex: hext() f - f2 = %i\n", f2); - } - } -} - -/* _test_imprison_complex(): more complicated into/out-of nouns -*/ -static void -_test_imprison_complex() -{ - // vint - { - u3_noun a = 1; - - u3_noun b= u3i_vint(a); - if (2 != b){ - printf("*** vint 1\n"); - } - - u3_noun c = u3i_vint(b); - if (3 != c){ - printf("*** vint 2\n"); - } - - // XX disabled, 64-bit - // -#if 0 - { - c3_d d = 1ULL << 50; - a = u3i_chubs(1, &d); - b = u3i_vint(a); - - if ((a + 1) != b){ - printf("*** vint 3\n"); - } - } -#endif - } - - // bytes - { - c3_y in_y[10] = { 10, 20, 0xff}; - u3_noun a = u3i_bytes(3, in_y); - - c3_w out_a = u3r_byte(0, a); - if (10 != out_a ){ - printf("*** u3r_byte 1\n"); - } - - c3_w out_b = u3r_byte(1, a); - if (20 != out_b ){ - printf("*** u3r_byte 2\n"); - } - - c3_w out_c = u3r_byte(2, a); - if (0xff != out_c ){ - printf("*** u3r_byte 3\n"); - } - - c3_y out_y[10]; - memset(out_y, 0, 10 * sizeof(c3_y)); - u3r_bytes(0, 3, out_y, a); - - if (10 != out_y[0] || - 20 != out_y[1] || - 0xff != out_y[2] || - 0 != out_y[3] - ){ - printf("*** u3r_byte 4\n"); - } - } - - // words - { - c3_w in_w[10] = {10, 20, 0xffffffff}; - u3_noun noun = u3i_words(3, in_w); - - - c3_w out_a = u3r_word(0, noun); - if (10 != out_a ){ - printf("*** u3r_word 1\n"); - } - - c3_w out_b = u3r_word(1, noun); - if (20 != out_b ){ - printf("*** u3r_word 2\n"); - } - - c3_w out_c = u3r_word(2, noun); - if (0xffffffff != out_c ){ - printf("*** u3r_word 3\n"); - } - - c3_w out_w[10]; - memset(out_w, 0, 10 * sizeof(c3_w)); - u3r_words(0, 3, out_w, noun); - - if (10 != out_w[0] || - 20 != out_w[1] || - 0xffffffff != out_w[2] || - 0 != out_w[3] - ){ - printf("*** u3r_word 4\n"); - } - } - - // chubs - { - c3_d in_d[10] = {1, 2, 0xffffffffffffffffULL}; - - c3_d out_d[10]; - - u3_noun a = u3i_chubs(1, & in_d[0]); - memset(out_d, 0, sizeof(c3_d) * 10); - u3r_chubs(0, 1, out_d, a); - if (1 != out_d[0] ){ - printf("*** u3r_chubs 1\n"); - } - - - u3_noun b = u3i_chubs(1, & in_d[1]); - memset(out_d, 0, sizeof(c3_d) * 10); - u3r_chubs(0, 1, out_d, b); - if (2 != out_d[0] ){ - printf("*** u3r_chubs 2\n"); - } - - u3_noun c = u3i_chubs(1, & in_d[2]); - memset(out_d, 0, sizeof(c3_d) * 10); - u3r_chubs(0, 1, out_d, c); - if (0xffffffffffffffffULL != out_d[0] ){ - printf("*** u3r_chubs 3\n"); - } - - u3_noun d = u3i_chubs(3, in_d); - memset(out_d, 0, sizeof(c3_d) * 10); - u3r_chubs(0, 3, out_d, d); - if (1 != out_d[0] ){ - printf("*** u3r_chubs 4-a\n"); - } - if (2 != out_d[1] ){ - printf("*** u3r_chubs 4-b\n"); - } - if (0xffffffffffffffffULL != out_d[2] ){ - printf("*** u3r_chubs 4-c\n"); - } - } - - // string - { - c3_c * in_c = "a"; - u3_noun noun = u3i_string(in_c); - c3_c* out_c = u3r_string(noun); - - if (0 != strcmp(in_c, out_c)){ - printf("*** u3r_string: in '%s'; out '%s'\n", in_c, out_c); - } - - c3_free(out_c); - in_c = "ab"; - noun = u3i_string(in_c); - out_c = u3r_string(noun); - - if (0 != strcmp(in_c, out_c)){ - printf("*** u3r_string: in '%s'; out '%s'\n", in_c, out_c); - } - - c3_free(out_c); - in_c = "abcd"; - noun = u3i_string(in_c); - out_c = u3r_string(noun); - - if (0 != strcmp(in_c, out_c)){ - printf("*** u3r_string: in '%s'; out '%s'\n", in_c, out_c); - } - - c3_free(out_c); - in_c = "this is a test"; - noun = u3i_string(in_c); - out_c = u3r_string(noun); - - if (0 != strcmp(in_c, out_c)){ - printf("*** u3r_string: in '%s'; out '%s'\n", in_c, out_c); - } - - c3_free(out_c); - } - - // tape - { - c3_c* in_c = "this is a test"; - u3_noun noun = u3i_tape(in_c); - - c3_y* out_y = u3r_tape(noun); - - if (0 != memcmp(in_c, out_y, strlen(in_c))){ - printf("*** u3r_tape 1\n"); - } - - c3_free(out_y); - - // tape stores each byte in the string as one atom in the tree - u3_noun lent = u3qb_lent(noun); - if ( (c3_w)lent != strlen(in_c) ){ - printf("*** u3r_tape 2\n"); - } - } - - // edit - { - - // q - // / \ - // a1 r - // / \ - // b2 s - // / \ - // c3 d4 - - u3_noun a = (u3_noun) 0x1; - u3_noun b = (u3_noun) 0x2; - u3_noun c = (u3_noun) 0x3; - u3_noun d = (u3_noun) 0x4; - - u3_noun s = u3i_cell(c, d); - u3_noun r = u3i_cell(b, s); - u3_noun q = u3i_cell(a, r); - - u3_noun axis = 2; - u3_noun newval = 99; - u3_noun hacked = u3i_edit(q, axis, newval); - - u3_noun read_1; - u3r_mean(hacked, axis, &read_1, 0); - - if (newval != read_1){ - printf("*** u3i_edit 1\n"); - } - } - - // molt - { - - // q - // / \ - // a1 r - // / \ - // b2 s - // / \ - // c3 d4 - - u3_noun a = (u3_noun) 0x1; - u3_noun b = (u3_noun) 0x2; - u3_noun c = (u3_noun) 0x3; - u3_noun d = (u3_noun) 0x4; - - u3_noun s = u3i_cell(c, d); - u3_noun r = u3i_cell(b, s); - u3_noun q = u3i_cell(a, r); - - u3_noun axis_1 = 2; - u3_noun newval_1 = 99; - - u3_noun axis_2 = 6; - u3_noun newval_2 = 777; - - u3_noun hacked = u3i_molt(q, axis_1, newval_1, axis_2, newval_2, 0); - - u3_noun read_1; - u3_noun read_2; - u3r_mean(hacked, axis_1, &read_1, axis_2, &read_2, 0); - - if (newval_1 != read_1){ - printf("*** u3i_molt 1\n"); - } - - if (newval_2 != read_2){ - printf("*** u3i_molt 2\n"); - } - } -} - -/* _test_sing(): Yes iff (a) and (b) are the same noun. -*/ -static void -_test_sing() -{ - // direct noun - // - { - u3_noun a = (u3_noun) 0x1; - u3_noun b = (u3_noun) 0x1; - u3_noun c = (u3_noun) 0x2; - - if (c3y != u3r_sing(a, a)) { - printf("*** sing direct: 1 \n"); - } - - if (c3y != u3r_sing(a, b)) { - printf("*** sing direct: 2 \n"); - } - - if (c3n != u3r_sing(a, c)) { - printf("*** sing direct: 3 \n"); - } - } - - // indirect - // - { - c3_c* in_alpha_c = "abcdefghijklmnopqrstuvwxyz"; - c3_c* in_numer_c = "0123456789001234567890"; - - - u3_noun a = u3i_string(in_alpha_c); - u3_noun b = u3i_string(in_alpha_c); - u3_noun c = u3i_string(in_numer_c); - - if (c3y != u3r_sing(a, a)) { - printf("*** sing indirect: 1 \n"); - } - - if (c3y != u3r_sing(a, b)) { - printf("*** sing indirect: 2 \n"); - } - - if (c3n != u3r_sing(a, c)) { - printf("*** sing indirect: \n"); - } - } -} - -/* _test_fing(): yes same copy of the same noun (ie, pointer equality) -*/ -static void -_test_fing() -{ - // direct noun - // - { - u3_noun a = (u3_noun) 0x1; - u3_noun b = (u3_noun) 0x1; - u3_noun c = (u3_noun) 0x2; - - if (c3y != u3r_fing(a, a)) { - printf("*** fing direct: 1 \n"); - } - - if (c3y != u3r_fing(a, b)) { - printf("*** fing direct: 2 \n"); - } - - if (c3n != u3r_fing(a, c)) { - printf("*** fing direct: 3 \n"); - } - } - - // indirect - // - { - c3_c* in_alpha_c = "abcdefghijklmnopqrstuvwxyz"; - c3_c* in_numer_c = "0123456789001234567890"; - - - u3_noun a = u3i_string(in_alpha_c); - u3_noun b = u3i_string(in_alpha_c); - u3_noun c = u3i_string(in_numer_c); - - if (c3y != u3r_fing(a, a)) { - printf("*** fing indirect: 1 \n"); - } - - if (c3n != u3r_fing(a, b)) { - printf("*** fing indirect: 2 \n"); - } - - if (c3n != u3r_fing(a, c)) { - printf("*** fing indirect: \n"); - } - } -} - -/* _test_met(): 'met' = measure / take size -*/ -static void -_test_met() -{ - c3_w ret_w; - u3_atom atom; - - // 1 - { - atom = 1; - - ret_w = u3r_met(0, atom); - if (1 != ret_w){ - printf("*** _test_met bit of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(3, atom); - if (1 != ret_w){ - printf("*** _test_met byte of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(4, atom); - if (1 != ret_w){ - printf("*** _test_met _w of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(5, atom); - if (1 != ret_w){ - printf("*** _test_met _d of 1 = %d \n", ret_w); - } - } - - // 2 = 0b10 - { - atom = 2; - - ret_w = u3r_met(0, atom); - if (2 != ret_w){ - printf("*** _test_met bit of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(3, atom); - if (1 != ret_w){ - printf("*** _test_met byte of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(5, atom); - if (1 != ret_w){ - printf("*** _test_met _w of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(6, atom); - if (1 != ret_w){ - printf("*** _test_met _d of 1 = %d \n", ret_w); - } - } - - // 8=0b1000 - { - atom = 8; - - ret_w = u3r_met(0, atom); - if (4 != ret_w){ - printf("*** _test_met bit of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(3, atom); - if (1 != ret_w){ - printf("*** _test_met byte of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(5, atom); - if (1 != ret_w){ - printf("*** _test_met _w of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(6, atom); - if (1 != ret_w){ - printf("*** _test_met _d of 1 = %d \n", ret_w); - } - } - - // 0xff = 255 =0b 1111 1111 - { - atom = 0xff; - - ret_w = u3r_met(0, atom); - if (8 != ret_w){ - printf("*** _test_met bit of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(3, atom); - if (1 != ret_w){ - printf("*** _test_met byte of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(5, atom); - if (1 != ret_w){ - printf("*** _test_met _w of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(6, atom); - if (1 != ret_w){ - printf("*** _test_met _d of 1 = %d \n", ret_w); - } - } - - // 0x100 = 256 =0b 0001 1111 1111 - { - atom = 0x100; - - ret_w = u3r_met(0, atom); - if (9 != ret_w){ - printf("*** _test_met bit of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(3, atom); - if (2 != ret_w){ - printf("*** _test_met byte of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(5, atom); - if (1 != ret_w){ - printf("*** _test_met _w of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(6, atom); - if (1 != ret_w){ - printf("*** _test_met _d of 1 = %d \n", ret_w); - } - } - - // XX disabled, 64-bit - // -#if 0 - // 32 bit direct - // 0x ff ff ff ff - { - atom = 0xffffffffULL; - - ret_w = u3r_met(0, atom); - if (32 != ret_w){ - printf("*** _test_met bit of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(3, atom); - if (4 != ret_w){ - printf("*** _test_met byte of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(5, atom); - if (1 != ret_w){ - printf("*** _test_met _w of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(6, atom); - if (1 != ret_w){ - printf("*** _test_met _d of 1 = %d \n", ret_w); - } - } -#endif - - // 4 words x 32 bits each = 128 bits = 16 bytes = 4 words = 2 doubles - // - { - c3_w data_w[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; - atom = u3i_words(4, data_w); - - ret_w = u3r_met(0, atom); - if (128 != ret_w){ - printf("*** _test_met bit of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(3, atom); - if (16 != ret_w){ - printf("*** _test_met byte of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(5, atom); - if (4 != ret_w){ - printf("*** _test_met _w of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(6, atom); - if (2 != ret_w){ - printf("*** _test_met _d of 1 = %d \n", ret_w); - } - } - - // 4 words (top word is '1' ) - // - { - c3_w data_w[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 1 }; - atom = u3i_words(4, data_w); - - ret_w = u3r_met(0, atom); - if (97 != ret_w){ - printf("*** _test_met bit of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(3, atom); - if (13 != ret_w){ - printf("*** _test_met byte of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(5, atom); - if (4 != ret_w){ - printf("*** _test_met _w of 1 = %d \n", ret_w); - } - - ret_w = u3r_met(6, atom); - if (2 != ret_w){ - printf("*** _test_met _d of 1 = %d \n", ret_w); - } - } -} - -/* _test_u3r_at(): inspect cells at arbitrary axis locations -** [ and utility function u3x_dep() ] -*/ -static void -_test_u3r_at() -{ - c3_w a_w = u3x_dep(0); - - if (0xffffffff != a_w) { printf("*** u3x_dep() \n"); } - - a_w = u3x_dep(1); - if (0 != a_w) { printf("*** u3x_dep() \n"); } - - a_w = u3x_dep(0b10); - if (1 != a_w) { printf("*** u3x_dep() \n"); } - - a_w = u3x_dep(0b11); - if (1 != a_w) { printf("*** u3x_dep() \n"); } - - a_w = u3x_dep(0b100); - if (2 != a_w) { printf("*** u3x_dep() \n"); } - - a_w = u3x_dep(0b110); - if (2 != a_w) { printf("*** u3x_dep() \n"); } - - a_w = u3x_dep(0b111); - if (2 != a_w) { printf("*** u3x_dep() \n"); } - - a_w = u3x_dep( ((c3_w) (((c3_d) 1 << 32) - 1)) ); - if (31 != a_w) { printf("*** u3x_dep() \n"); } - - - // XX disabled, 64-bit - // -#if 0 - a_w = u3x_dep_d(0); - a_w = u3x_dep_d(1); - a_w = u3x_dep_d(0b10); - a_w = u3x_dep_d(0b11); - a_w = u3x_dep_d(0b100); - a_w = u3x_dep_d( ((c3_w) (((c3_d) 1 << 32) - 1)) ); - a_w = u3x_dep_d( ((c3_w) (((c3_d) 1 << 33) - 1)) ); - a_w = u3x_dep_d( ((c3_d) (((c3_d) 1 << 64) - 1)) ); -#endif - - u3_weak ret; - - // addr 1 in atom == atom value - u3_noun tree = 1; - ret = u3r_at( 1, tree); - if (1 != ret) { printf("*** u3r_at()\n"); } - - // addr 1 in atom == atom value - tree = 2; - ret = u3r_at( 1, tree); - if (2 != ret) { printf("*** u3r_at \n"); } - - // illegal - ret = u3r_at( 2, tree); - if (u3_none != ret) { printf("*** u3r_at \n"); } - - - // simple tree [ 1 2] - tree = u3i_cell(10, 20); - ret = u3r_at( 1, tree); - if (tree != ret) { printf("*** u3r_at \n"); } - - ret = u3r_at( 2, tree); - if (10 != ret) { printf("*** u3r_at \n"); } - ret = u3r_at( 3, tree); - if (20 != ret) { printf("*** u3r_at \n"); } - - // simple tree [ 1 ] - c3_w in_w[10] = {10, 20, 0xffffffff}; - u3_noun bignum = u3i_words(3, in_w); - - tree = u3i_cell(99, bignum); - ret = u3r_at( 2, tree); - if (99 != ret) { printf("*** u3r_at \n"); } - ret = u3r_at( 3, tree); - if (bignum != ret) { printf("*** u3r_at \n"); } -} - -// XX disabled, static functions -// -#if 0 -void _n_push(c3_ys mov, c3_ys off, u3_noun a); -u3_noun * _n_peek(c3_ys off); -u3_noun* _n_peet(c3_ys mov, c3_ys off); -void _n_pop(c3_ys mov); -u3_noun _n_pep(c3_ys mov, c3_ys off); -void _n_toss(c3_ys mov, c3_ys off); -u3_noun* _n_swap(c3_ys mov, c3_ys off); - -/* _test_nvm_stack_inner(): -*/ -void -_test_nvm_stack_inner(c3_ys mov, c3_ys off) -{ - u3_noun * peek; - - // push 1, peek, pop - if(1) { - _n_push(mov, off, 0x1122334455667788); - peek = _n_peek(off); - if (0x1122334455667788 != *peek) { printf("*** test_nvm_stack 1\n"); } - _n_pop(mov); - } - - // push 2, peek, pop, peek, pop - if(1) { - _n_push(mov, off, 88); - _n_push(mov, off, 99); - peek = _n_peek(off); - if (99 != *peek) { printf("*** test_nvm_stack 2\n"); } - _n_pop(mov); - peek = _n_peek(off); - if (88 != *peek) { printf("*** test_nvm_stack 3\n"); } - _n_pop(mov); - } - - // 100 x (push, peek, pop) - { - int ii; - for (ii=0; ii <= 100; ii++){ - _n_push(mov, off, (u3_noun) ii); - } - for (ii=100; ii >= 0; ii--){ - peek = _n_peek(off); - if (ii != *peek) { printf("*** test_nvm_stack 4\n"); } - _n_pop(mov); - } - } - - // peet() - { - _n_push(mov, off, 333); - _n_push(mov, off, 444); - - peek = _n_peet(mov, off); - if (333 != *peek) { printf("*** test_nvm_stack 5\n"); } - - _n_push(mov, off, 555); - peek = _n_peet(mov, off); - if (444 != *peek) { printf("*** test_nvm_stack 6\n"); } - } - - // pep() - { - _n_push(mov, off, 777); - u3_noun ret = _n_pep(mov, off); - if (777 != ret) { printf("*** test_nvm_stack 7\n"); } - - - _n_push(mov, off, 777); - _n_push(mov, off, 888); - ret = _n_pep(mov, off); - if (888 != ret) { printf("*** test_nvm_stack 8\n"); } - ret = _n_pep(mov, off); - if (777 != ret) { printf("*** test_nvm_stack 9\n"); } - - } - - // toss - { - _n_push(mov, off, 2777); - _n_push(mov, off, 3888); - _n_toss(mov, off); - u3_noun ret = _n_pep(mov, off); - if (2777 != ret) { printf("*** test_nvm_stack 10\n"); } - - } - - // swap - { - _n_push(mov, off, 2002); - _n_push(mov, off, 3003); - _n_swap(mov, off); - u3_noun ret = _n_pep(mov, off); - if (2002 != ret) { printf("*** test_nvm_stack 11\n"); } - ret = _n_pep(mov, off); - if (3003 != ret) { printf("*** test_nvm_stack 12\n"); } - - } -} - -/* _test_nvm_stack_south(): test the stack usage in an inner, south road -*/ -u3_noun -_test_nvm_stack_south(u3_noun arg) -{ - c3_ys mov = 2; - c3_ys off = -2; - - _test_nvm_stack_inner(mov, off); - - return u3_nul; -} -#endif - -/* _test_nvm_stack(): test the stack usage of the bytecode interpreter -** (growing in both directions: N and S) -*/ -static void -_test_nvm_stack() -{ - // XX disabled, static functions - // XX rewrite to use u3a_push/u3a_pop? - // -#if 0 - // north road - c3_ys mov = -2; - c3_ys off = 0; - _test_nvm_stack_inner(mov, off); - - // south road - u3m_soft(100, &_test_nvm_stack_south, 0); -#endif -} - -static c3_i -_test_noun(void) -{ - c3_i ret_i = 1; - - if ( !_test_chop() ) { - fprintf(stderr, "test noun: chop failed\r\n"); - ret_i = 0; - } - - return ret_i; -} - -/* main(): run all test cases. -*/ -int -main(int argc, char* argv[]) -{ - _setup(); - - if ( !_test_noun() ) { - fprintf(stderr, "test noun: failed\r\n"); - exit(1); - } - - // GC - // - u3m_grab(u3_none); - - // XX the following tests leak memory - // fix and move to _test_noun() - // - _test_noun_bits_set(); - _test_noun_bits_read(); - _test_imprison(); - _test_imprison_complex(); - _test_sing(); - _test_fing(); - _test_met(); - _test_cells(); - _test_cells_complex(); - _test_u3r_at(); - _test_nvm_stack(); - - fprintf(stderr, "test_noun: ok\n"); - - return 0; -} diff --git a/pkg/urbit/tests/unix_tests.c b/pkg/urbit/tests/unix_tests.c deleted file mode 100644 index ca247f5ef..000000000 --- a/pkg/urbit/tests/unix_tests.c +++ /dev/null @@ -1,65 +0,0 @@ -#include "all.h" -#include "vere/vere.h" - -/* _setup(): prepare for tests. -*/ -static void -_setup(void) -{ -} - -/* _test_safe(): -*/ -static c3_i -_test_safe() -{ - c3_i ret_i = 1; - - if ( !u3_unix_cane("/") || - !u3_unix_cane("~.") || - !u3_unix_cane("a") || - !u3_unix_cane("a/b") || - !u3_unix_cane("a/b/c/defg/h/ijklmnop") ) - { - fprintf(stderr, "_safe fail 1\n"); - ret_i = 0; - } - - if ( u3_unix_cane("") || - u3_unix_cane(".") || - u3_unix_cane("..") || - u3_unix_cane("/.") || - u3_unix_cane("a/b/c//") || - u3_unix_cane("a/b/.") || - u3_unix_cane("/././../.") || - u3_unix_cane("/../etc") ) - { - fprintf(stderr, "_safe fail 2\r\n"); - ret_i = 0; - } - - if ( !u3_unix_cane(".a") || - !u3_unix_cane("/.a.b.c/..c") ) - { - fprintf(stderr, "_safe fail 3\r\n"); - ret_i = 0; - } - - return ret_i; -} - -/* main(): run all test cases. -*/ -int -main(int argc, char* argv[]) -{ - _setup(); - - if ( !_test_safe() ) { - fprintf(stderr, "test unix: failed\r\n"); - exit(1); - } - - fprintf(stderr, "test unix: ok\r\n"); - return 0; -} diff --git a/pkg/urbit/tests/ur_tests.c b/pkg/urbit/tests/ur_tests.c deleted file mode 100644 index 1e590e572..000000000 --- a/pkg/urbit/tests/ur_tests.c +++ /dev/null @@ -1,1860 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "ur/ur.h" - -/* -** initialize helper for bitstream-writer tests. -*/ -static void -_bsw_reinit(ur_bsw_t *bsw, uint64_t prev, uint64_t size) -{ - bsw->prev = prev; - bsw->size = size; - bsw->bits = 0; - bsw->fill = 0; - bsw->off = 0; - - free(bsw->bytes); - bsw->bytes = calloc(size, 1); -} - -/* -** check bitstream-writer test invariants. -*/ -static int -_bsw_bit_check(const char* cap, ur_bsw_t *bsw, uint8_t byt, uint8_t off) -{ - int ret = 1; - - if ( !ur_bsw_sane(bsw) ) { - fprintf(stderr, "%s: insane off=%u fill=%" PRIu64 " bits=%" PRIu64 "\r\n", - cap, bsw->off, bsw->fill, bsw->bits); - ret = 0; - } - - if ( byt != bsw->bytes[0] ) { - fprintf(stderr, "%s: bytes fail (%u, %u)\r\n", cap, byt, bsw->bytes[0]); - ret = 0; - } - - if ( off != bsw->off ) { - fprintf(stderr, "%s: offset fail (%u, %u)\r\n", cap, off, bsw->off); - ret = 0; - } - - return ret; -} - -/* -** test 8 sequential writes of a set bit. -*/ -static int -_test_bsw_bit_ones(void) -{ - int ret = 1; - ur_bsw_t bsw = {0}; - _bsw_reinit(&bsw, 1, 1); - - ret &= _bsw_bit_check("bsw ones init", &bsw, 0x0, 0); - - ur_bsw_bit(&bsw, 1); - ret &= _bsw_bit_check("bsw ones a", &bsw, 0x1, 1); - - ur_bsw_bit(&bsw, 1); - ret &= _bsw_bit_check("bsw ones b", &bsw, 0x3, 2); - - ur_bsw_bit(&bsw, 1); - ret &= _bsw_bit_check("bsw ones c", &bsw, 0x7, 3); - - ur_bsw_bit(&bsw, 1); - ret &= _bsw_bit_check("bsw ones d", &bsw, 0xf, 4); - - ur_bsw_bit(&bsw, 1); - ret &= _bsw_bit_check("bsw ones e", &bsw, 0x1f, 5); - - ur_bsw_bit(&bsw, 1); - ret &= _bsw_bit_check("bsw ones f", &bsw, 0x3f, 6); - - ur_bsw_bit(&bsw, 1); - ret &= _bsw_bit_check("bsw ones g", &bsw, 0x7f, 7); - - ur_bsw_bit(&bsw, 1); - ret &= _bsw_bit_check("bsw ones h", &bsw, 0xff, 0); - - if ( bsw.size != 2 ) { - fprintf(stderr, "bsw ones grow: fail\r\n"); - ret = 0; - } - - free(bsw.bytes); - - return ret; -} - -/* -** test 8 sequential writes of 1 null bit. -*/ -static int -_test_bsw_bit_zeros(void) -{ - int ret = 1; - ur_bsw_t bsw = {0}; - _bsw_reinit(&bsw, 1, 1); - - ret &= _bsw_bit_check("bsw zeros init", &bsw, 0x0, 0); - - ur_bsw_bit(&bsw, 0); - ret &= _bsw_bit_check("bsw zeros a", &bsw, 0x0, 1); - - ur_bsw_bit(&bsw, 0); - ret &= _bsw_bit_check("bsw zeros b", &bsw, 0x0, 2); - - ur_bsw_bit(&bsw, 0); - ret &= _bsw_bit_check("bsw zeros c", &bsw, 0x0, 3); - - ur_bsw_bit(&bsw, 0); - ret &= _bsw_bit_check("bsw zeros d", &bsw, 0x0, 4); - - ur_bsw_bit(&bsw, 0); - ret &= _bsw_bit_check("bsw zeros e", &bsw, 0x0, 5); - - ur_bsw_bit(&bsw, 0); - ret &= _bsw_bit_check("bsw zeros f", &bsw, 0x0, 6); - - ur_bsw_bit(&bsw, 0); - ret &= _bsw_bit_check("bsw zeros g", &bsw, 0x0, 7); - - ur_bsw_bit(&bsw, 0); - ret &= _bsw_bit_check("bsw zeros h", &bsw, 0x0, 0); - - if ( bsw.size != 2 ) { - fprintf(stderr, "bsw zeros grow: fail\r\n"); - ret = 0; - } - - free(bsw.bytes); - - return ret; -} - -/* -** test 8 sequential writes of alternating bits. -*/ -static int -_test_bsw_bit_alt(void) -{ - int ret = 1; - ur_bsw_t bsw = {0}; - _bsw_reinit(&bsw, 1, 1); - - ret &= _bsw_bit_check("bsw alt init", &bsw, 0x0, 0); - - ur_bsw_bit(&bsw, 0); - ret &= _bsw_bit_check("bsw alt a", &bsw, 0x0, 1); - - ur_bsw_bit(&bsw, 1); - ret &= _bsw_bit_check("bsw alt b", &bsw, 0x2, 2); - - ur_bsw_bit(&bsw, 0); - ret &= _bsw_bit_check("bsw alt c", &bsw, 0x2, 3); - - ur_bsw_bit(&bsw, 1); - ret &= _bsw_bit_check("bsw alt d", &bsw, 0xa, 4); - - ur_bsw_bit(&bsw, 0); - ret &= _bsw_bit_check("bsw alt e", &bsw, 0xa, 5); - - ur_bsw_bit(&bsw, 1); - ret &= _bsw_bit_check("bsw alt f", &bsw, 0x2a, 6); - - ur_bsw_bit(&bsw, 0); - ret &= _bsw_bit_check("bsw alt g", &bsw, 0x2a, 7); - - ur_bsw_bit(&bsw, 1); - ret &= _bsw_bit_check("bsw alt h", &bsw, 0xaa, 0); - - if ( bsw.size != 2 ) { - fprintf(stderr, "bsw alt grow: fail\r\n"); - ret = 0; - } - - free(bsw.bytes); - - return ret; -} - -static int -_test_bsw_bit(void) -{ - return _test_bsw_bit_ones() - & _test_bsw_bit_zeros() - & _test_bsw_bit_alt(); -} - -/* -** subsequents bitstream-writer tests assume the correctnesss of -** ur_bsw_bit(), and compare the output of a bit-at-a-time -** "golden master" with that of the relevant, higher-level operation. -** -** XX the "golden" master implementations shouldn't be in bitstream module, -** as we don't intend to run them, but it's kind of weird implement them -** in the test itself. -** -*/ -static int -_bsw_cmp_check(const char* cap, uint8_t val, uint8_t off, uint8_t len, ur_bsw_t *a, ur_bsw_t *b) -{ - int ret = 1; - - if ( !ur_bsw_sane(a) ) { - fprintf(stderr, "%s: val 0x%02x off %u, len %u: a insane off=%u fill=%" PRIu64 " bits=%" PRIu64 "\r\n", - cap, val, off, len, a->off, a->fill, a->bits); - ret = 0; - } - if ( !ur_bsw_sane(b) ) { - fprintf(stderr, "%s: val 0x%02x off %u len %u: b insane off=%u fill=%" PRIu64 " bits=%" PRIu64 "\r\n", - cap, val, off, len, b->off, b->fill, b->bits); - ret = 0; - } - - if ( a->off != b->off ) { - fprintf(stderr, "%s: val 0x%02x off %u len %u: offset fail (%u, %u)\r\n", - cap, val, off, len, a->off, b->off); - ret = 0; - } - - if ( a->fill != b->fill ) { - fprintf(stderr, "%s: val 0x%02x off %u len %u: fill fail (%" PRIu64 ", %" PRIu64 ")\r\n", - cap, val, off, len, a->fill, b->fill); - ret = 0; - } - - { - uint64_t k, len_byt = a->fill + !!a->off; - - if ( memcmp(a->bytes, b->bytes, len_byt) ) { - fprintf(stderr, "%s: val 0x%02x off %u, len %u not equal off=%u fill=%" PRIu64 "\r\n", - cap, val, off, len, b->off, b->fill); - fprintf(stderr, " a: { "); - for ( k = 0; k < len_byt; k++ ) { - fprintf(stderr, "%02x, ", a->bytes[k]); - } - fprintf(stderr, "}\r\n"); - fprintf(stderr, " b: { "); - for ( k = 0; k < len_byt; k++ ) { - fprintf(stderr, "%02x, ", b->bytes[k]); - } - fprintf(stderr, "}\r\n"); - ret = 0; - } - } - - return ret; -} - -/* -** ur_bsw8 golden master -*/ -static void -_bsw8_slow(ur_bsw_t *bsw, uint8_t len, uint8_t byt) -{ - len = ur_min(8, len); - - while ( len ) { - ur_bsw_bit(bsw, byt); - byt >>= 1; - len--; - } -} - -/* -** at varying offsets, write varying numbers of bits via -** ur_bsw8 and master, comparing the result each time. -*/ -static int -_test_bsw8_loop(const char* cap, uint8_t val) -{ - int ret = 1; - ur_bsw_t a = {0}; - ur_bsw_t b = {0}; - uint8_t i, j; - - for ( i = 0; i < 8; i++) { - for ( j = 0; j <= 8; j++ ) { - _bsw_reinit(&a, 1, 1); - _bsw_reinit(&b, 1, 1); - a.off = a.bits = b.off = b.bits = i; - - _bsw8_slow(&a, j, val); - ur_bsw8(&b, j, val); - - ret &= _bsw_cmp_check(cap, val, i, j, &a, &b); - } - } - - return ret; -} - -static int -_test_bsw8(void) -{ - return _test_bsw8_loop("bsw bits ones", 0xff) - & _test_bsw8_loop("bsw bits zeros", 0x0) - & _test_bsw8_loop("bsw bits alt 1", 0xaa) - & _test_bsw8_loop("bsw bits alt 2", 0x55); -} - -/* -** ur_bsw32 golden master -*/ -static void -_bsw32_slow(ur_bsw_t *bsw, uint8_t len, uint32_t val) -{ - len = ur_min(32, len); - - while ( len ) { - ur_bsw_bit(bsw, val & 0xff); - val >>= 1; - len--; - } -} - -/* -** at varying offsets, write varying numbers of bits via -** ur_bsw32 and master, comparing the result each time. -*/ -static int -_test_bsw32_loop(const char* cap, uint32_t val) -{ - int ret = 1; - ur_bsw_t a = {0}; - ur_bsw_t b = {0}; - uint8_t i, j; - - for ( i = 0; i < 8; i++) { - for ( j = 0; j <= 32; j++ ) { - _bsw_reinit(&a, 1, 1); - _bsw_reinit(&b, 1, 1); - a.off = a.bits = b.off = b.bits = i; - - _bsw32_slow(&a, j, val); - ur_bsw32(&b, j, val); - - ret &= _bsw_cmp_check(cap, val, i, j, &a, &b); - } - } - - return ret; -} - -static int -_test_bsw32(void) -{ - return _test_bsw32_loop("bsw 32 ones", 0xffffffff) - & _test_bsw32_loop("bsw 32 zeros", 0x0) - & _test_bsw32_loop("bsw 32 alt 1", 0xaaaaaaaa) - & _test_bsw32_loop("bsw 32 alt 2", 0x55555555); -} - -/* -** ur_bsw64 golden master -*/ -static void -_bsw64_slow(ur_bsw_t *bsw, uint8_t len, uint64_t val) -{ - len = ur_min(64, len); - - while ( len ) { - ur_bsw_bit(bsw, val & 0xff); - val >>= 1; - len--; - } -} - -/* -** at varying offsets, write varying numbers of bits via -** ur_bsw64 and master, comparing the result each time. -*/ -static int -_test_bsw64_loop(const char* cap, uint64_t val) -{ - int ret = 1; - ur_bsw_t a = {0}; - ur_bsw_t b = {0}; - uint8_t i, j; - - for ( i = 0; i < 8; i++) { - for ( j = 0; j <= 64; j++ ) { - _bsw_reinit(&a, 1, 1); - _bsw_reinit(&b, 1, 1); - a.off = a.bits = b.off = b.bits = i; - - _bsw64_slow(&a, j, val); - ur_bsw64(&b, j, val); - - ret &= _bsw_cmp_check(cap, val, i, j, &a, &b); - } - } - - return ret; -} - -static int -_test_bsw64(void) -{ - return _test_bsw64_loop("bsw 64 ones", 0xffffffffffffffffULL) - & _test_bsw64_loop("bsw 64 zeros", 0x0ULL) - & _test_bsw64_loop("bsw 64 alt 1", 0xaaaaaaaaaaaaaaaaULL) - & _test_bsw64_loop("bsw 64 alt 2", 0x5555555555555555ULL); -} - -/* -** ur_bsw_bytes() golden master -*/ -static void -_bsw_bytes_slow(ur_bsw_t *bsw, uint64_t len, uint8_t *byt) -{ - uint64_t i, len_byt = len >> 3; - - for ( i = 0; i < len_byt; i++ ) { - _bsw8_slow(bsw, 8, byt[i]); - len -= 8; - } - - _bsw8_slow(bsw, len, byt[len_byt]); -} - -/* -** at varying offsets, write varying numbers of bits via -** ur_bsw_bytes and master, comparing the result each time. -*/ -static int -_test_bsw_bytes_loop(const char* cap, uint64_t len, uint8_t val) -{ - int ret = 1; - ur_bsw_t a = {0}; - ur_bsw_t b = {0}; - uint8_t i, j, *byt; - uint64_t len_bit = len << 3; - - byt = malloc(len); - memset(byt, val, len); - - for ( i = 0; i < 8; i++) { - for ( j = 0; j < len_bit; j++ ) { - _bsw_reinit(&a, 1, 1); - _bsw_reinit(&b, 1, 1); - a.off = a.bits = b.off = b.bits = i; - - _bsw_bytes_slow(&a, j, byt); - ur_bsw_bytes(&b, j, byt); - - ret &= _bsw_cmp_check(cap, val, i, j, &a, &b); - } - } - - free(byt); - - return ret; -} - -static int -_test_bsw_bytes(void) -{ - return _test_bsw_bytes_loop("bsw bytes nought", 0, 0x0) - & _test_bsw_bytes_loop("bsw bytes ones odd", 3, 0xff) - & _test_bsw_bytes_loop("bsw bytes ones even", 4, 0xff) - & _test_bsw_bytes_loop("bsw bytes zeros odd", 5, 0x0) - & _test_bsw_bytes_loop("bsw bytes zeros even", 6, 0x0) - & _test_bsw_bytes_loop("bsw bytes alt 1 odd", 7, 0xaa) - & _test_bsw_bytes_loop("bsw bytes alt 1 even", 8, 0xaa) - & _test_bsw_bytes_loop("bsw bytes alt 2 odd", 9, 0x55) - & _test_bsw_bytes_loop("bsw bytes alt 2 even", 10, 0x55); -} - -/* -** ur_bsw_bex golden master -*/ -static void -_bsw_bex_slow(ur_bsw_t *bsw, uint8_t n) -{ - while ( n >= 64 ) { - _bsw64_slow(bsw, 64, 0); - n -= 64; - } - - _bsw64_slow(bsw, n + 1, 1ULL << n); -} - -/* -** at varying offsets, write varying numbers of bits via -** ur_bsw_bex and master, comparing the result each time. -*/ -static int -_test_bsw_bex() -{ - int ret = 1; - ur_bsw_t a = {0}; - ur_bsw_t b = {0}; - uint8_t i; - uint32_t j; - - for ( i = 0; i < 8; i++) { - for ( j = 0; j < 256; j++ ) { - _bsw_reinit(&a, 1, 1); - _bsw_reinit(&b, 1, 1); - a.off = a.bits = b.off = b.bits = i; - - _bsw_bex_slow(&a, j); - ur_bsw_bex(&b, j); - - ret &= _bsw_cmp_check("bsw bex", j, i, j + 1, &a, &b); - } - } - - return ret; -} - -static int -_test_bsw(void) -{ - return _test_bsw_bit() - & _test_bsw8() - & _test_bsw32() - & _test_bsw64() - & _test_bsw_bytes() - & _test_bsw_bex(); -} - -/* -** check bitstream-reader test invariants. -*/ -static int -_bsr_bit_check(const char *cap, - ur_bsr_t *bsr, - uint8_t off, - uint64_t bits, - uint8_t exp, - uint8_t val, - ur_cue_res_e ser, - ur_cue_res_e res) -{ - int ret = 1; - - if ( !ur_bsr_sane(bsr) ) { - fprintf(stderr, "%s: insane off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", - cap, bsr->off, bsr->left, bsr->bits); - ret = 0; - } - - if ( ser != res ) { - fprintf(stderr, "%s: res not equal (%s, %s) off=%u left=%" PRIu64 " byte=%02x bits=%" PRIu64 "\r\n", - cap, (ur_cue_good == ser) ? "good" : "gone", - (ur_cue_good == res) ? "good" : "gone", - bsr->off, bsr->left, bsr->left ? bsr->bytes[0] : 0, bsr->bits); - ret = 0; - } - - if ( (ur_cue_good == res) && (exp != val) ) { - fprintf(stderr, "%s: val not equal (%02x, %02x) off=%u left=%" PRIu64 " byte=%02x bits=%" PRIu64 "\r\n", - cap, exp, val, bsr->off, bsr->left, bsr->left ? bsr->bytes[0] : 0, bsr->bits); - ret = 0; - } - - if ( off != bsr->off ) { - fprintf(stderr, "%s: offset fail (%u, %u)\r\n", cap, off, bsr->off); - ret = 0; - } - - if ( bits != bsr->bits ) { - fprintf(stderr, "%s: bits fail (%" PRIu64 ", %" PRIu64 ")\r\n", cap, bits, bsr->bits); - ret = 0; - } - - return ret; -} - -/* -** read a bit 8 times from a bitstream initialized to all ones, -** checking invariants and result after each read. -*/ -static int -_test_bsr_bit_ones(void) -{ - int ret = 1; - uint8_t ones[1] = { 0xff }; - ur_bsr_t bsr = { .left = sizeof(ones), .bytes = ones }; - uint8_t out; - ur_cue_res_e res; - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 1", &bsr, 1, 1, ur_cue_good, res, 1, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 2", &bsr, 2, 2, ur_cue_good, res, 1, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 3", &bsr, 3, 3, ur_cue_good, res, 1, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 4", &bsr, 4, 4, ur_cue_good, res, 1, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 5", &bsr, 5, 5, ur_cue_good, res, 1, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 6", &bsr, 6, 6, ur_cue_good, res, 1, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 7", &bsr, 7, 7, ur_cue_good, res, 1, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 8", &bsr, 0, 8, ur_cue_good, res, 1, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 9", &bsr, 0, 8, ur_cue_gone, res, 0, 0); - - return ret; -} - -/* -** read a bit 8 times from a bitstream initialized to all zeros, -** checking invariants and result after each read. -*/ -static int -_test_bsr_bit_zeros(void) -{ - int ret = 1; - uint8_t ones[1] = { 0x0 }; - ur_bsr_t bsr = { .left = sizeof(ones), .bytes = ones }; - uint8_t out; - ur_cue_res_e res; - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 1", &bsr, 1, 1, ur_cue_good, res, 0, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 2", &bsr, 2, 2, ur_cue_good, res, 0, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 3", &bsr, 3, 3, ur_cue_good, res, 0, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 4", &bsr, 4, 4, ur_cue_good, res, 0, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 5", &bsr, 5, 5, ur_cue_good, res, 0, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 6", &bsr, 6, 6, ur_cue_good, res, 0, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 7", &bsr, 7, 7, ur_cue_good, res, 0, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 8", &bsr, 0, 8, ur_cue_good, res, 0, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 9", &bsr, 0, 8, ur_cue_gone, res, 0, 0); - - return ret; -} - -/* -** read a bit 8 times from a bitstream initialized to alternating zeros and ones, -** checking invariants and result after each read. -*/ -static int -_test_bsr_bit_alt(void) -{ - int ret = 1; - uint8_t ones[1] = { 0xaa }; - ur_bsr_t bsr = { .left = sizeof(ones), .bytes = ones }; - uint8_t out; - ur_cue_res_e res; - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 1", &bsr, 1, 1, ur_cue_good, res, 0, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 2", &bsr, 2, 2, ur_cue_good, res, 1, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 3", &bsr, 3, 3, ur_cue_good, res, 0, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 4", &bsr, 4, 4, ur_cue_good, res, 1, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 5", &bsr, 5, 5, ur_cue_good, res, 0, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 6", &bsr, 6, 6, ur_cue_good, res, 1, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 7", &bsr, 7, 7, ur_cue_good, res, 0, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 8", &bsr, 0, 8, ur_cue_good, res, 1, out); - - res = ur_bsr_bit(&bsr, &out); - ret &= _bsr_bit_check("bsr bit ones 9", &bsr, 0, 8, ur_cue_gone, res, 0, 0); - - return ret; -} - -static int -_test_bsr_bit(void) -{ - return _test_bsr_bit_ones() - & _test_bsr_bit_zeros() - & _test_bsr_bit_alt(); -} - -/* -** check bitstream-reader test invariants, after (maybe) reading -** of the end of the stream. -*/ -static int -_bsr_bit_any_check(const char* cap, ur_bsr_t *bsr, uint8_t off, uint64_t bits, uint8_t exp, uint8_t val) -{ - int ret = 1; - - if ( !ur_bsr_sane(bsr) ) { - fprintf(stderr, "%s: insane off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", - cap, bsr->off, bsr->left, bsr->bits); - ret = 0; - } - - if ( exp != val ) { - fprintf(stderr, "%s: not equal (%02x, %02x) off=%u left=%" PRIu64 " byte=%02x bits=%" PRIu64 "\r\n", - cap, exp, val, bsr->off, bsr->left, bsr->left ? bsr->bytes[0] : 0, bsr->bits); - ret = 0; - } - - if ( off != bsr->off ) { - fprintf(stderr, "%s: offset fail (%u, %u)\r\n", cap, off, bsr->off); - ret = 0; - } - - if ( bits != bsr->bits ) { - fprintf(stderr, "%s: bits fail (%" PRIu64 ", %" PRIu64 ")\r\n", cap, bits, bsr->bits); - ret = 0; - } - - return ret; -} - -/* -** read a bit 17 times from a bitstream initialized to 8 ones, -** checking invariants and result after each read. -*/ -static int -_test_bsr_bit_any_ones(void) -{ - int ret = 1; - uint8_t ones[1] = { 0xff }; - ur_bsr_t bsr = { .left = sizeof(ones), .bytes = ones }; - uint8_t out; - - ret &= _bsr_bit_any_check("bsr bit-any ones init", &bsr, 0, 0, 0, 0); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones 1", &bsr, 1, 1, 1, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones 2", &bsr, 2, 2, 1, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones 3", &bsr, 3, 3, 1, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones 4", &bsr, 4, 4, 1, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones 5", &bsr, 5, 5, 1, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones 6", &bsr, 6, 6, 1, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones 7", &bsr, 7, 7, 1, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones 8", &bsr, 0, 8, 1, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones off 9", &bsr, 0, 9, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones off 10", &bsr, 0, 10, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones off 11", &bsr, 0, 11, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones off 12", &bsr, 0, 12, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones off 13", &bsr, 0, 13, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones off 14", &bsr, 0, 14, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones off 15", &bsr, 0, 15, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones off 16", &bsr, 0, 16, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any ones off 17", &bsr, 0, 17, 0, out); - - return ret; -} - -/* -** read a bit 17 times from a bitstream initialized to 8 zeros, -** checking invariants and result after each read. -*/ -static int -_test_bsr_bit_any_zeros(void) -{ - int ret = 1; - uint8_t ones[1] = { 0x0 }; - ur_bsr_t bsr = { .left = sizeof(ones), .bytes = ones }; - uint8_t out; - - ret &= _bsr_bit_any_check("bsr bit-any zeros init", &bsr, 0, 0, 0, 0); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros 1", &bsr, 1, 1, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros 2", &bsr, 2, 2, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros 3", &bsr, 3, 3, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros 4", &bsr, 4, 4, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros 5", &bsr, 5, 5, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros 6", &bsr, 6, 6, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros 7", &bsr, 7, 7, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros 8", &bsr, 0, 8, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros off 9", &bsr, 0, 9, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros off 10", &bsr, 0, 10, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros off 11", &bsr, 0, 11, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros off 12", &bsr, 0, 12, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros off 13", &bsr, 0, 13, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros off 14", &bsr, 0, 14, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros off 15", &bsr, 0, 15, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros off 16", &bsr, 0, 16, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any zeros off 17", &bsr, 0, 17, 0, out); - - return ret; -} - -/* -** read a bit 17 times from a bitstream initialized to 8 bits of alternating, -** ones and zeros, checking invariants and result after each read. -*/ -static int -_test_bsr_bit_any_alt(void) -{ - int ret = 1; - uint8_t ones[1] = { 0xaa }; - ur_bsr_t bsr = { .left = sizeof(ones), .bytes = ones }; - uint8_t out; - - ret &= _bsr_bit_any_check("bsr bit-any alt init", &bsr, 0, 0, 0, 0); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt 1", &bsr, 1, 1, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt 2", &bsr, 2, 2, 1, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt 3", &bsr, 3, 3, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt 4", &bsr, 4, 4, 1, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt 5", &bsr, 5, 5, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt 6", &bsr, 6, 6, 1, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt 7", &bsr, 7, 7, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt 8", &bsr, 0, 8, 1, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt off 9", &bsr, 0, 9, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt off 10", &bsr, 0, 10, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt off 11", &bsr, 0, 11, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt off 12", &bsr, 0, 12, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt off 13", &bsr, 0, 13, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt off 14", &bsr, 0, 14, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt off 15", &bsr, 0, 15, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt off 16", &bsr, 0, 16, 0, out); - - out = ur_bsr_bit_any(&bsr); - ret &= _bsr_bit_any_check("bsr bit-any alt off 17", &bsr, 0, 17, 0, out); - - return ret; -} - -static int -_test_bsr_bit_any(void) -{ - return _test_bsr_bit_any_ones() - & _test_bsr_bit_any_zeros() - & _test_bsr_bit_any_alt(); -} - -/* -** subsequents bitstream-reader tests assume the correctnesss of -** ur_bsr_bit_any(), and compare the output of a bit-at-a-time -** "golden master" with that of the relevant, higher-level operation. -** -** XX the "golden" master implementations shouldn't be in bitstream module, -** as we don't intend to run them, but it's kind of weird implement them -** in the test itself. -** -*/ -static int -_bsr_cmp_any_check(const char* cap, uint8_t off, uint8_t len, ur_bsr_t *a, ur_bsr_t *b) -{ - int ret = 1; - - if ( !ur_bsr_sane(a) ) { - fprintf(stderr, "%s: off %u, len %u a insane off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", - cap, off, len, a->off, a->left, a->bits); - ret = 0; - } - - if ( !ur_bsr_sane(b) ) { - fprintf(stderr, "%s: off %u, len %u a insane off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", - cap, off, len, b->off, b->left, b->bits); - ret = 0; - } - - if ( a->off != b->off ) { - fprintf(stderr, "%s: off %u len %u: offset fail (%u, %u)\r\n", - cap, off, len, a->off, b->off); - ret = 0; - } - - if ( a->left != b->left ) { - fprintf(stderr, "%s: off %u len %u: left fail (%" PRIu64 ", %" PRIu64 ")\r\n", - cap, off, len, a->left, b->left); - ret = 0; - } - - if ( a->bits != b->bits ) { - fprintf(stderr, "%s: off %u len %u: bits fail (%" PRIu64 ", %" PRIu64 ")\r\n", - cap, off, len, a->bits, b->bits); - ret = 0; - } - - if ( a->bytes != b->bytes ) { - fprintf(stderr, "%s: off %u len %u: bytes fail (%p, %p)\r\n", - cap, off, len, a->bytes, b->bytes); - ret = 0; - } - - return ret; -} - -/* -** ur_bsr8_any golden master -*/ -static uint8_t -_bsr8_any_slow(ur_bsr_t *bsr, uint8_t len) -{ - uint8_t i, out = 0; - - len = ur_min(8, len); - - for ( i = 0; i < len; i++ ) { - out ^= ur_bsr_bit_any(bsr) << i; - } - - return out; -} - -/* -** from a bitstream-reader initialized with varying values/lengths/offsets, -** read a varying numbers of bits via ur_bsr8_any and master, comparing -** the results and respective states each time. -*/ -static int -_test_bsr8_loop(const char *cap, uint8_t len, uint8_t val) -{ - int ret = 1; - uint8_t *bytes; - ur_bsr_t a, b; - uint8_t c, d, i, j; - - bytes = malloc(len); - memset(bytes, val, len); - - for ( i = 0; i < 8; i++) { - for ( j = 0; j <= 8; j++ ) { - a.left = b.left = len; - a.bytes = b.bytes = bytes; - a.off = a.bits = b.off = b.bits = i; - - c = _bsr8_any_slow(&a, j); - d = ur_bsr8_any(&b, j); - - ret &= _bsr_cmp_any_check(cap, i, j, &a, &b); - - if ( c != d ) { - fprintf(stderr, "%s: off %u, len %u not equal (%02x, %02x) off=%u left=%" PRIu64 " byte=%02x bits=%" PRIu64 "\r\n", - cap, i, j, c, d, b.off, b.left, b.left ? b.bytes[0] : 0, b.bits); - ret = 0; - } - } - } - - free(bytes); - - return ret; -} - -static int -_test_bsr8(void) -{ - return _test_bsr8_loop("bsr8 ones 1", 1, 0xff) - & _test_bsr8_loop("bsr8 ones 2", 2, 0xff) - & _test_bsr8_loop("bsr8 zeros 1", 1, 0x0) - & _test_bsr8_loop("bsr8 zeros 2", 2, 0x0) - & _test_bsr8_loop("bsr8 alt-1 1", 1, 0xaa) - & _test_bsr8_loop("bsr8 alt-1 2", 2, 0xaa) - & _test_bsr8_loop("bsr8 alt-2 1", 1, 0x55) - & _test_bsr8_loop("bsr8 alt-2 2", 2, 0x55); -} - -/* -** ur_bsr32_any golden master -*/ -static uint32_t -_bsr32_any_slow(ur_bsr_t *bsr, uint8_t len) -{ - uint32_t out = 0; - uint8_t i; - - len = ur_min(32, len); - - for ( i = 0; i < len; i++ ) { - out ^= (uint32_t)ur_bsr_bit_any(bsr) << i; - } - - return out; -} - -/* -** from a bitstream-reader initialized with varying values/lengths/offsets, -** read a varying numbers of bits via ur_bsr32_any and master, comparing -** the results and respective states each time. -*/ -static int -_test_bsr32_loop(const char *cap, uint8_t len, uint8_t val) -{ - int ret = 1; - uint8_t *bytes; - ur_bsr_t a, b; - uint32_t c, d; - uint8_t i, j; - - bytes = malloc(len); - memset(bytes, val, len); - - for ( i = 0; i < 8; i++) { - for ( j = 0; j <= 32; j++ ) { - a.left = b.left = len; - a.bytes = b.bytes = bytes; - a.off = a.bits = b.off = b.bits = i; - - c = _bsr32_any_slow(&a, j); - d = ur_bsr32_any(&b, j); - - ret &= _bsr_cmp_any_check(cap, i, j, &a, &b); - - if ( c != d ) { - fprintf(stderr, "%s: off %u, len %u not equal (%08x, %08x) off=%u left=%" PRIu64 " byte=%02x bits=%" PRIu64 "\r\n", - cap, i, j, c, d, b.off, b.left, b.left ? b.bytes[0] : 0, b.bits); - ret = 0; - } - } - } - - free(bytes); - - return ret; -} - -static int -_test_bsr32(void) -{ - return _test_bsr32_loop("bsr32 ones 1", 1, 0xff) - & _test_bsr32_loop("bsr32 ones 2", 2, 0xff) - & _test_bsr32_loop("bsr32 ones 3", 3, 0xff) - & _test_bsr32_loop("bsr32 ones 4", 4, 0xff) - & _test_bsr32_loop("bsr32 zeros 1", 1, 0x0) - & _test_bsr32_loop("bsr32 zeros 2", 2, 0x0) - & _test_bsr32_loop("bsr32 zeros 3", 3, 0x0) - & _test_bsr32_loop("bsr32 zeros 4", 4, 0x0) - & _test_bsr32_loop("bsr32 alt-1 1", 1, 0xaa) - & _test_bsr32_loop("bsr32 alt-1 2", 2, 0xaa) - & _test_bsr32_loop("bsr32 alt-1 3", 3, 0xaa) - & _test_bsr32_loop("bsr32 alt-1 4", 4, 0xaa) - & _test_bsr32_loop("bsr32 alt-2 1", 1, 0x55) - & _test_bsr32_loop("bsr32 alt-2 2", 2, 0x55) - & _test_bsr32_loop("bsr32 alt-2 3", 3, 0x55) - & _test_bsr32_loop("bsr32 alt-2 4", 4, 0x55); -} - -/* -** ur_bsr64_any golden master -*/ -static uint64_t -_bsr64_any_slow(ur_bsr_t *bsr, uint8_t len) -{ - uint64_t out = 0; - uint8_t i; - - len = ur_min(64, len); - - for ( i = 0; i < len; i++ ) { - out ^= (uint64_t)ur_bsr_bit_any(bsr) << i; - } - - return out; -} - -/* -** from a bitstream-reader initialized with varying values/lengths/offsets, -** read a varying numbers of bits via ur_bsr64_any and master, comparing -** the results and respective states each time. -*/ -static int -_test_bsr64_loop(const char *cap, uint8_t len, uint8_t val) -{ - int ret = 1; - uint8_t *bytes; - ur_bsr_t a, b; - uint64_t c, d; - uint8_t i, j; - - bytes = malloc(len); - memset(bytes, val, len); - - for ( i = 0; i < 8; i++) { - for ( j = 0; j <= 64; j++ ) { - a.left = b.left = len; - a.bytes = b.bytes = bytes; - a.off = a.bits = b.off = b.bits = i; - - c = _bsr64_any_slow(&a, j); - d = ur_bsr64_any(&b, j); - - ret &= _bsr_cmp_any_check(cap, i, j, &a, &b); - - if ( c != d ) { - fprintf(stderr, "%s: off %u, len %u not equal (%016" PRIx64", %016" PRIx64") off=%u left=%" PRIu64 " byte=%02x bits=%" PRIu64 "\r\n", - cap, i, j, c, d, b.off, b.left, b.left ? b.bytes[0] : 0, b.bits); - ret = 0; - } - } - } - - free(bytes); - - return ret; -} - -static int -_test_bsr64(void) -{ - return _test_bsr64_loop("bsr64 ones 1", 1, 0xff) - & _test_bsr64_loop("bsr64 ones 2", 2, 0xff) - & _test_bsr64_loop("bsr64 ones 3", 3, 0xff) - & _test_bsr64_loop("bsr64 ones 4", 4, 0xff) - & _test_bsr64_loop("bsr64 ones 5", 5, 0xff) - & _test_bsr64_loop("bsr64 ones 6", 6, 0xff) - & _test_bsr64_loop("bsr64 ones 7", 7, 0xff) - & _test_bsr64_loop("bsr64 ones 8", 8, 0xff) - & _test_bsr64_loop("bsr64 zeros 1", 1, 0x0) - & _test_bsr64_loop("bsr64 zeros 2", 2, 0x0) - & _test_bsr64_loop("bsr64 zeros 3", 3, 0x0) - & _test_bsr64_loop("bsr64 zeros 4", 4, 0x0) - & _test_bsr64_loop("bsr64 zeros 5", 5, 0x0) - & _test_bsr64_loop("bsr64 zeros 6", 6, 0x0) - & _test_bsr64_loop("bsr64 zeros 7", 7, 0x0) - & _test_bsr64_loop("bsr64 zeros 8", 8, 0x0) - & _test_bsr64_loop("bsr64 alt-1 1", 1, 0xaa) - & _test_bsr64_loop("bsr64 alt-1 2", 2, 0xaa) - & _test_bsr64_loop("bsr64 alt-1 3", 3, 0xaa) - & _test_bsr64_loop("bsr64 alt-1 4", 4, 0xaa) - & _test_bsr64_loop("bsr64 alt-1 5", 5, 0xaa) - & _test_bsr64_loop("bsr64 alt-1 6", 6, 0xaa) - & _test_bsr64_loop("bsr64 alt-1 7", 7, 0xaa) - & _test_bsr64_loop("bsr64 alt-1 8", 8, 0xaa) - & _test_bsr64_loop("bsr64 alt-2 1", 1, 0x55) - & _test_bsr64_loop("bsr64 alt-2 2", 2, 0x55) - & _test_bsr64_loop("bsr64 alt-2 3", 3, 0x55) - & _test_bsr64_loop("bsr64 alt-2 4", 4, 0x55) - & _test_bsr64_loop("bsr64 alt-2 5", 5, 0x55) - & _test_bsr64_loop("bsr64 alt-2 6", 6, 0x55) - & _test_bsr64_loop("bsr64 alt-2 7", 7, 0x55) - & _test_bsr64_loop("bsr64 alt-2 8", 8, 0x55); -} - -/* -** ur_bsr_bytes_any golden master -*/ -static void -_bsr_bytes_any_slow(ur_bsr_t *bsr, uint64_t len, uint8_t *out) -{ - uint64_t i, len_byt = len >> 3, len_bit = ur_mask_3(len); - - for ( i = 0; i < len_byt; i++ ) { - out[i] = _bsr8_any_slow(bsr, 8); - } - - if ( len_bit ) { - out[len_byt] = _bsr8_any_slow(bsr, len_bit); - } -} - -/* -** from a bitstream-reader initialized with varying values/lengths/offsets, -** read a varying numbers of bits via ur_bsr_bytes_any and master, comparing -** the results and respective states each time. -*/ -static int -_test_bsr_bytes_any_loop(const char *cap, uint8_t len, uint8_t val) -{ - int ret = 1; - uint64_t max = (len << 3) + 7; - ur_bsr_t a, b; - uint8_t *bytes, *c, *d; - uint8_t i, j, k; - - c = malloc(1 + len); - d = malloc(1 + len); - bytes = malloc(len); - memset(bytes, val, len); - - for ( i = 0; i < 8; i++) { - for ( j = 1; j <= max; j++ ) { - a.left = b.left = len; - a.bytes = b.bytes = len ? bytes : 0; - a.off = b.off = len ? i : 0; - a.bits = b.bits = i; - memset(c, 0x0, len); - memset(d, 0x0, len); - - _bsr_bytes_any_slow(&a, j, c); - ur_bsr_bytes_any(&b, j, d); - - ret &= _bsr_cmp_any_check(cap, i, j, &a, &b); - - if ( memcmp(c, d, len) ) { - fprintf(stderr, "%s: off %u, len %u not equal off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", - cap, i, j, b.off, b.left, b.bits); - fprintf(stderr, " a: { "); - for ( k = 0; k < len; k++ ) { - fprintf(stderr, "%02x, ", c[k]); - } - fprintf(stderr, "}\r\n"); - fprintf(stderr, " b: { "); - for ( k = 0; k < len; k++ ) { - fprintf(stderr, "%02x, ", d[k]); - } - fprintf(stderr, "}\r\n"); - ret = 0; - } - } - } - - free(bytes); - free(d); - free(c); - - return ret; -} - -static int -_test_bsr_bytes_any(void) -{ - return _test_bsr_bytes_any_loop("bsr bytes nought", 0, 0x0) - & _test_bsr_bytes_any_loop("bsr bytes ones odd", 3, 0xff) - & _test_bsr_bytes_any_loop("bsr bytes ones even", 4, 0xff) - & _test_bsr_bytes_any_loop("bsr bytes zeros odd", 5, 0x0) - & _test_bsr_bytes_any_loop("bsr bytes zeros even", 6, 0x0) - & _test_bsr_bytes_any_loop("bsr bytes alt 1 odd", 7, 0xaa) - & _test_bsr_bytes_any_loop("bsr bytes alt 1 even", 8, 0xaa) - & _test_bsr_bytes_any_loop("bsr bytes alt 2 odd", 9, 0x55) - & _test_bsr_bytes_any_loop("bsr bytes alt 2 even", 10, 0x55); -} - -/* -** from a bitstream-reader initialized with varying values/lengths/offsets, -** skip a varying numbers of bits via ur_bsr_skip_any and read the same via -** ur_bsr_bytes_any master, comparing the respective states each time. -*/ -static int -_test_bsr_skip_any_loop(const char *cap, uint8_t len, uint8_t val) -{ - int ret = 1; - uint64_t max = (len << 3) + 7; - ur_bsr_t a, b; - uint8_t *bytes, *c; - uint8_t i, j; - - c = malloc(1 + len); - bytes = malloc(len); - memset(bytes, val, len); - - for ( i = 0; i < 8; i++) { - for ( j = 1; j <= max; j++ ) { - a.left = b.left = len; - a.bytes = b.bytes = len ? bytes : 0; - a.off = b.off = len ? i : 0; - a.bits = b.bits = i; - memset(c, 0x0, len); - - _bsr_bytes_any_slow(&a, j, c); - ur_bsr_skip_any(&b, j); - - ret &= _bsr_cmp_any_check(cap, i, j, &a, &b); - } - } - - free(bytes); - free(c); - - return ret; -} - -static int -_test_bsr_skip_any(void) -{ - return _test_bsr_skip_any_loop("bsr skip nought", 0, 0x0) - & _test_bsr_skip_any_loop("bsr skip ones odd", 3, 0xff) - & _test_bsr_skip_any_loop("bsr skip ones even", 4, 0xff) - & _test_bsr_skip_any_loop("bsr skip zeros odd", 5, 0x0) - & _test_bsr_skip_any_loop("bsr skip zeros even", 6, 0x0) - & _test_bsr_skip_any_loop("bsr skip alt 1 odd", 7, 0xaa) - & _test_bsr_skip_any_loop("bsr skip alt 1 even", 8, 0xaa) - & _test_bsr_skip_any_loop("bsr skip alt 2 odd", 9, 0x55) - & _test_bsr_skip_any_loop("bsr skip alt 2 even", 10, 0x55); -} - -/* -** compare the result and state of two reads (that were not permitted -** to read past the end of the stream). -*/ -static int -_bsr_cmp_check(const char* cap, - uint8_t off, - uint8_t len, - ur_bsr_t *a, - ur_bsr_t *b, - uint8_t c, - uint8_t d, - ur_cue_res_e e, - ur_cue_res_e f) -{ - int ret = 1; - - if ( !ur_bsr_sane(a) ) { - fprintf(stderr, "%s: off %u, len %u a insane off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", - cap, off, len, a->off, a->left, a->bits); - ret = 0; - } - - if ( !ur_bsr_sane(b) ) { - fprintf(stderr, "%s: off %u, len %u a insane off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", - cap, off, len, b->off, b->left, b->bits); - ret = 0; - } - - if ( e != f ) { - fprintf(stderr, "%s: off %u, len %u ret not equal (%s, %s) off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", - cap, off, len, - (ur_cue_good == e) ? "good" : "gone", - (ur_cue_good == f) ? "good" : "gone", - b->off, b->left, b->bits); - ret = 0; - } - - if ( (ur_cue_good == e) && (c != d) ) { - fprintf(stderr, "%s: off %u, len %u val not equal (%02x, %02x) off=%u left=%" PRIu64 " bits=%" PRIu64 "\r\n", - cap, off, len, c, d, b->off, b->left, b->bits); - ret = 0; - } - - if ( a->off != b->off ) { - fprintf(stderr, "%s: off %u len %u: offset fail (%u, %u)\r\n", - cap, off, len, a->off, b->off); - ret = 0; - } - - if ( a->left != b->left ) { - fprintf(stderr, "%s: off %u len %u: left fail (%" PRIu64 ", %" PRIu64 ")\r\n", - cap, off, len, a->left, b->left); - ret = 0; - } - - if ( a->bits != b->bits ) { - fprintf(stderr, "%s: off %u len %u: bits fail (%" PRIu64 ", %" PRIu64 ")\r\n", - cap, off, len, a->bits, b->bits); - ret = 0; - } - - if ( a->bytes != b->bytes ) { - fprintf(stderr, "%s: off %u len %u: bytes fail (%p, %p)\r\n", - cap, off, len, a->bytes, b->bytes); - ret = 0; - } - - - return ret; -} - -/* -** ur_bsr_log golden master -*/ -static ur_cue_res_e -_bsr_log_slow(ur_bsr_t *bsr, uint8_t *out) -{ - ur_cue_res_e res; - uint8_t bit, i = 0; - - do { - if ( ur_cue_good != (res = ur_bsr_bit(bsr, &bit)) ) { - return res; - } - else if ( bit ) { - *out = i; - return ur_cue_good; - } - } - while ( ++i ); - - return ur_cue_meme; -} - -/* -** from a bitstream-reader initialized with varying values/lengths/offsets, -** read a varying numbers of bits via ur_bsr_log and master, comparing -** the results and respective states each time. -*/ -static int -_test_bsr_log_loop(const char *cap, uint8_t len, uint8_t val) -{ - int ret = 1; - ur_bsr_t a, b; - uint8_t *bytes, c, d; - uint8_t i, j; - ur_cue_res_e e, f; - - bytes = malloc(len); - - for ( i = 0; i < 8; i++) { - for ( j = 0; j < len; j++ ) { - a.left = b.left = len; - a.bytes = b.bytes = bytes; - a.off = a.bits = b.off = b.bits = i; - - memset(bytes, 0x0, j); - memset(bytes + j, val, len - j); - - e = _bsr_log_slow(&a, &c); - f = ur_bsr_log(&b, &d); - - ret &= _bsr_cmp_check(cap, i, j, &a, &b, c, d, e, f); - } - } - - free(bytes); - - return ret; -} - -static int -_test_bsr_log(void) -{ - int ret = _test_bsr_log_loop("bsr log nought", 0, 0x0) - & _test_bsr_log_loop("bsr log ones odd", 3, 0xff) - & _test_bsr_log_loop("bsr log ones even", 4, 0xff) - & _test_bsr_log_loop("bsr log ones big", 50, 0xff) - & _test_bsr_log_loop("bsr log zeros odd", 5, 0x0) - & _test_bsr_log_loop("bsr log zeros even", 6, 0x0) - & _test_bsr_log_loop("bsr log zeros big", 50, 0x0); - - { - uint8_t i, j = 5; - char cap[1024]; - - for ( i = 0; i < 8; i++ ) { - snprintf(cap, 1000, "bsr log 1<<%u odd", i); - ret &= _test_bsr_log_loop((const char*)cap, j++, 0x1 << i); - - snprintf(cap, 1000, "bsr log 1<<%u even", i); - ret &= _test_bsr_log_loop((const char*)cap, j++, 0x1 << i); - - snprintf(cap, 1000, "bsr log 1<<%u big", i); - ret &= _test_bsr_log_loop((const char*)cap, 50, 0x1 << i); - } - } - - return ret; -} - -/* -** ur_bsr_tag golden master -*/ -static ur_cue_res_e -_bsr_tag_slow(ur_bsr_t *bsr, ur_cue_tag_e *out) -{ - ur_cue_res_e res; - uint8_t bit; - - if ( ur_cue_good != (res = ur_bsr_bit(bsr, &bit)) ) { - return res; - } - else if ( 0 == bit ) { - *out = ur_jam_atom; - return ur_cue_good; - } - else if ( ur_cue_good != (res = ur_bsr_bit(bsr, &bit)) ) { - return res; - } - - *out = ( 0 == bit ) ? ur_jam_cell : ur_jam_back; - return ur_cue_good; -} - -/* -** from a bitstream-reader initialized with varying values/lengths/offsets, -** read a jam type tag via ur_bsr_tag and master, comparing the results and -** respective states each time. -*/ -static int -_test_bsr_tag_loop(const char *cap, uint8_t len, uint8_t val) -{ - int ret = 1; - ur_bsr_t a, b; - uint8_t *bytes; - ur_cue_tag_e c, d; - uint8_t i, j; - ur_cue_res_e e, f; - - bytes = malloc(len); - - for ( i = 0; i < 8; i++) { - for ( j = 0; j < len; j++ ) { - a.left = b.left = len; - a.bytes = b.bytes = bytes; - a.off = a.bits = b.off = b.bits = i; - - memset(bytes, 0x0, j); - memset(bytes + j, val, len - j); - - e = _bsr_tag_slow(&a, &c); - f = ur_bsr_tag(&b, &d); - - ret &= _bsr_cmp_check(cap, i, j, &a, &b, c, d, e, f); - } - } - - free(bytes); - - return ret; -} - -static int -_test_bsr_tag(void) -{ - return _test_bsr_tag_loop("bsr tag nought", 0, 0x0) - & _test_bsr_tag_loop("bsr tag ones 1", 1, 0xff) - & _test_bsr_tag_loop("bsr tag ones 2", 2, 0xff) - & _test_bsr_tag_loop("bsr tag zeros 1", 1, 0x0) - & _test_bsr_tag_loop("bsr tag zeros 2", 2, 0x0) - & _test_bsr_tag_loop("bsr tag alt-1 1", 1, 0xaa) - & _test_bsr_tag_loop("bsr tag alt-1 2", 2, 0xaa) - & _test_bsr_tag_loop("bsr tag alt-2 1", 1, 0x55) - & _test_bsr_tag_loop("bsr tag alt-2 2", 2, 0x55); -} - -static int -_test_bsr(void) -{ - return _test_bsr_bit() - & _test_bsr_bit_any() - & _test_bsr_bytes_any() - & _test_bsr_skip_any() - & _test_bsr8() - & _test_bsr32() - & _test_bsr64() - & _test_bsr_log() - & _test_bsr_tag(); -} - -static int -_test_jam_spec(const char *cap, - ur_root_t *r, - ur_nref ref, - size_t len, - const uint8_t *res) -{ - uint64_t i, out_len; - uint8_t *out; - int ret; - - ur_jam(r, ref, &out_len, &out); - - if ( 0 != memcmp(out, res, len) ) { - fprintf(stderr, "\033[31mjam %s fail\033[0m\r\n", cap); - - fprintf(stderr, " actual: { "); - for ( i = 0; i < out_len; i++ ) { - fprintf(stderr, "0x%x, ", out[i]); - } - fprintf(stderr, "}\r\n"); - fprintf(stderr, " expect: { "); - for ( i = 0; i < len; i++ ) { - fprintf(stderr, "0x%x, ", res[i]); - } - fprintf(stderr, "}\r\n"); - - ret = 0; - } - else { - ret = 1; - } - - free(out); - - return ret; -} - -static int -_test_cue_spec(const char *cap, - ur_root_t* r, - ur_nref ref, - size_t len, - const uint8_t *res) -{ - int ret = 1; - ur_nref out; - - if ( !ur_cue_test(len, res) ) { - fprintf(stderr, "\033[31mcue %s fail 1\033[0m\r\n", cap); - ret = 0; - } - - if ( ur_cue_good != ur_cue(r, len, res, &out) ) { - fprintf(stderr, "\033[31mcue %s fail 2\033[0m\r\n", cap); - ret = 0; - } - else if ( ref != out ) { - fprintf(stderr, "\033[31mcue %s fail 3 ref=%" PRIu64 " out=%" PRIu64 " \033[0m\r\n", cap, ref, out); - ret = 0; - } - - return ret; -} - -/* -** test jam/cue correctness and roundtrips across a variety of inputs -*/ -static int -_test_jam_cue(void) -{ - ur_root_t *r = ur_root_init(); - int ret = 1; - -# define NC(a, b) ur_cons(r, a, b) -# define NT(a, b, c) NC(a, NC(b, c)) - -# define FAST 0x74736166 -# define FULL 0x6c6c7566 - -# define TEST_CASE(a, b) \ - const char* cap = a; \ - ur_nref ref = b; \ - ret &= _test_jam_spec(cap, r, ref, sizeof(res), res); \ - ret &= _test_cue_spec(cap, r, ref, sizeof(res), res); \ - - { - uint8_t res[1] = { 0x2 }; - TEST_CASE("0", 0); - } - - { - uint8_t res[1] = { 0xc }; - TEST_CASE("1", 1); - } - - { - uint8_t res[1] = { 0x48 }; - TEST_CASE("2", 2); - } - - { - uint8_t res[6] = { 0xc0, 0x37, 0xb, 0x9b, 0xa3, 0x3 }; - TEST_CASE("%fast", FAST); - } - - { - uint8_t res[6] = { 0xc0, 0x37, 0xab, 0x63, 0x63, 0x3 }; - TEST_CASE("%full", FULL); - } - - { - uint8_t res[1] = { 0x29 }; - TEST_CASE("[0 0]", NC(0, 0)); - } - - { - uint8_t res[2] = { 0x31, 0x3 }; - TEST_CASE("[1 1]", NC(1, 1)); - } - - { - uint8_t res[2] = { 0x21, 0xd1 }; - TEST_CASE("[2 3]", NC(2, 3)); - } - - { - uint8_t res[11] = { 0x1, 0xdf, 0x2c, 0x6c, 0x8e, 0xe, 0x7c, 0xb3, 0x3a, 0x36, 0x36 }; - TEST_CASE("[%fast %full]", NC(FAST, FULL)); - } - - { - uint8_t res[2] = { 0x71, 0xcc }; - TEST_CASE("[1 1 1]", NC(1, NC(1, 1))); - } - - { - uint8_t res[12] = { 0x1, 0xdf, 0x2c, 0x6c, 0x8e, 0x1e, 0xf0, 0xcd, 0xea, 0xd8, 0xd8, 0x93 }; - TEST_CASE("[%fast %full %fast]", NC(FAST, NC(FULL, FAST))); - } - - { - uint8_t res[6] = { 0xa5, 0x35, 0x19, 0xf3, 0x18, 0x5 }; - TEST_CASE("[[0 0] [[0 0] 1 1] 1 1]", NC(NC(0, 0), NC(NC(NC(0, 0), NC(1, 1)), NC(1, 1)))); - } - - { - uint8_t res[14] = { 0x15, 0x17, 0xb2, 0xd0, 0x85, 0x59, 0xb8, 0x61, 0x87, 0x5f, 0x10, 0x54, 0x55, 0x5 }; - TEST_CASE("deep", NC(NC(NC(1, NC(NC(2, NC(NC(3, NC(NC(4, NC(NT(5, 6, NC(7, NC(NC(8, 0), 0))), 0)), 0)), 0)), 0)), 0), 0)); - } - - { - uint8_t inp[33] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; - uint8_t res[35] = { 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8 }; - TEST_CASE("wide", ur_coin_bytes(r, sizeof(inp), inp)); - } - - { - uint8_t inp[16] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xa8, 0xab, 0x60, 0xef, 0x2d, 0xd, 0x0, 0x0, 0x80 }; - uint8_t res[19] = { 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x50, 0x57, 0xc1, 0xde, 0x5b, 0x1a, 0x0, 0x0, 0x0, 0x1 }; - TEST_CASE("date", ur_coin_bytes(r, sizeof(inp), inp)); - } - - ur_root_free(r); - - return ret; -} - -static int -_test_ur(void) -{ - int ret = 1; - - if ( !_test_bsw() ) { - fprintf(stderr, "ur test bsw failed\r\n"); - ret = 0; - } - - if ( !_test_bsr() ) { - fprintf(stderr, "ur test bsr failed\r\n"); - ret = 0; - } - - if ( !_test_jam_cue() ) { - fprintf(stderr, "ur test jam/cue failed\r\n"); - ret = 0; - } - - return ret; -} - -int -main(int argc, char* argv[]) -{ - if ( !_test_ur() ) { - fprintf(stderr, "ur test failed\r\n"); - return 1; - } - - fprintf(stderr, "ur ok\n"); - return 0; -} diff --git a/pkg/urbit/ur/bitstream.c b/pkg/urbit/ur/bitstream.c deleted file mode 100644 index 5d69e3f9e..000000000 --- a/pkg/urbit/ur/bitstream.c +++ /dev/null @@ -1,1280 +0,0 @@ -#include -#include -#include -#include - -#include "ur/defs.h" -#include "ur/bitstream.h" - -ur_cue_res_e -ur_bsr_init(ur_bsr_t *bsr, uint64_t len, const uint8_t *bytes) -{ - // check for overflow - // - if ( (len << 3) < len ) { - return ur_cue_meme; - } - - bsr->left = len; - bsr->bytes = bytes; - - return ur_cue_good; -} - -ur_bool_t -ur_bsr_sane(ur_bsr_t *bsr) -{ - ur_bool_t ret = 8 > bsr->off; - - if ( !bsr->left ) { - ret = ret && (!bsr->off && !bsr->bytes); - } - - return ret; -} - -ur_cue_res_e -ur_bsr_bit(ur_bsr_t *bsr, uint8_t *out) -{ - uint64_t left = bsr->left; - - if ( !left ) { - return ur_cue_gone; - } - else { - const uint8_t *b = bsr->bytes; - uint8_t off = bsr->off; - uint8_t bit = (b[0] >> off) & 1; - - if ( 7 == off ) { - bsr->bytes = ( --left ) ? (b + 1) : 0; - bsr->left = left; - bsr->off = 0; - } - else { - bsr->off = 1 + off; - } - - bsr->bits++; - - *out = bit; - return ur_cue_good; - } -} - -uint8_t -ur_bsr_bit_any(ur_bsr_t *bsr) -{ - uint64_t left = bsr->left; - - bsr->bits++; - - if ( !left ) { - return 0; - } - else { - const uint8_t *b = bsr->bytes; - uint8_t off = bsr->off; - uint8_t bit = (b[0] >> off) & 1; - - if ( 7 == off ) { - bsr->bytes = ( --left ) ? (b + 1) : 0; - bsr->left = left; - bsr->off = 0; - } - else { - bsr->off = 1 + off; - } - - return bit; - } -} - -uint8_t -ur_bsr8_any(ur_bsr_t *bsr, uint8_t len) -{ - uint64_t left = bsr->left; - - len = ur_min(8, len); - - bsr->bits += len; - - if ( !left ) { - return 0; - } - else { - uint8_t off = bsr->off; - uint8_t rest = 8 - off; - const uint8_t *b = bsr->bytes; - uint8_t m = b[0] >> off; - - if ( len < rest ) { - bsr->off = off + len; - return m & ((1 << len) - 1); - } - else if ( 1 == left ) { - bsr->off = 0; - bsr->left = 0; - bsr->bytes = 0; - return m; - } - else { - off = len - rest; - - bsr->off = off; - bsr->left--; - bsr->bytes++; - - { - uint8_t l = b[1] & ((1 << off) - 1); - return m ^ (l << rest); - } - } - } -} - -uint32_t -ur_bsr32_any(ur_bsr_t *bsr, uint8_t len) -{ - uint64_t left = bsr->left; - - len = ur_min(32, len); - - bsr->bits += len; - - if ( !left ) { - return 0; - } - else { - uint8_t off = bsr->off; - uint8_t rest = 8 - off; - uint32_t m = bsr->bytes[0] >> off; - - if ( len < rest ) { - bsr->off = off + len; - return m & ((1 << len) - 1); - } - else { - const uint8_t *b; - uint8_t mask, len_byt; - uint32_t l; - - len -= rest; - left--; - b = ++bsr->bytes; - - len_byt = len >> 3; - - if ( len_byt >= left ) { - len_byt = left; - bsr->off = off = 0; - bsr->left = 0; - bsr->bytes = 0; - } - else { - bsr->off = off = ur_mask_3(len); - bsr->left = left - len_byt; - bsr->bytes += len_byt; - } - - mask = (1 << off) - 1; - - switch ( len_byt ) { - default: assert(0); - - case 4: { - l = (uint32_t)b[0] - ^ (uint32_t)b[1] << 8 - ^ (uint32_t)b[2] << 16 - ^ (uint32_t)b[3] << 24; - } break; - - case 3: { - l = (uint32_t)b[0] - ^ (uint32_t)b[1] << 8 - ^ (uint32_t)b[2] << 16; - - if ( mask ) { - l ^= (uint32_t)(b[3] & mask) << 24; - } - } break; - - case 2: { - l = (uint32_t)b[0] - ^ (uint32_t)b[1] << 8; - - if ( mask ) { - l ^= (uint32_t)(b[2] & mask) << 16; - } - } break; - - case 1: { - l = (uint32_t)b[0]; - - if ( mask ) { - l ^= (uint32_t)(b[1] & mask) << 8; - } - } break; - - case 0: { - l = ( mask ) ? (uint32_t)(b[0] & mask) : 0; - } break; - } - - return m ^ (l << rest); - } - } -} - -uint64_t -ur_bsr64_any(ur_bsr_t *bsr, uint8_t len) -{ - uint64_t left = bsr->left; - - len = ur_min(64, len); - - bsr->bits += len; - - if ( !left ) { - return 0; - } - else { - uint8_t off = bsr->off; - uint8_t rest = 8 - off; - uint64_t m = bsr->bytes[0] >> off; - - if ( len < rest ) { - bsr->off = off + len; - return m & ((1 << len) - 1); - } - else { - const uint8_t *b; - uint8_t mask, len_byt; - uint64_t l; - - len -= rest; - left--; - b = ++bsr->bytes; - - len_byt = len >> 3; - - if ( len_byt >= left ) { - len_byt = left; - bsr->off = off = 0; - bsr->left = 0; - bsr->bytes = 0; - } - else { - bsr->off = off = ur_mask_3(len); - bsr->left = left - len_byt; - bsr->bytes += len_byt; - } - - mask = (1 << off) - 1; - - switch ( len_byt ) { - case 8: { - l = (uint64_t)b[0] - ^ (uint64_t)b[1] << 8 - ^ (uint64_t)b[2] << 16 - ^ (uint64_t)b[3] << 24 - ^ (uint64_t)b[4] << 32 - ^ (uint64_t)b[5] << 40 - ^ (uint64_t)b[6] << 48 - ^ (uint64_t)b[7] << 56; - } break; - - case 7: { - l = (uint64_t)b[0] - ^ (uint64_t)b[1] << 8 - ^ (uint64_t)b[2] << 16 - ^ (uint64_t)b[3] << 24 - ^ (uint64_t)b[4] << 32 - ^ (uint64_t)b[5] << 40 - ^ (uint64_t)b[6] << 48; - - if ( mask ) { - l ^= (uint64_t)(b[7] & mask) << 56; - } - } break; - - case 6: { - l = (uint64_t)b[0] - ^ (uint64_t)b[1] << 8 - ^ (uint64_t)b[2] << 16 - ^ (uint64_t)b[3] << 24 - ^ (uint64_t)b[4] << 32 - ^ (uint64_t)b[5] << 40; - - if ( mask ) { - l ^= (uint64_t)(b[6] & mask) << 48; - } - } break; - - case 5: { - l = (uint64_t)b[0] - ^ (uint64_t)b[1] << 8 - ^ (uint64_t)b[2] << 16 - ^ (uint64_t)b[3] << 24 - ^ (uint64_t)b[4] << 32; - - if ( mask ) { - l ^= (uint64_t)(b[5] & mask) << 40; - } - } break; - - case 4: { - l = (uint64_t)b[0] - ^ (uint64_t)b[1] << 8 - ^ (uint64_t)b[2] << 16 - ^ (uint64_t)b[3] << 24; - - if ( mask ) { - l ^= (uint64_t)(b[4] & mask) << 32; - } - } break; - - case 3: { - l = (uint64_t)b[0] - ^ (uint64_t)b[1] << 8 - ^ (uint64_t)b[2] << 16; - - if ( mask ) { - l ^= (uint64_t)(b[3] & mask) << 24; - } - } break; - - case 2: { - l = (uint64_t)b[0] - ^ (uint64_t)b[1] << 8; - - if ( mask ) { - l ^= (uint64_t)(b[2] & mask) << 16; - } - } break; - - case 1: { - l = (uint64_t)b[0]; - - if ( mask ) { - l ^= (uint64_t)(b[1] & mask) << 8; - } - } break; - - case 0: { - l = ( mask ) ? (uint64_t)(b[0] & mask) : 0; - } break; - } - - return m ^ (l << rest); - } - } -} - -void -ur_bsr_bytes_any(ur_bsr_t *bsr, uint64_t len, uint8_t *out) -{ - uint64_t left = bsr->left; - - bsr->bits += len; - - if ( !left ) { - return; - } - else { - const uint8_t *b = bsr->bytes; - uint8_t off = bsr->off; - uint64_t len_byt = len >> 3; - uint8_t len_bit = ur_mask_3(len); - uint64_t need = len_byt + !!len_bit; - - if ( !off ) { - if ( need > left ) { - memcpy(out, b, left); - left = 0; - bsr->bytes = 0; - } - else { - memcpy(out, b, len_byt); - off = len_bit; - - if ( off ) { - out[len_byt] = b[len_byt] & ((1 << off) - 1); - } - - left -= len_byt; - bsr->bytes = ( left ) ? b + len_byt : 0; - } - } - // the most-significant bits from a byte in the stream - // become the least-significant bits of an output byte, and vice-versa - // - else { - uint8_t rest = 8 - off; - uint64_t last = left - 1; - uint64_t max = ur_min(last, len_byt); - uint8_t m, l; - - // loop over all the bytes we need (or all that remain) - // - { - uint64_t i; - - for ( i = 0; i < max; i++ ) { - out[i] = (b[i] >> off) ^ (b[i + 1] << rest); - } - - b += max; - m = *b >> off; - } - - // we're reading into or beyond the last byte [bsr] - // - // [m] holds all the remaining bits in [bsr], - // but we might not need all of it - // - if ( need >= left ) { - uint8_t bits = len - (last << 3); - - if ( bits < rest ) { - out[max] = m & ((1 << len_bit) - 1); - bsr->bytes = b; - left = 1; - off += len_bit; - } - else { - out[max] = m; - bsr->bytes = 0; - left = 0; - off = 0; - } - } - // we need less than a byte, but it might span multiple bytes - // - else { - uint8_t bits = off + len_bit; - uint8_t step = !!(bits >> 3); - - bsr->bytes = b + step; - left -= len_byt + step; - off = ur_mask_3(bits); - - if ( len_bit ) { - if ( len_bit <= rest ) { - out[max] = m & ((1 << len_bit) - 1); - } - else { - l = *++b & ((1 << off) - 1); - out[max] = (m ^ (l << rest)) & ((1 << len_bit) - 1); - } - } - } - } - - bsr->off = off; - bsr->left = left; - } -} - -void -ur_bsr_skip_any(ur_bsr_t *bsr, uint64_t len) -{ - uint64_t left = bsr->left; - - bsr->bits += len; - - if ( !left ) { - return; - } - else { - const uint8_t *b = bsr->bytes; - uint8_t off = bsr->off; - uint64_t len_byt = len >> 3; - uint8_t len_bit = ur_mask_3(len); - uint64_t need = len_byt + !!len_bit; - uint8_t rest = 8 - off; - uint64_t last = left - 1; - - b += ur_min(last, len_byt) + 1; - - if ( need >= left ) { - uint8_t bits = len - (last << 3); - - if ( bits < rest ) { - bsr->bytes = b - 1; - left = 1; - off += len_bit; - } - else { - bsr->bytes = 0; - left = 0; - off = 0; - } - } - else { - uint8_t bits = off + len_bit; - uint8_t step = !!(bits >> 3); - - bsr->bytes = b - (1 - step); - left -= len_byt + step; - off = ur_mask_3(bits); - } - - bsr->off = off; - bsr->left = left; - } -} - -static inline ur_cue_res_e -_bsr_set_gone(ur_bsr_t *bsr, uint8_t bits) -{ - bsr->bits += bits; - bsr->bytes = 0; - bsr->left = 0; - bsr->off = 0; - return ur_cue_gone; -} - -ur_cue_res_e -ur_bsr_tag(ur_bsr_t *bsr, ur_cue_tag_e *out) -{ - uint64_t left = bsr->left; - - if ( !left ) { - return ur_cue_gone; - } - else { - const uint8_t *b = bsr->bytes; - uint8_t off = bsr->off; - uint8_t bit = (b[0] >> off) & 1; - uint8_t len = 1; - - if ( 0 == bit ) { - *out = ur_jam_atom; - } - else { - if ( 7 == off ) { - if ( 1 == left ) { - return _bsr_set_gone(bsr, 1); - } - - bit = b[1] & 1; - } - else { - bit = (b[0] >> (off + 1)) & 1; - } - - len++; - *out = ( 0 == bit ) ? ur_jam_cell : ur_jam_back; - } - - { - uint8_t bits = off + len; - uint8_t bytes = bits >> 3; - - left -= bytes; - - if ( !left ) { - bsr->bytes = 0; - bsr->left = 0; - bsr->off = 0; - } - else { - bsr->bytes += bytes; - bsr->left = left; - bsr->off = ur_mask_3(bits); - } - - bsr->bits += len; - - return ur_cue_good; - } - } -} - -static inline ur_cue_res_e -_bsr_log_meme(ur_bsr_t *bsr) -{ - bsr->bits += 256; - bsr->bytes += 32; - bsr->left -= 32; - return ur_cue_meme; -} - -ur_cue_res_e -ur_bsr_log(ur_bsr_t *bsr, uint8_t *out) -{ - uint64_t left = bsr->left; - - if ( !left ) { - return ur_cue_gone; - } - else { - uint8_t off = bsr->off; - const uint8_t *b = bsr->bytes; - uint8_t byt = b[0] >> off; - uint8_t skip = 0; - - while ( !byt ) { - if ( 32 == skip ) { - return _bsr_log_meme(bsr); - } - - byt = b[++skip]; - - if ( skip == left ) { - return _bsr_set_gone(bsr, (skip << 3) - off); - } - } - - { - uint32_t zeros = ur_tz8(byt) + (skip ? ((skip << 3) - off) : 0); - - if ( 255 < zeros ) { - return _bsr_log_meme(bsr); - } - else { - uint32_t bits = off + 1 + zeros; - uint8_t bytes = bits >> 3; - - left -= bytes; - - bsr->bytes = left ? (b + bytes) : 0; - bsr->bits += 1 + zeros; - bsr->left = left; - bsr->off = ur_mask_3(bits); - - *out = zeros; - return ur_cue_good; - } - } - } -} - -ur_cue_res_e -ur_bsr_rub_len(ur_bsr_t *bsr, uint64_t *out) -{ - ur_cue_res_e res; - uint8_t len; - - if ( ur_cue_good != (res = ur_bsr_log(bsr, &len)) ) { - return res; - } - else if ( 64 <= len ) { - return ur_cue_meme; - } - - switch ( len ) { - case 0: { - *out = 0; - } break; - - case 1: { - *out = 1; - } break; - - default: { - len--; - *out = ur_bsr64_any(bsr, len) ^ (1ULL << len); - } break; - } - - return ur_cue_good; -} - -/* -** bitstream-writer operations follow a pattern of an unsafe (inline) -** implementation, unsafe wrt to buffer size and reallocation, -** wrapped in a public function with buffer size checks. -** -** higher-level operations made up of multiple discrete writes check -** the buffer size once for all involved writes. -** -** this pattern should be easily adaptable to an alternate bitstream-writer -** implementation that flushes accumulated output periodically instead -** of reallocating the output buffer. -*/ - -void -ur_bsw_init(ur_bsw_t *bsw, uint64_t prev, uint64_t size) -{ - bsw->prev = prev; - bsw->size = size; - bsw->bytes = calloc(size, 1); - - if ( !bsw->bytes ) { - fprintf(stderr, - "ur: bitstream-init allocation failed, out of memory\r\n"); - abort(); - } -} - -void -ur_bsw_grow(ur_bsw_t *bsw, uint64_t step) -{ - uint64_t size = bsw->size; - uint64_t next = size + step; - - bsw->bytes = realloc(bsw->bytes, next); - - if ( !bsw->bytes ) { - fprintf(stderr, - "ur: bitstream-write allocation failed, out of memory\r\n"); - abort(); - } - - memset(bsw->bytes + size, 0, step); - - bsw->prev = size; - bsw->size = next; -} - -ur_bool_t -ur_bsw_sane(ur_bsw_t *bsw) -{ - return ( (8 > bsw->off) - && ((bsw->fill << 3) + bsw->off == bsw->bits) ); -} - -uint64_t -ur_bsw_done(ur_bsw_t *bsw, uint64_t *len, uint8_t **byt) -{ - uint64_t bits = bsw->bits; - - *len = bsw->fill + !!bsw->off; - *byt = bsw->bytes; - - memset(bsw, 0, sizeof(*bsw)); - - return bits; -} - -static inline void -_bsw_bit_unsafe(ur_bsw_t *bsw, uint8_t bit) -{ - uint64_t fill = bsw->fill; - uint8_t off = bsw->off; - - bsw->bytes[fill] ^= (bit & 1) << off; - - if ( 7 == off ) { - bsw->fill = 1 + fill; - bsw->off = 0; - } - else { - bsw->off = 1 + off; - } - - bsw->bits++; -} - -void -ur_bsw_bit(ur_bsw_t *bsw, uint8_t bit) -{ - if ( (7 == bsw->off) - && ((1 + bsw->fill) == bsw->size) ) - { - ur_bsw_grow(bsw, bsw->prev); - } - - _bsw_bit_unsafe(bsw, bit); -} - -static inline void -_bsw8_unsafe(ur_bsw_t *bsw, uint8_t len, uint8_t byt) -{ - uint64_t fill = bsw->fill; - uint8_t off = bsw->off; - uint8_t rest = 8 - off; - uint8_t l, m; - - // the least-significant bits of the input become the - // most-significant bits of a byte in the output stream - // - if ( len < rest ) { - l = byt & ((1 << len) - 1); - - bsw->bytes[fill] ^= l << off; - bsw->off = off + len; - } - // and vice-versa - // - else { - l = byt & ((1 << rest) - 1); - m = byt >> rest; - - bsw->bytes[fill++] ^= l << off; - off = len - rest; - bsw->bytes[fill] = m & ((1 << off) - 1); - - bsw->fill = fill; - bsw->off = off; - } - - bsw->bits += len; -} - -void -ur_bsw8(ur_bsw_t *bsw, uint8_t len, uint8_t byt) -{ - len = ur_min(8, len); - - if ( bsw->fill + !!((bsw->off + len) >> 3) >= bsw->size ) { - ur_bsw_grow(bsw, bsw->prev); - } - - _bsw8_unsafe(bsw, len, byt); -} - -static inline void -_bsw32_unsafe(ur_bsw_t *bsw, uint8_t len, uint32_t val) -{ - uint64_t fill = bsw->fill; - uint8_t off = bsw->off; - uint8_t *bytes = bsw->bytes; - - bsw->bits += len; - - if ( off ) { - uint8_t rest = 8 - off; - - if ( len < rest ) { - bytes[fill] ^= (val & ((1 << len) - 1)) << off; - bsw->off = off + len; - return; - } - - bytes[fill++] ^= (val & ((1 << rest) - 1)) << off; - val >>= rest; - len -= rest; - } - - switch ( len >> 3 ) { - case 4: { - bytes[fill++] = ur_mask_8(val); - bytes[fill++] = ur_mask_8(val >> 8); - bytes[fill++] = ur_mask_8(val >> 16); - bytes[fill++] = ur_mask_8(val >> 24); - - // no offset is possible here - // - bsw->fill = fill; - bsw->off = 0; - return; - } - - case 3: { - bytes[fill++] = ur_mask_8(val); - bytes[fill++] = ur_mask_8(val >> 8); - bytes[fill++] = ur_mask_8(val >> 16); - val >>= 24; - } break; - - case 2: { - bytes[fill++] = ur_mask_8(val); - bytes[fill++] = ur_mask_8(val >> 8); - val >>= 16; - } break; - - case 1: { - bytes[fill++] = ur_mask_8(val); - val >>= 8; - } break; - } - - off = ur_mask_3(len); - - if ( off ) { - bytes[fill] = (uint8_t)(val & ((1 << off) - 1)); - } - - bsw->fill = fill; - bsw->off = off; -} - -void -ur_bsw32(ur_bsw_t *bsw, uint8_t len, uint32_t val) -{ - uint8_t need; - - len = ur_min(32, len); - need = ur_bloq_up3( bsw->off + len ); - - if ( bsw->fill + need >= bsw->size ) { - ur_bsw_grow(bsw, ur_max(need, bsw->prev)); - } - - _bsw32_unsafe(bsw, len, val); -} - -static inline void -_bsw64_unsafe(ur_bsw_t *bsw, uint8_t len, uint64_t val) -{ - uint64_t fill = bsw->fill; - uint8_t off = bsw->off; - uint8_t *bytes = bsw->bytes; - - bsw->bits += len; - - if ( off ) { - uint8_t rest = 8 - off; - - if ( len < rest ) { - bytes[fill] ^= (val & ((1 << len) - 1)) << off; - bsw->off = off + len; - return; - } - - bytes[fill++] ^= (val & ((1 << rest) - 1)) << off; - val >>= rest; - len -= rest; - } - - switch ( len >> 3 ) { - case 8: { - bytes[fill++] = ur_mask_8(val); - bytes[fill++] = ur_mask_8(val >> 8); - bytes[fill++] = ur_mask_8(val >> 16); - bytes[fill++] = ur_mask_8(val >> 24); - bytes[fill++] = ur_mask_8(val >> 32); - bytes[fill++] = ur_mask_8(val >> 40); - bytes[fill++] = ur_mask_8(val >> 48); - bytes[fill++] = ur_mask_8(val >> 56); - - // no offset is possible here - // - bsw->fill = fill; - bsw->off = 0; - return; - } - - case 7: { - bytes[fill++] = ur_mask_8(val); - bytes[fill++] = ur_mask_8(val >> 8); - bytes[fill++] = ur_mask_8(val >> 16); - bytes[fill++] = ur_mask_8(val >> 24); - bytes[fill++] = ur_mask_8(val >> 32); - bytes[fill++] = ur_mask_8(val >> 40); - bytes[fill++] = ur_mask_8(val >> 48); - val >>= 56; - } break; - - case 6: { - bytes[fill++] = ur_mask_8(val); - bytes[fill++] = ur_mask_8(val >> 8); - bytes[fill++] = ur_mask_8(val >> 16); - bytes[fill++] = ur_mask_8(val >> 24); - bytes[fill++] = ur_mask_8(val >> 32); - bytes[fill++] = ur_mask_8(val >> 40); - val >>= 48; - } break; - - case 5: { - bytes[fill++] = ur_mask_8(val); - bytes[fill++] = ur_mask_8(val >> 8); - bytes[fill++] = ur_mask_8(val >> 16); - bytes[fill++] = ur_mask_8(val >> 24); - bytes[fill++] = ur_mask_8(val >> 32); - val >>= 40; - } break; - - case 4: { - bytes[fill++] = ur_mask_8(val); - bytes[fill++] = ur_mask_8(val >> 8); - bytes[fill++] = ur_mask_8(val >> 16); - bytes[fill++] = ur_mask_8(val >> 24); - val >>= 32; - } break; - - case 3: { - bytes[fill++] = ur_mask_8(val); - bytes[fill++] = ur_mask_8(val >> 8); - bytes[fill++] = ur_mask_8(val >> 16); - val >>= 24; - } break; - - case 2: { - bytes[fill++] = ur_mask_8(val); - bytes[fill++] = ur_mask_8(val >> 8); - val >>= 16; - } break; - - case 1: { - bytes[fill++] = ur_mask_8(val); - val >>= 8; - } break; - } - - off = ur_mask_3(len); - - if ( off ) { - bytes[fill] = (uint8_t)(val & ((1 << off) - 1)); - } - - bsw->fill = fill; - bsw->off = off; -} - -void -ur_bsw64(ur_bsw_t *bsw, uint8_t len, uint64_t val) -{ - uint8_t need; - - len = ur_min(64, len); - need = ur_bloq_up3( bsw->off + len ); - - if ( bsw->fill + need >= bsw->size ) { - ur_bsw_grow(bsw, ur_max(need, bsw->prev)); - } - - _bsw64_unsafe(bsw, len, val); -} - -static inline void -_bsw_bytes_unsafe(ur_bsw_t *bsw, const uint64_t len, const uint8_t* src) -{ - uint64_t fill = bsw->fill; - uint8_t off = bsw->off; - uint8_t *dst = bsw->bytes + fill; - - if ( !off ) { - const uint64_t len_byt = len >> 3; - const uint8_t len_bit = ur_mask_3(len); - - memcpy(dst, src, len_byt); - bsw->fill = fill + len_byt; - - if ( len_bit ) { - dst[len_byt] = src[len_byt] & ((1 << len_bit) - 1); - bsw->off = len_bit; - } - } - else { - const uint8_t rest = 8 - off; - - if ( rest >= len ) { - uint16_t ful = off + len; - - *dst ^= (*src & ((1 << len) - 1)) << off; - - if ( ful >> 3 ) { - bsw->fill = fill + 1; - } - - bsw->off = ur_mask_3(ful); - } - else { - const uint64_t nel = len - rest; - const uint64_t len_byt = nel >> 3; - const uint8_t len_bit = ur_mask_3(nel); - - *dst++ ^= *src << off; - - for ( uint64_t i = 0; i < len_byt; i++ ) { - dst[i] = (src[i] >> rest) ^ (src[i + 1] << off); - } - - { - uint8_t tal = (src[len_byt] >> rest) - ^ (( off > len_bit ) ? 0 : (src[len_byt + 1] << off)); - dst[len_byt] = tal & ((1 << len_bit) - 1); - } - - bsw->fill = fill + len_byt + 1; - bsw->off = len_bit; - } - } - - bsw->bits += len; -} - -void -ur_bsw_bytes(ur_bsw_t *bsw, uint64_t len, uint8_t *byt) -{ - uint64_t need = ur_bloq_up3(len + bsw->off); - - if ( bsw->fill + need >= bsw->size ) { - ur_bsw_grow(bsw, ur_max(need, bsw->prev)); - } - - _bsw_bytes_unsafe(bsw, len, byt); -} - -static inline void -_bsw_bex_unsafe(ur_bsw_t *bsw, uint8_t n) -{ - uint64_t fill = bsw->fill; - uint8_t off = bsw->off; - uint32_t bits = n + off; - - fill += bits >> 3; - off = ur_mask_3(bits); - - bsw->bytes[fill] ^= 1 << off; - - if ( 7 == off ) { - bsw->off = 0; - bsw->fill = 1 + fill; - } - else { - bsw->off = 1 + off; - bsw->fill = fill; - } - - bsw->bits += 1 + n; -} - -void -ur_bsw_bex(ur_bsw_t *bsw, uint8_t n) -{ - uint64_t need = ur_bloq_up3(1 + n + bsw->off); - - if ( bsw->fill + need >= bsw->size ) { - ur_bsw_grow(bsw, ur_max(need, bsw->prev)); - } - - _bsw_bex_unsafe(bsw, n); -} - -static inline void -_bsw_mat64_unsafe(ur_bsw_t *bsw, uint8_t len, uint64_t val) -{ - if ( 0 == len ) { - _bsw_bit_unsafe(bsw, 1); - } - else { - { - uint8_t nel = ur_met0_64(len); - _bsw_bex_unsafe(bsw, nel); - _bsw64_unsafe(bsw, nel - 1, len); - } - - _bsw64_unsafe(bsw, len, val); - } -} - -/* -* the length of a "mat" run-length encoded atom of [len] bits -*/ -#define MAT_LEN(len) ( ( 0 == len ) ? 1 : len + (2 * ur_met0_64((uint64_t)len)) ) - -void -ur_bsw_mat64(ur_bsw_t *bsw, uint8_t len, uint64_t val) -{ - uint8_t need; - - len = ur_min(64, len); - need = ur_bloq_up3( bsw->off + MAT_LEN(len) ); - - if ( bsw->fill + need >= bsw->size ) { - ur_bsw_grow(bsw, ur_max(need, bsw->prev)); - } - - _bsw_mat64_unsafe(bsw, len, val); -} - -static inline void -_bsw_mat_bytes_unsafe(ur_bsw_t *bsw, uint64_t len, uint8_t *byt) -{ - if ( 0 == len ) { - _bsw_bit_unsafe(bsw, 1); - } - else { - // write run-length - // - { - uint8_t nel = ur_met0_64(len); - _bsw_bex_unsafe(bsw, nel); - _bsw64_unsafe(bsw, nel - 1, len); - } - - _bsw_bytes_unsafe(bsw, len, byt); - } -} - -void -ur_bsw_mat_bytes(ur_bsw_t *bsw, uint64_t len, uint8_t *byt) -{ - uint64_t need = ur_bloq_up3( bsw->off + MAT_LEN(len) ); - - if ( bsw->fill + need >= bsw->size ) { - ur_bsw_grow(bsw, ur_max(need, bsw->prev)); - } - - _bsw_mat_bytes_unsafe(bsw, len, byt); -} - -static inline void -_bsw_back64(ur_bsw_t *bsw, uint8_t len, uint64_t val) -{ - _bsw8_unsafe(bsw, 2, 3); - _bsw_mat64_unsafe(bsw, len, val); -} - -void -ur_bsw_back64(ur_bsw_t *bsw, uint8_t len, uint64_t val) -{ - uint8_t need; - - len = ur_min(64, len); - need = ur_bloq_up3( 2 + bsw->off + MAT_LEN(len) ); - - if ( bsw->fill + need >= bsw->size ) { - ur_bsw_grow(bsw, ur_max(need, bsw->prev)); - } - - _bsw_back64(bsw, len, val); -} - -static inline void -_bsw_atom64(ur_bsw_t *bsw, uint8_t len, uint64_t val) -{ - _bsw_bit_unsafe(bsw, 0); - _bsw_mat64_unsafe(bsw, len, val); -} - -void -ur_bsw_atom64(ur_bsw_t *bsw, uint8_t len, uint64_t val) -{ - uint8_t need; - - len = ur_min(64, len); - need = ur_bloq_up3( 1 + bsw->off + MAT_LEN(len) ); - - if ( bsw->fill + need >= bsw->size ) { - ur_bsw_grow(bsw, ur_max(need, bsw->prev)); - } - - _bsw_atom64(bsw, len, val); -} - -static inline void -_bsw_atom_bytes_unsafe(ur_bsw_t *bsw, uint64_t len, uint8_t *byt) -{ - _bsw_bit_unsafe(bsw, 0); - _bsw_mat_bytes_unsafe(bsw, len, byt); -} - -void -ur_bsw_atom_bytes(ur_bsw_t *bsw, uint64_t len, uint8_t *byt) -{ - uint64_t need = ur_bloq_up3( 1 + bsw->off + MAT_LEN(len) ); - - if ( bsw->fill + need >= bsw->size ) { - ur_bsw_grow(bsw, ur_max(need, bsw->prev)); - } - - _bsw_atom_bytes_unsafe(bsw, len, byt); -} - -void -ur_bsw_cell(ur_bsw_t *bsw) -{ - uint8_t need = ur_bloq_up3( 2 + bsw->off ); - - if ( bsw->fill + need >= bsw->size ) { - ur_bsw_grow(bsw, ur_max(need, bsw->prev)); - } - - _bsw8_unsafe(bsw, 2, 1); -} diff --git a/pkg/urbit/ur/hashcons.c b/pkg/urbit/ur/hashcons.c deleted file mode 100644 index a2dd691d7..000000000 --- a/pkg/urbit/ur/hashcons.c +++ /dev/null @@ -1,1025 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "ur/defs.h" -#include "ur/hashcons.h" - -// declarations of inline functions -// -uint64_t -ur_met0_bytes_unsafe(uint64_t len, uint8_t *byt); - -static void* -_oom(const char* cap, void* v) -{ - if ( !v ) { - fprintf(stderr, - "ur: hashcons: %s: allocation failed, out of memory\r\n", cap); - abort(); - } - - return v; -} - -void -ur_dict32_grow(ur_root_t *r, ur_dict32_t *dict, uint64_t prev, uint64_t size) -{ - ur_pail32_t *buckets, *old_buckets = dict->buckets; - uint8_t *fills, *old_fills = dict->fills; - uint64_t old_size = dict->size; - uint64_t i, next = prev + size; - - buckets = _oom("dict32_grow", calloc(next, sizeof(*buckets))); - fills = _oom("dict32_grow", calloc(next, sizeof(*fills))); - - if ( old_buckets ) { - for ( i = 0; i < old_size; i++ ) { - ur_pail32_t *old_bucket = &(old_buckets[i]); - uint8_t j, old_fill = old_fills[i]; - - for ( j = 0; j < old_fill; j++ ) { - uint32_t val = old_bucket->vals[j]; - ur_nref ref = old_bucket->refs[j]; - ur_mug mug = ur_nref_mug(r, ref); - - uint64_t idx = ( mug % next ); - ur_pail32_t *bucket = &(buckets[idx]); - uint8_t new_fill = fills[idx]; - - if ( ur_pail_max == new_fill ) { - free(buckets); - free(fills); - return ur_dict32_grow(r, dict, size, next); - } - - bucket->refs[new_fill] = ref; - bucket->vals[new_fill] = val; - fills[idx] = 1 + new_fill; - } - } - - free(old_buckets); - free(old_fills); - } - - dict->prev = size; - dict->size = next; - dict->fills = fills; - dict->buckets = buckets; -} - -ur_bool_t -ur_dict32_get(ur_root_t *r, ur_dict32_t *dict, ur_nref ref, uint32_t *out) -{ - ur_mug mug = ur_nref_mug(r, ref); - uint64_t idx = ( mug % dict->size ); - - ur_pail32_t *bucket = &(dict->buckets[idx]); - uint8_t i, fill = dict->fills[idx]; - - for ( i = 0; i < fill; i++ ) { - if ( ref == bucket->refs[i] ) { - *out = bucket->vals[i]; - return 1; - } - } - - return 0; -} - -void -ur_dict32_put(ur_root_t *r, ur_dict32_t *dict, ur_nref ref, uint32_t val) -{ - ur_mug mug = ur_nref_mug(r, ref); - - while ( 1 ) { - uint64_t idx = ( mug % dict->size ); - ur_pail32_t *bucket = &(dict->buckets[idx]); - uint8_t i, fill = dict->fills[idx]; - - for ( i = 0; i < fill; i++ ) { - if ( ref == bucket->refs[i] ) { - bucket->vals[i] = val; - return; - } - } - - if ( ur_pail_max == fill ) { - ur_dict32_grow(r, dict, dict->prev, dict->size); - continue; - } - - bucket->refs[fill] = ref; - bucket->vals[fill] = val; - dict->fills[idx] = 1 + fill; - break; - } -} - -void -ur_dict32_wipe(ur_dict32_t *dict) -{ - uint8_t *fills = dict->fills; - uint64_t size = dict->size; - - memset(fills, 0, sizeof(*fills) * size); -} - -void -ur_dict64_grow(ur_root_t *r, ur_dict64_t *dict, uint64_t prev, uint64_t size) -{ - ur_pail64_t *buckets, *old_buckets = dict->buckets; - uint8_t *fills, *old_fills = dict->fills; - uint64_t old_size = dict->size; - uint64_t i, next = prev + size; - - buckets = _oom("dict64_grow", calloc(next, sizeof(*buckets))); - fills = _oom("dict64_grow", calloc(next, sizeof(*fills))); - - if ( old_buckets ) { - for ( i = 0; i < old_size; i++ ) { - ur_pail64_t *old_bucket = &(old_buckets[i]); - uint8_t j, old_fill = old_fills[i]; - - for ( j = 0; j < old_fill; j++ ) { - uint64_t val = old_bucket->vals[j]; - ur_nref ref = old_bucket->refs[j]; - ur_mug mug = ur_nref_mug(r, ref); - - uint64_t idx = ( mug % next ); - ur_pail64_t *bucket = &(buckets[idx]); - uint8_t new_fill = fills[idx]; - - if ( ur_pail_max == new_fill ) { - free(buckets); - free(fills); - return ur_dict64_grow(r, dict, size, next); - } - - bucket->refs[new_fill] = ref; - bucket->vals[new_fill] = val; - fills[idx] = 1 + new_fill; - } - } - - free(old_buckets); - free(old_fills); - } - - dict->prev = size; - dict->size = next; - dict->fills = fills; - dict->buckets = buckets; -} - -ur_bool_t -ur_dict64_get(ur_root_t *r, ur_dict64_t *dict, ur_nref ref, uint64_t *out) -{ - ur_mug mug = ur_nref_mug(r, ref); - uint64_t idx = ( mug % dict->size ); - - ur_pail64_t *bucket = &(dict->buckets[idx]); - uint8_t i, fill = dict->fills[idx]; - - for ( i = 0; i < fill; i++ ) { - if ( ref == bucket->refs[i] ) { - *out = bucket->vals[i]; - return 1; - } - } - - return 0; -} - -void -ur_dict64_put(ur_root_t *r, ur_dict64_t *dict, ur_nref ref, uint64_t val) -{ - ur_mug mug = ur_nref_mug(r, ref); - - while ( 1 ) { - uint64_t idx = ( mug % dict->size ); - ur_pail64_t *bucket = &(dict->buckets[idx]); - uint8_t i, fill = dict->fills[idx]; - - for ( i = 0; i < fill; i++ ) { - if ( ref == bucket->refs[i] ) { - bucket->vals[i] = val; - return; - } - } - - if ( ur_pail_max == fill ) { - ur_dict64_grow(r, dict, dict->prev, dict->size); - continue; - } - - bucket->refs[fill] = ref; - bucket->vals[fill] = val; - dict->fills[idx] = 1 + fill; - break; - } -} - -void -ur_dict64_wipe(ur_dict64_t *dict) -{ - uint8_t *fills = dict->fills; - uint64_t size = dict->size; - - memset(fills, 0, sizeof(*fills) * size); -} - -void -ur_dict_grow(ur_root_t *r, ur_dict_t *dict, uint64_t prev, uint64_t size) -{ - ur_pail_t *buckets, *old_buckets = dict->buckets; - uint8_t *fills, *old_fills = dict->fills; - uint64_t old_size = dict->size; - uint64_t i, next = prev + size; - - buckets = _oom("dict_grow", calloc(next, sizeof(*buckets))); - fills = _oom("dict_grow", calloc(next, sizeof(*fills))); - - if ( old_buckets ) { - for ( i = 0; i < old_size; i++ ) { - ur_pail_t *old_bucket = &(old_buckets[i]); - uint8_t j, old_fill = old_fills[i]; - - for ( j = 0; j < old_fill; j++ ) { - ur_nref ref = old_bucket->refs[j]; - ur_mug mug = ur_nref_mug(r, ref); - - uint64_t idx = ( mug % next ); - ur_pail_t *bucket = &(buckets[idx]); - uint8_t new_fill = fills[idx]; - - if ( ur_pail_max == new_fill ) { - free(buckets); - free(fills); - return ur_dict_grow(r, dict, size, next); - } - - bucket->refs[new_fill] = ref; - fills[idx] = 1 + new_fill; - } - } - - free(old_buckets); - free(old_fills); - } - - dict->prev = size; - dict->size = next; - dict->fills = fills; - dict->buckets = buckets; -} - -ur_bool_t -ur_dict_get(ur_root_t *r, ur_dict_t *dict, ur_nref ref) -{ - ur_mug mug = ur_nref_mug(r, ref); - uint64_t idx = ( mug % dict->size ); - - ur_pail_t *bucket = &(dict->buckets[idx]); - uint8_t i, fill = dict->fills[idx]; - - for ( i = 0; i < fill; i++ ) { - if ( ref == bucket->refs[i] ) { - return 1; - } - } - - return 0; -} - -void -ur_dict_put(ur_root_t *r, ur_dict_t *dict, ur_nref ref) -{ - ur_mug mug = ur_nref_mug(r, ref); - - while ( 1 ) { - uint64_t idx = ( mug % dict->size ); - ur_pail_t *bucket = &(dict->buckets[idx]); - uint8_t i, fill = dict->fills[idx]; - - for ( i = 0; i < fill; i++ ) { - if ( ref == bucket->refs[i] ) { - return; - } - } - - if ( ur_pail_max == fill ) { - ur_dict_grow(r, dict, dict->prev, dict->size); - continue; - } - - bucket->refs[fill] = ref; - dict->fills[idx] = 1 + fill; - break; - } -} - -void -ur_dict_wipe(ur_dict_t *dict) -{ - uint8_t *fills = dict -> fills; - uint64_t size = dict->size; - - memset(fills, 0, sizeof(*fills) * size); -} - -void -ur_dict_free(ur_dict_t *dict) -{ - free(dict->buckets); - free(dict->fills); - dict->buckets = 0; -} - -ur_mug -ur_mug_bytes(const uint8_t *byt, uint64_t len) -{ - uint32_t seed = 0xcafebabe; - uint8_t i = 0; - - while ( i < 8 ) { - ur_mug mug; - uint32_t raw; - MurmurHash3_x86_32(byt, len, seed, &raw); - mug = (raw >> 31) ^ ( ur_mask_31(raw) ); - - if ( 0 == mug ) { - seed++; i++; - } - else { - return mug; - } - } - - return (ur_mug)0x7fff; -} - -ur_mug -ur_mug32(uint32_t x) -{ - uint8_t byt[4] = { - ur_mask_8(x >> 0), - ur_mask_8(x >> 8), - ur_mask_8(x >> 16), - ur_mask_8(x >> 24) - }; - - return ur_mug_bytes(byt, ur_met3_32(x)); -} - -ur_mug -ur_mug64(uint64_t x) -{ - uint8_t byt[8] = { - ur_mask_8(x >> 0), - ur_mask_8(x >> 8), - ur_mask_8(x >> 16), - ur_mask_8(x >> 24), - ur_mask_8(x >> 32), - ur_mask_8(x >> 40), - ur_mask_8(x >> 48), - ur_mask_8(x >> 56) - }; - - return ur_mug_bytes(byt, ur_met3_64(x)); -} - -ur_mug -ur_mug_both(ur_mug hed, ur_mug tal) -{ - uint32_t seed = 0xdeadbeef; - uint8_t len = 4 + ur_bloq_up3(ur_met0_32(tal)); - uint8_t i = 0; - uint8_t byt[8] = { - ur_mask_8(hed >> 0), - ur_mask_8(hed >> 8), - ur_mask_8(hed >> 16), - ur_mask_8(hed >> 24), - ur_mask_8(tal >> 0), - ur_mask_8(tal >> 8), - ur_mask_8(tal >> 16), - ur_mask_8(tal >> 24) - }; - - while ( i < 8 ) { - ur_mug mug; - uint32_t raw; - MurmurHash3_x86_32(byt, len, seed, &raw); - mug = (raw >> 31) ^ ( ur_mask_31(raw) ); - - if ( 0 == mug ) { - seed++; i++; - } - else { - return mug; - } - } - - return (ur_mug)0xfffe; -} - -ur_mug -ur_nref_mug(ur_root_t *r, ur_nref ref) -{ - switch ( ur_nref_tag(ref) ) { - default: assert(0); - - case ur_direct: return ur_mug64(ref); - case ur_iatom: return r->atoms.mugs[ur_nref_idx(ref)]; - case ur_icell: return r->cells.mugs[ur_nref_idx(ref)]; - } -} - -ur_bool_t -ur_deep(ur_nref ref) -{ - return ur_icell == ur_nref_tag(ref); -} - -ur_nref -ur_head(ur_root_t *r, ur_nref ref) -{ - assert( ur_deep(ref) ); - return r->cells.heads[ur_nref_idx(ref)]; -} - -ur_nref -ur_tail(ur_root_t *r, ur_nref ref) -{ - assert( ur_deep(ref) ); - return r->cells.tails[ur_nref_idx(ref)]; -} - -void -ur_atoms_grow(ur_atoms_t *atoms) -{ - uint64_t prev = atoms->prev; - uint64_t size = atoms->size; - uint64_t next = prev + size; - uint8_t **bytes = atoms->bytes; - uint64_t *lens = atoms->lens; - ur_mug *mugs = atoms->mugs; - - atoms->bytes = _oom("atoms_grow", malloc(next * ( sizeof(*atoms->bytes) - + sizeof(*atoms->lens) - + sizeof(*atoms->mugs) ))); - atoms->lens = (void*)((char*)atoms->bytes + (next * sizeof(*atoms->bytes))); - atoms->mugs = (void*)((char*)atoms->lens + (next * sizeof(*atoms->lens))); - - if ( bytes ) { - memcpy(atoms->bytes, bytes, size * (sizeof(*bytes))); - memcpy(atoms->lens, lens, size * (sizeof(*lens))); - memcpy(atoms->mugs, mugs, size * (sizeof(*mugs))); - - free(bytes); - } - - atoms->prev = size; - atoms->size = next; -} - -void -ur_cells_grow(ur_cells_t *cells) -{ - uint64_t prev = cells->prev; - uint64_t size = cells->size; - uint64_t next = prev + size; - ur_nref *heads = cells->heads; - ur_nref *tails = cells->tails; - ur_mug *mugs = cells->mugs; - - cells->heads = _oom("cells_grow", malloc(next * ( sizeof(*cells->heads) - + sizeof(*cells->heads) - + sizeof(*cells->mugs) ))); - cells->tails = (void*)((char*)cells->heads + (next * sizeof(*cells->heads))); - cells->mugs = (void*)((char*)cells->tails + (next * sizeof(*cells->tails))); - - if ( heads ) { - memcpy(cells->heads, heads, size * (sizeof(*heads))); - memcpy(cells->tails, tails, size * (sizeof(*tails))); - memcpy(cells->mugs, mugs, size * (sizeof(*mugs))); - - free(heads); - } - - cells->prev = size; - cells->size = next; -} - -void -ur_bytes(ur_root_t *r, ur_nref ref, uint8_t **byt, uint64_t *len) -{ - assert( !ur_deep(ref) ); - switch ( ur_nref_tag(ref) ) { - default: assert(0); - - case ur_direct: { - *len = ur_met3_64(ref); - // XX little-endian - // - *byt = (uint8_t*)&ref; - } break; - - case ur_iatom: { - uint64_t idx = ur_nref_idx(ref); - *len = r->atoms.lens[idx]; - *byt = r->atoms.bytes[idx]; - } break; - } -} - -uint64_t -ur_met(ur_root_t *r, uint8_t bloq, ur_nref ref) -{ - uint64_t m_bit; - - // XX return bool for cells, length in out parameter - // - assert( !ur_deep(ref) ); - - if ( ur_direct == ur_nref_tag(ref) ) { - m_bit = ur_met0_64(ref); - } - else { - uint64_t idx = ur_nref_idx(ref); - uint64_t len = r->atoms.lens[idx]; - uint8_t *byt = r->atoms.bytes[idx]; - - m_bit = ur_met0_bytes_unsafe(len, byt); - } - - switch ( bloq ) { - case 0: return m_bit; - case 1: return ur_bloq_up1(m_bit); - case 2: return ur_bloq_up2(m_bit); - case 3: return ur_bloq_up3(m_bit); - - default: { - uint64_t m_byt = ur_bloq_up3(m_bit); - uint8_t off = (bloq - 3); - return (m_byt + ((1ULL << off) - 1)) >> off; - } - } -} - -static ur_nref -_coin_unsafe(ur_atoms_t *atoms, ur_mug mug, uint64_t len, uint8_t *byt) -{ - uint64_t fill = atoms->fill; - ur_tag tag = ur_iatom; - ur_nref tom = ( fill | ((uint64_t)tag << 62) ); - - // XX necessary? - // - assert( 62 >= ur_met0_64(fill) ); - - atoms->bytes[fill] = byt; - atoms->lens[fill] = len; - atoms->mugs[fill] = mug; - atoms->fill = 1 + fill; - - return tom; -} - -static ur_nref -_cons_unsafe(ur_cells_t *cells, ur_mug mug, ur_nref hed, ur_nref tal) -{ - uint64_t fill = cells->fill; - ur_tag tag = ur_icell; - ur_nref cel = ( fill | ((uint64_t)tag << 62) ); - - // XX necessary? - // - assert( 62 >= ur_met0_64(fill) ); - - cells->mugs[fill] = mug; - cells->heads[fill] = hed; - cells->tails[fill] = tal; - cells->fill = 1 + fill; - - return cel; -} - -ur_nref -ur_coin_bytes_unsafe(ur_root_t *r, uint64_t len, uint8_t *byt) -{ - ur_atoms_t *atoms = &(r->atoms); - ur_dict_t *dict = &(atoms->dict); - ur_mug mug = ur_mug_bytes(byt, len); - - while ( 1 ) { - uint64_t idx = ( mug % dict->size ); - ur_pail_t *bucket = &(dict->buckets[idx]); - uint8_t i, b_fill = dict->fills[idx]; - ur_nref tom; - - for ( i = 0; i < b_fill; i++ ) { - uint8_t *t_byt; - uint64_t t_len; - tom = bucket->refs[i]; - - ur_bytes(r, tom, &t_byt, &t_len); - - if ( (t_len == len) - && (0 == memcmp(t_byt, byt, len)) ) - { - return tom; - } - } - - if ( ur_pail_max == b_fill ) { - ur_dict_grow(r, dict, dict->prev, dict->size); - continue; - } - - if ( atoms->fill == atoms->size ) { - ur_atoms_grow(atoms); - } - - tom = _coin_unsafe(atoms, mug, len, byt); - - bucket->refs[b_fill] = tom; - dict->fills[idx] = 1 + b_fill; - - return tom; - } -} - -ur_nref -ur_coin_bytes(ur_root_t *r, uint64_t len, uint8_t *byt) -{ - // strip trailing zeroes - // - while ( len && !byt[len - 1] ) { - len--; - } - - // produce a direct atom if possible - // - if ( 62 >= ur_met0_bytes_unsafe(len, byt) ) { - uint64_t i, direct = 0; - - for ( i = 0; i < len; i++ ) { - direct |= byt[i] << (8 * i); - } - - return (ur_nref)direct; - } - else { - uint8_t *copy = _oom("coin_bytes", malloc(len)); - memcpy(copy, byt, len); - - return ur_coin_bytes_unsafe(r, len, copy); - } -} - -ur_nref -ur_coin64(ur_root_t *r, uint64_t n) -{ - if ( ur_direct == ur_nref_tag(n) ) { - return n; - } - else { - uint8_t *byt; - assert( 8 == ur_met3_64(n) ); - - byt = _oom("coin64", malloc(8)); - - byt[0] = ur_mask_8(n); - byt[1] = ur_mask_8(n >> 8); - byt[2] = ur_mask_8(n >> 16); - byt[3] = ur_mask_8(n >> 24); - byt[4] = ur_mask_8(n >> 32); - byt[5] = ur_mask_8(n >> 40); - byt[6] = ur_mask_8(n >> 48); - byt[7] = ur_mask_8(n >> 56); - - return ur_coin_bytes_unsafe(r, 8, byt); - } -} - -ur_nref -ur_cons(ur_root_t *r, ur_nref hed, ur_nref tal) -{ - ur_cells_t *cells = &(r->cells); - ur_dict_t *dict = &(cells->dict); - ur_mug mug = ur_mug_both(ur_nref_mug(r, hed), - ur_nref_mug(r, tal)); - - while ( 1 ) { - uint64_t idx = ( mug % dict->size ); - ur_pail_t *bucket = &(dict->buckets[idx]); - uint8_t i, b_fill = dict->fills[idx]; - ur_nref cel; - - for ( i = 0; i < b_fill; i++ ) { - cel = bucket->refs[i]; - - if ( (hed == ur_head(r, cel)) - && (tal == ur_tail(r, cel)) ) - { - return cel; - } - } - - if ( ur_pail_max == b_fill ) { - ur_dict_grow(r, dict, dict->prev, dict->size); - continue; - } - - if ( cells->fill == cells->size ) { - ur_cells_grow(cells); - } - - cel = _cons_unsafe(cells, mug, hed, tal); - - bucket->refs[b_fill] = cel; - dict->fills[idx] = 1 + b_fill; - - return cel; - } -} - -static void -_print_memory(FILE *f, const char *c, uint64_t bytes) -{ - if ( !bytes ) { - fprintf(f, "%s: B/0\r\n", c); - } - else { - uint32_t g = (bytes / 1000000000); - uint32_t m = (bytes % 1000000000) / 1000000; - uint32_t k = (bytes % 1000000) / 1000; - uint32_t b = (bytes % 1000); - - if ( g ) { - fprintf(f, "%s: GB/%d.%03d.%03d.%03d\r\n", c, g, m, k, b); - } - else if ( m ) { - fprintf(f, "%s: MB/%d.%03d.%03d\r\n", c, m, k, b); - } - else if ( k ) { - fprintf(f, "%s: KB/%d.%03d\r\n", c, k, b); - } - else if ( b ) { - fprintf(f, "%s: B/%d\r\n", c, b); - } - } -} - -static uint64_t -_dict_info(FILE *f, ur_dict_t *dict) -{ - uint64_t data = dict->size * sizeof(*dict->buckets); - _print_memory(f, " dict", data); - return data; -} - -static uint64_t -_atoms_info(FILE *f, ur_atoms_t *atoms) -{ - uint64_t total = 0; - uint64_t size = atoms->size; - uint64_t fill = atoms->fill; - uint64_t refs = size * ( sizeof(*atoms->bytes) - + sizeof(*atoms->lens) - + sizeof(*atoms->mugs) ); - uint64_t i, data = 0; - - fprintf(f, " atoms (%" PRIu64 "):\r\n", fill); - - _print_memory(f, " refs", refs); - total += refs; - - for ( i = 0; i < fill; i++ ) { - data += atoms->lens[i]; - } - _print_memory(f, " data", data); - total += data; - - total += _dict_info(f, &(atoms->dict)); - _print_memory(f, " total", total); - return total; -} - -static uint64_t -_cells_info(FILE *f, ur_cells_t *cells) -{ - uint64_t total = 0; - uint64_t size = cells->size; - uint64_t fill = cells->fill; - uint64_t refs = size * ( sizeof(*cells->heads) - + sizeof(*cells->heads) - + sizeof(*cells->mugs) ); - - fprintf(f, " cells (%" PRIu64 "):\r\n", fill); - - _print_memory(f, " refs", refs); - total += refs; - - total += _dict_info(f, &(cells->dict)); - _print_memory(f, " total", total); - return total; -} - -void -ur_root_info(FILE *f, ur_root_t *r) -{ - uint64_t total = 0; - - fprintf(stderr, "hash-cons arena:\r\n"); - - { - uint64_t root = sizeof(*r); - _print_memory(f, " root", root); - total += root; - } - - total += _atoms_info(f, &(r->atoms)); - total += _cells_info(f, &(r->cells)); - - _print_memory(f, "total", total); -} - -static void -_atoms_free(ur_atoms_t *atoms) -{ - uint8_t **bytes = atoms->bytes; - uint64_t i, fill = atoms->fill; - - for ( i = 0; i < fill; i++ ) { - free(bytes[i]); - } - - ur_dict_free(&(atoms->dict)); - free(bytes); -} - -static void -_cells_free(ur_cells_t *cells) -{ - ur_dict_free(&(cells->dict)); - free(cells->heads); -} - -void -ur_root_free(ur_root_t *r) -{ - _atoms_free(&(r->atoms)); - _cells_free(&(r->cells)); - free(r); -} - -ur_root_t* -ur_root_init(void) -{ - ur_root_t *r = _oom("root_init", calloc(1, sizeof(*r))); - - { - ur_dict_t *dict; - - // allocate atom storage - // - r->atoms.prev = ur_fib11; - r->atoms.size = ur_fib12; - ur_atoms_grow(&(r->atoms)); - - // allocate atom hashtable - // - dict = &(r->atoms.dict); - ur_dict_grow(r, dict, ur_fib11, ur_fib12); - - // allocate cell storage - // - r->cells.prev = ur_fib11; - r->cells.size = ur_fib12; - ur_cells_grow(&(r->cells)); - - // allocate cell hashtable - // - dict = &(r->cells.dict); - ur_dict_grow(r, dict, ur_fib11, ur_fib12); - } - - return r; -} - -void -ur_nvec_free(ur_nvec_t *v) -{ - free(v->refs); -} - -void -ur_nvec_init(ur_nvec_t *v, uint64_t size) -{ - v->fill = 0; - v->refs = _oom("nvec_init", calloc(size, sizeof(ur_nref))); -} - -/* -** define opaque struct ur_walk_fore_s (ie, ur_walk_fore_t) -*/ -struct ur_walk_fore_s { - ur_root_t *r; - uint32_t prev; - uint32_t size; - ur_nref *top; -}; - -ur_walk_fore_t* -ur_walk_fore_init_with(ur_root_t *r, - uint32_t s_prev, - uint32_t s_size) -{ - ur_walk_fore_t *w = _oom("walk_fore", malloc(sizeof(*w))); - w->top = _oom("walk_fore", malloc(s_size * sizeof(*w->top))); - w->prev = s_prev; - w->size = s_size; - w->r = r; - - return w; -} - -ur_walk_fore_t* -ur_walk_fore_init(ur_root_t *r) -{ - return ur_walk_fore_init_with(r, ur_fib10, ur_fib11); -} - -void -ur_walk_fore_with(ur_walk_fore_t *w, - ur_nref ref, - void *v, - void (*atom)(ur_root_t*, ur_nref, void*), - ur_bool_t (*cell)(ur_root_t*, ur_nref, void*)) -{ - ur_root_t *r = w->r; - uint32_t fill = 1; - - *w->top = ref; - - do { - // visit atom, pop stack - // - if ( !ur_deep(ref) ) { - atom(r, ref, v); - fill--; - } - // visit cell, pop stack if false - // - else if ( !cell(r, ref, v) ) { - fill--; - } - // push the tail, continue into the head - // - else { - w->top[fill++] = ur_tail(r, ref); - - // reallocate "stack" if full - // - if ( w->size == fill ) { - uint32_t next = w->prev + w->size; - w->top = _oom("walk_fore", realloc(w->top, next * sizeof(*w->top))); - w->prev = w->size; - w->size = next; - } - - w->top[fill] = ur_head(r, ref); - } - - ref = w->top[fill]; - } while ( fill ); -} - -void -ur_walk_fore_done(ur_walk_fore_t *w) -{ - free(w->top); - free(w); -} - -void -ur_walk_fore(ur_root_t *r, - ur_nref ref, - void *v, - void (*atom)(ur_root_t*, ur_nref, void*), - ur_bool_t (*cell)(ur_root_t*, ur_nref, void*)) -{ - ur_walk_fore_t *w = ur_walk_fore_init(r); - ur_walk_fore_with(w, ref, v, atom, cell); - ur_walk_fore_done(w); -} diff --git a/pkg/urbit/ur/serial.c b/pkg/urbit/ur/serial.c deleted file mode 100644 index 2bdfa2f4b..000000000 --- a/pkg/urbit/ur/serial.c +++ /dev/null @@ -1,586 +0,0 @@ -#include -#include - -#include "ur/ur.h" - -static void* -_oom(const char* cap, void* v) -{ - if ( !v ) { - fprintf(stderr, - "ur: hashcons: %s: allocation failed, out of memory\r\n", cap); - abort(); - } - - return v; -} - -static inline void -_bsw_atom(ur_root_t *r, ur_nref ref, ur_bsw_t *bsw, uint64_t len) -{ - switch ( ur_nref_tag(ref) ) { - default: assert(0); - - case ur_direct: return ur_bsw_atom64(bsw, len, ref); - - case ur_iatom: { - uint8_t *byt = r->atoms.bytes[ur_nref_idx(ref)]; - return ur_bsw_atom_bytes(bsw, len, byt); - } - } -} - -/* -** define opaque struct ur_jam_s (ie, ur_jam_t) -*/ -struct ur_jam_s { - ur_root_t *r; - ur_walk_fore_t *w; - ur_dict64_t dict; - ur_bsw_t bsw; -}; - -static void -_jam_atom(ur_root_t *r, ur_nref ref, void *ptr) -{ - ur_jam_t *j = ptr; - ur_dict64_t *dict = &j->dict; - ur_bsw_t *bsw = &j->bsw; - uint64_t bak, len = ur_met(r, 0, ref); - - if ( !ur_dict64_get(r, dict, ref, &bak) ) { - ur_dict64_put(r, dict, ref, bsw->bits); - - _bsw_atom(r, ref, bsw, len); - } - else { - uint64_t len_bak = ur_met0_64(bak); - - if ( len <= len_bak ) { - _bsw_atom(r, ref, bsw, len); - } - else { - ur_bsw_back64(bsw, len_bak, bak); - } - } -} - -static ur_bool_t -_jam_cell(ur_root_t *r, ur_nref ref, void *ptr) -{ - ur_jam_t *j = ptr; - ur_dict64_t *dict = &j->dict; - ur_bsw_t *bsw = &j->bsw; - uint64_t bak; - - if ( !ur_dict64_get(r, dict, ref, &bak) ) { - ur_dict64_put(r, dict, ref, bsw->bits); - - ur_bsw_cell(bsw); - return 1; - } - else { - ur_bsw_back64(bsw, ur_met0_64(bak), bak); - return 0; - } -} - -static uint64_t -_jam(ur_jam_t *j, - ur_nref ref, - uint64_t *len, - uint8_t **byt) -{ - ur_bsw_init(&j->bsw, ur_fib11, ur_fib12); - ur_walk_fore_with(j->w, ref, j, _jam_atom, _jam_cell); - return ur_bsw_done(&j->bsw, len, byt); -} - -ur_jam_t* -ur_jam_init_with(ur_root_t *r, - uint64_t d_prev, - uint64_t d_size, - uint32_t s_prev, - uint32_t s_size) -{ - ur_jam_t *j = _oom("jam_init", calloc(sizeof(*j), 1)); - j->w = ur_walk_fore_init_with(r, s_prev, s_size); - j->r = r; - - ur_dict64_grow(r, &j->dict, d_prev, d_size); - - return j; -} - -ur_jam_t* -ur_jam_init(ur_root_t *r) -{ - return ur_jam_init_with(r, ur_fib11, ur_fib12, // dict sizes - ur_fib10, ur_fib11); // stack sizes -} - -uint64_t -ur_jam_with(ur_jam_t *j, - ur_nref ref, - uint64_t *len, - uint8_t **byt) -{ - uint64_t bits = _jam(j, ref, len, byt); - ur_dict64_wipe(&j->dict); - return bits; -} - -void -ur_jam_done(ur_jam_t *j) -{ - ur_dict_free((ur_dict_t*)&j->dict); - ur_walk_fore_done(j->w); - free(j); -} - -uint64_t -ur_jam(ur_root_t *r, - ur_nref ref, - uint64_t *len, - uint8_t **byt) -{ - ur_jam_t *j = ur_jam_init(r); - uint64_t bits = _jam(j, ref, len, byt); - ur_jam_done(j); - return bits; -} - -/* -** stack frame for recording head vs tail iteration -** -** $? [CUE_HEAD bits=@] -** [hed=* bits=@] -*/ - -#define CUE_HEAD 0xffffffffffffffffULL - -typedef struct _cue_frame_s { - uint64_t ref; - uint64_t bits; -} _cue_frame_t; - -typedef struct _cue_stack_s { - uint32_t prev; - uint32_t size; - uint32_t fill; - _cue_frame_t* f; -} _cue_stack_t; - -static inline ur_cue_res_e -_cue_next(ur_root_t *r, - _cue_stack_t *s, - ur_bsr_t *bsr, - ur_dict64_t *dict, - ur_nref *out) -{ - while ( 1 ) { - uint64_t len, bits = bsr->bits; - ur_cue_tag_e tag; - ur_cue_res_e res; - - if ( ur_cue_good != (res = ur_bsr_tag(bsr, &tag)) ) { - return res; - } - - switch ( tag ) { - default: assert(0); - - case ur_jam_cell: { - // reallocate the stack if full - // - if ( s->fill == s->size ) { - uint32_t next = s->prev + s->size; - s->f = _oom("cue_next stack", realloc(s->f, next * sizeof(*s->f))); - s->prev = s->size; - s->size = next; - } - - // save a head-frame and read the head from the stream - // - { - _cue_frame_t* f = &(s->f[s->fill++]); - f->ref = CUE_HEAD; - f->bits = bits; - } - continue; - } - - case ur_jam_back: { - if ( ur_cue_good != (res = ur_bsr_rub_len(bsr, &len)) ) { - return res; - } - else if ( 62 < len ) { - return ur_cue_meme; - } - else { - uint64_t val, bak = ur_bsr64_any(bsr, len); - - if ( !ur_dict64_get(r, dict, bak, &val) ) { - return ur_cue_back; - } - - *out = (ur_nref)val; - return ur_cue_good; - } - } - - case ur_jam_atom: { - if ( ur_cue_good != (res = ur_bsr_rub_len(bsr, &len)) ) { - return res; - } - else if ( 62 >= len ) { - *out = (ur_nref)ur_bsr64_any(bsr, len); - } - else { - uint64_t len_byt = (len >> 3) + !!ur_mask_3(len); - uint8_t *byt = _oom("cue_next bytes", calloc(len_byt, 1)); - - ur_bsr_bytes_any(bsr, len, byt); - - // strip trailing zeroes - // - while ( len_byt && !byt[len_byt - 1] ) { - len_byt--; - } - - *out = ur_coin_bytes_unsafe(r, len_byt, byt); - } - - ur_dict64_put(r, dict, bits, (uint64_t)*out); - return ur_cue_good; - } - } - } -} - -/* -** define opaque struct ur_cue_s (ie, ur_cue_t) -*/ -struct ur_cue_s { - ur_root_t *r; - _cue_stack_t s; - ur_dict64_t dict; -}; - -static ur_cue_res_e -_cue(ur_cue_t *c, - uint64_t len, - const uint8_t *byt, - ur_nref *out) -{ - ur_bsr_t bsr = {0}; - ur_root_t *r = c->r; - _cue_stack_t *s = &c->s; - ur_dict64_t *dict = &c->dict; - ur_cue_res_e res; - ur_nref ref; - - // init bitstream-reader - // - if ( ur_cue_good != (res = ur_bsr_init(&bsr, len, byt)) ) { - return res; - } - // bit-cursor (and backreferences) must fit in 62-bit direct atoms - // - else if ( 0x7ffffffffffffffULL < len ) { - return ur_cue_meme; - } - - // advance into stream - // - res = _cue_next(r, s, &bsr, dict, &ref); - - // process result - // - while ( s->fill && (ur_cue_good == res) ) { - // peek at the top of the stack - // - _cue_frame_t *f = &(s->f[s->fill - 1]); - - // f is a head-frame; stash result and read the tail from the stream - // - if ( CUE_HEAD == f->ref ) { - f->ref = ref; - res = _cue_next(r, s, &bsr, dict, &ref); - } - // f is a tail-frame; pop the stack and continue - // - else { - ref = ur_cons(r, f->ref, ref); - ur_dict64_put(r, dict, f->bits, (uint64_t)ref); - s->fill--; - } - } - - if ( ur_cue_good == res ) { - *out = ref; - } - return res; -} - -ur_cue_t* -ur_cue_init_with(ur_root_t *r, - uint64_t d_prev, - uint64_t d_size, - uint32_t s_prev, - uint32_t s_size) -{ - ur_cue_t* c = _oom("cue_init", calloc(sizeof(*c), 1)); - c->r = r; - - ur_dict64_grow(r, &c->dict, d_prev, d_size); - - c->s.prev = s_prev; - c->s.size = s_size; - c->s.f = _oom("cue_test_init", malloc(s_size * sizeof(*c->s.f))); - - return c; -} - -ur_cue_t* -ur_cue_init(ur_root_t *r) -{ - return ur_cue_init_with(r, ur_fib11, ur_fib12, // dict sizes - ur_fib10, ur_fib11); // stack sizes -} - -ur_cue_res_e -ur_cue_with(ur_cue_t *c, - uint64_t len, - const uint8_t *byt, - ur_nref *out) -{ - ur_cue_res_e res = _cue(c, len, byt, out); - - // XX check size, shrink if above threshold - // - ur_dict64_wipe(&c->dict); - c->s.fill = 0; - - return res; -} - -void -ur_cue_done(ur_cue_t *c) -{ - - ur_dict_free((ur_dict_t*)&c->dict); - free(c->s.f); - free(c); -} - -ur_cue_res_e -ur_cue(ur_root_t *r, - uint64_t len, - const uint8_t *byt, - ur_nref *out) -{ - ur_cue_t *c = ur_cue_init(r); - ur_cue_res_e res = _cue(c, len, byt, out); - - ur_cue_done(c); - return res; -} - -/* -** stack frame for recording head vs tail iteration -** -** [hed=? bits=@] -** -*/ - -typedef struct _cue_test_frame_s { - ur_bool_t tal; - uint64_t bits; -} _cue_test_frame_t; - -typedef struct _cue_test_stack_s { - uint32_t prev; - uint32_t size; - uint32_t fill; - _cue_test_frame_t* f; -} _cue_test_stack_t; - -static inline ur_cue_res_e -_cue_test_next(_cue_test_stack_t *s, - ur_bsr_t *bsr, - ur_dict_t *dict) -{ - while ( 1 ) { - uint64_t len, bits = bsr->bits; - ur_cue_tag_e tag; - ur_cue_res_e res; - - if ( ur_cue_good != (res = ur_bsr_tag(bsr, &tag)) ) { - return res; - } - - switch ( tag ) { - default: assert(0); - - case ur_jam_cell: { - // reallocate the stack if full - // - if ( s->fill == s->size ) { - uint32_t next = s->prev + s->size; - s->f = _oom("cue_test", realloc(s->f, next * sizeof(*s->f))); - s->prev = s->size; - s->size = next; - } - - // save a head-frame and read the head from the stream - // - { - _cue_test_frame_t* f = &(s->f[s->fill++]); - f->tal = 0; - f->bits = bits; - } - continue; - } - - case ur_jam_back: { - if ( ur_cue_good != (res = ur_bsr_rub_len(bsr, &len)) ) { - return res; - } - else if ( 62 < len ) { - return ur_cue_meme; - } - else { - uint64_t bak = ur_bsr64_any(bsr, len); - return ur_dict_get((ur_root_t*)0, dict, bak) - ? ur_cue_good - : ur_cue_back; - } - } - - case ur_jam_atom: { - if ( ur_cue_good != (res = ur_bsr_rub_len(bsr, &len)) ) { - return res; - } - - ur_bsr_skip_any(bsr, len); - ur_dict_put((ur_root_t*)0, dict, bits); - return ur_cue_good; - } - } - } -} - -/* -** define opaque struct ur_cue_test_s (ie, ur_cue_test_t) -*/ -struct ur_cue_test_s { - _cue_test_stack_t s; - ur_dict_t dict; -}; - -static ur_cue_res_e -_cue_test(ur_cue_test_t *t, - uint64_t len, - const uint8_t *byt) -{ - ur_bsr_t bsr = {0}; - _cue_test_stack_t *s = &t->s; - ur_dict_t *dict = &t->dict; - ur_cue_res_e res; - - // init bitstream-reader - // - if ( ur_cue_good != (res = ur_bsr_init(&bsr, len, byt)) ) { - return res; - } - // bit-cursor (and backreferences) must fit in 62-bit direct atoms - // - else if ( 0x7ffffffffffffffULL < len ) { - return ur_cue_meme; - } - - // advance into stream - // - res = _cue_test_next(s, &bsr, dict); - - // process result - // - while ( s->fill && (ur_cue_good == res) ) { - // peek at the top of the stack - // - _cue_test_frame_t *f = &(s->f[s->fill - 1]); - - // f is a head-frame; stash result and read the tail from the stream - // - if ( !f->tal ) { - f->tal = 1; - res = _cue_test_next(s, &bsr, dict); - } - // f is a tail-frame; pop the stack and continue - // - else { - ur_dict_put((ur_root_t*)0, dict, f->bits); - s->fill--; - } - } - - return res; -} - -ur_cue_test_t* -ur_cue_test_init_with(uint64_t d_prev, - uint64_t d_size, - uint32_t s_prev, - uint32_t s_size) -{ - ur_cue_test_t* t = _oom("cue_test_init", calloc(sizeof(*t), 1)); - - ur_dict_grow((ur_root_t*)0, &t->dict, d_prev, d_size); - - t->s.prev = s_prev; - t->s.size = s_size; - t->s.f = _oom("cue_test_init", malloc(s_size * sizeof(*t->s.f))); - - return t; -} - -ur_cue_test_t* -ur_cue_test_init(void) -{ - return ur_cue_test_init_with(ur_fib11, ur_fib12, // dict sizes - ur_fib10, ur_fib11); // stack sizes -} - -ur_bool_t -ur_cue_test_with(ur_cue_test_t *t, - uint64_t len, - const uint8_t *byt) -{ - ur_bool_t ret = ur_cue_good == _cue_test(t, len, byt); - - // XX check size, shrink if above threshold - // - ur_dict_wipe(&t->dict); - t->s.fill = 0; - - return ret; -} - -void -ur_cue_test_done(ur_cue_test_t *t) -{ - ur_dict_free(&t->dict); - free(t->s.f); - free(t); -} - -ur_bool_t -ur_cue_test(uint64_t len, const uint8_t *byt) -{ - ur_cue_test_t *t = ur_cue_test_init(); - ur_bool_t ret = ur_cue_good == _cue_test(t, len, byt); - - ur_cue_test_done(t); - return ret; -} diff --git a/pkg/urbit/vere/auto.c b/pkg/urbit/vere/auto.c deleted file mode 100644 index e1d4de0c0..000000000 --- a/pkg/urbit/vere/auto.c +++ /dev/null @@ -1,442 +0,0 @@ -/* vere/auto.c -*/ -#include "all.h" -#include "vere/vere.h" - -/* u3_auto_plan(): enqueue an ovum. -*/ -u3_ovum* -u3_auto_plan(u3_auto* car_u, u3_ovum *egg_u) -{ - egg_u->car_u = car_u; - - if ( !car_u->ent_u ) { - c3_assert(!car_u->ext_u); - - egg_u->pre_u = egg_u->nex_u = 0; - car_u->ent_u = car_u->ext_u = egg_u; - car_u->dep_w = 1; - } - // enqueue at driver entry (back of the line) - // - // [pre_u] points towards [ext_u] (back in time) - // [nex_u] points towards [ent_u] (forward in time) - // - else { - egg_u->nex_u = 0; - egg_u->pre_u = car_u->ent_u; - - car_u->ent_u->nex_u = egg_u; - car_u->ent_u = egg_u; - car_u->dep_w++; - } - - u3_pier_spin(car_u->pir_u); - - return egg_u; -} - -/* u3_auto_redo(): retry an ovum. -*/ -u3_ovum* -u3_auto_redo(u3_auto* car_u, u3_ovum *egg_u) -{ - c3_assert( egg_u->car_u == car_u ); - - egg_u->try_w++; - - if ( !car_u->ent_u ) { - c3_assert(!car_u->ext_u); - - egg_u->pre_u = egg_u->nex_u = 0; - car_u->ent_u = car_u->ext_u = egg_u; - car_u->dep_w = 1; - } - // enqueue at driver exit (front of the line) - // - else { - egg_u->nex_u = car_u->ext_u; - egg_u->pre_u = 0; - - car_u->ext_u->pre_u = egg_u; - car_u->ext_u = egg_u; - car_u->dep_w++; - } - - u3_pier_spin(car_u->pir_u); - - return egg_u; -} - -/* u3_auto_peer(): subscribe to updates. -*/ -void -u3_auto_peer(u3_ovum* egg_u, - void* ptr_v, - u3_ovum_peer news_f, - u3_ovum_bail bail_f) -{ - egg_u->ptr_v = ptr_v; - egg_u->cb_u.news_f = news_f; - egg_u->cb_u.bail_f = bail_f; -} - -/* u3_auto_bail_slog(): print a bail notification. -*/ -void -u3_auto_bail_slog(u3_ovum* egg_u, u3_noun lud) -{ - c3_c* car_c = u3r_string(egg_u->car_u->nam_m); - u3_noun dul = lud; - c3_w len_w = 1; - - while ( u3_nul != dul ) { - u3l_log("%s: bail %u", car_c, len_w++); - u3_pier_punt_goof(car_c, u3k(u3h(dul))); - - dul = u3t(dul); - } - - u3_pier_punt_ovum(car_c, u3k(egg_u->wir), u3k(u3h(egg_u->cad))); - - u3z(lud); - c3_free(car_c); -} - -/* u3_auto_bail(): notify driver that [egg_u] crashed. -*/ -void -u3_auto_bail(u3_ovum* egg_u, u3_noun lud) -{ - // optional - // - if ( egg_u->cb_u.bail_f ) { - c3_l cod_l = u3a_lush(egg_u->car_u->nam_m); - egg_u->cb_u.bail_f(egg_u, lud); - u3a_lop(cod_l); - } - else { - u3_auto_bail_slog(egg_u, lud); - u3_ovum_free(egg_u); - } -} - -/* _auto_news(): notify driver of ovum status -*/ -static void -_auto_news(u3_ovum* egg_u, u3_ovum_news new_e) -{ - // optional - // - if ( egg_u->cb_u.news_f ) { - c3_l cod_l = u3a_lush(egg_u->car_u->nam_m); - egg_u->cb_u.news_f(egg_u, new_e); - u3a_lop(cod_l); - } -} - -/* u3_auto_done(): notify driver of [egg_u] completion. -*/ -void -u3_auto_done(u3_ovum* egg_u) -{ - _auto_news(egg_u, u3_ovum_done); - u3_ovum_free(egg_u); -} - -/* u3_auto_work(): notify driver of [egg_u] commencement. -*/ -void -u3_auto_work(u3_ovum* egg_u) -{ - _auto_news(egg_u, u3_ovum_work); -} - -/* u3_auto_drop(): dequeue and dispose an ovum. -*/ -void -u3_auto_drop(u3_auto* car_u, u3_ovum* egg_u) -{ - { - c3_assert( egg_u->car_u ); - - // the previous ovum (or [ext_u]) will point to our next ovum - // - if ( !egg_u->pre_u ) { - egg_u->car_u->ext_u = egg_u->nex_u; - } - else { - egg_u->pre_u->nex_u = egg_u->nex_u; - } - - // the next ovum (or [ent_u]) will point to our previous ovum - // - if ( !egg_u->nex_u ) { - egg_u->car_u->ent_u = egg_u->pre_u; - } - else { - egg_u->nex_u->pre_u = egg_u->pre_u; - } - - egg_u->car_u->dep_w--; - - egg_u->nex_u = egg_u->pre_u = 0; - } - - // notify driver if not self-caused - // - if ( egg_u->car_u && ( car_u != egg_u->car_u ) ) { - _auto_news(egg_u, u3_ovum_drop); - } - - u3_ovum_free(egg_u); -} - -/* u3_auto_next(): select an ovum, dequeue and construct. -*/ -u3_ovum* -u3_auto_next(u3_auto* car_u, u3_noun* ovo) -{ - while ( car_u ) { - if ( !car_u->ext_u ) { - car_u = car_u->nex_u; - continue; - } - else { - u3_ovum* egg_u = car_u->ext_u; - - c3_assert( !egg_u->pre_u ); - - if ( egg_u->nex_u ) { - egg_u->nex_u->pre_u = 0; - car_u->ext_u = egg_u->nex_u; - car_u->dep_w--; - } - else { - car_u->ent_u = car_u->ext_u = 0; - car_u->dep_w = 0; - } - - egg_u->nex_u = 0; - - u3_auto_work(egg_u); - - *ovo = u3nc(u3nc(u3k(egg_u->tar), u3k(egg_u->wir)), - u3k(egg_u->cad)); - - return egg_u; - } - } - - return 0; -} - -/* _auto_kick_lost(): print details of unroutable effect. RETAIN -*/ -static void -_auto_kick_lost(u3_noun pax, u3_noun fav) -{ - u3_noun tox = u3do("spat", u3k(pax)); - c3_c* tag_c = u3r_string(u3h(fav)); - c3_c* pax_c = u3r_string(tox); - - u3l_log("kick: lost %%%s on %s", tag_c, pax_c); - - c3_free(pax_c); - c3_free(tag_c); - u3z(tox); -} - -/* _auto_kick(): kick with leak label. -*/ -static c3_o -_auto_kick(u3_auto* car_u, u3_noun pax, u3_noun fav) -{ - c3_l cod_l = u3a_lush(car_u->nam_m); - c3_o kik_o = car_u->io.kick_f(car_u, pax, fav); - u3a_lop(cod_l); - return kik_o; -} - -/* u3_auto_kick(): route effects to a linked driver. RETAIN -*/ -void -u3_auto_kick(u3_auto* car_u, u3_noun act) -{ - u3_auto* rac_u = car_u; - u3_noun fec, pax, wir, cad; - - while ( u3_nul != act ) { - fec = u3h(act); - u3x_cell(fec, &pax, &cad); - - // XX temporary backwards compatibility, remove - // - if ( c3n == u3r_p(pax, u3_blip, &wir) ) { - wir = pax; - } - - while ( c3n == _auto_kick(car_u, u3k(wir), u3k(cad)) ) { - if ( car_u->nex_u ) { - car_u = car_u->nex_u; - continue; - } - else { - _auto_kick_lost(wir, cad); - break; - } - } - - car_u = rac_u; - act = u3t(act); - } -} - -/* u3_auto_live(): check if all drivers are live. -*/ -c3_o -u3_auto_live(u3_auto* car_u) -{ - while ( car_u ) { - if ( c3n == car_u->liv_o ) { - return c3n; - } - - car_u = car_u->nex_u; - } - - return c3y; -} - -/* u3_auto_talk(): start all drivers. -*/ -void -u3_auto_talk(u3_auto* car_u) -{ - c3_l cod_l; - - while ( car_u ) { - cod_l = u3a_lush(car_u->nam_m); - car_u->io.talk_f(car_u); - u3a_lop(cod_l); - car_u = car_u->nex_u; - } -} - -/* u3_auto_exit(): close all drivers. -*/ -void -u3_auto_exit(u3_auto* car_u) -{ - u3_auto* nex_u; - c3_l cod_l; - - while ( car_u ) { - nex_u = car_u->nex_u; - - { - u3_ovum *egg_u = car_u->ext_u; - u3_ovum *xen_u; - - while ( egg_u ) { - xen_u = egg_u->nex_u; - u3_ovum_free(egg_u); - egg_u = xen_u; - } - } - - cod_l = u3a_lush(car_u->nam_m); - car_u->io.exit_f(car_u); - u3a_lop(cod_l); - - car_u = nex_u; - } -} - -/* u3_auto_info(): status info as a (list mass), all drivers. -*/ -u3_noun -u3_auto_info(u3_auto* car_u) -{ - u3_noun lit = u3_nul; - - while ( car_u ) { - if ( car_u->io.info_f ) { - lit = u3nc(u3_pier_mass(car_u->nam_m, car_u->io.info_f(car_u)), lit); - } - car_u = car_u->nex_u; - } - return u3kb_flop(lit); -} - -/* u3_auto_slog(): print status info. -*/ -void -u3_auto_slog(u3_auto* car_u) -{ - u3_auto* nex_u; - - u3l_log(" drivers:"); - - while ( car_u ) { - nex_u = car_u->nex_u; - - u3l_log(" %.*s: live=%s, queue=%u", - u3r_met(3, car_u->nam_m), - (c3_c*)&car_u->nam_m, - ( c3y == car_u->liv_o ) ? "&" : "|", - car_u->dep_w); - - // XX details - // - if ( car_u->io.slog_f ) { - c3_l cod_l = u3a_lush(car_u->nam_m); - car_u->io.slog_f(car_u); - u3a_lop(cod_l); - } - - car_u = nex_u; - } -} - -/* _auto_link(): validate and link initalized [car_u] -*/ -static u3_auto* -_auto_link(u3_auto* car_u, u3_pier* pir_u, u3_auto* nex_u) -{ - // skip null drivers - // - if ( !car_u ) { - return nex_u; - } - - // assert that io callbacks are present (info_f and slog_f are optional) - // - c3_assert( car_u->io.talk_f ); - c3_assert( car_u->io.kick_f ); - c3_assert( car_u->io.exit_f ); - - car_u->pir_u = pir_u; - car_u->nex_u = nex_u; - return car_u; -} - -/* u3_auto_init(): initialize all drivers. -*/ -u3_auto* -u3_auto_init(u3_pier* pir_u) -{ - u3_auto* car_u = 0; - - car_u = _auto_link(u3_hind_io_init(pir_u), pir_u, car_u); - car_u = _auto_link(u3_behn_io_init(pir_u), pir_u, car_u); - car_u = _auto_link(u3_conn_io_init(pir_u), pir_u, car_u); - car_u = _auto_link(u3_ames_io_init(pir_u), pir_u, car_u); - car_u = _auto_link(u3_http_io_init(pir_u), pir_u, car_u); - car_u = _auto_link(u3_cttp_io_init(pir_u), pir_u, car_u); - car_u = _auto_link(u3_unix_io_init(pir_u), pir_u, car_u); - car_u = _auto_link(u3_term_io_init(pir_u), pir_u, car_u); - car_u = _auto_link(u3_fore_io_init(pir_u), pir_u, car_u); - - return car_u; -} diff --git a/pkg/urbit/vere/dawn.c b/pkg/urbit/vere/dawn.c deleted file mode 100644 index 195d5ccac..000000000 --- a/pkg/urbit/vere/dawn.c +++ /dev/null @@ -1,491 +0,0 @@ -/* vere/dawn.c -** -** ethereum-integrated pre-boot validation -*/ -#include "all.h" -#include "vere/vere.h" -#include -#include - -/* _dawn_oct_to_buf(): +octs to uv_buf_t -*/ -static uv_buf_t -_dawn_oct_to_buf(u3_noun oct) -{ - if ( c3n == u3a_is_cat(u3h(oct)) ) { - exit(1); - } - - c3_w len_w = u3h(oct); - c3_y* buf_y = c3_malloc(1 + len_w); - buf_y[len_w] = 0; - - u3r_bytes(0, len_w, buf_y, u3t(oct)); - - u3z(oct); - return uv_buf_init((void*)buf_y, len_w); -} - -/* _dawn_buf_to_oct(): uv_buf_t to +octs -*/ -static u3_noun -_dawn_buf_to_oct(uv_buf_t buf_u) -{ - u3_noun len = u3i_words(1, (c3_w*)&buf_u.len); - - if ( c3n == u3a_is_cat(len) ) { - exit(1); - } - - return u3nc(len, u3i_bytes(buf_u.len, (const c3_y*)buf_u.base)); -} - - -/* _dawn_curl_alloc(): allocate a response buffer for curl -*/ -static size_t -_dawn_curl_alloc(void* dat_v, size_t uni_t, size_t mem_t, void* buf_v) -{ - uv_buf_t* buf_u = buf_v; - - size_t siz_t = uni_t * mem_t; - buf_u->base = c3_realloc(buf_u->base, 1 + siz_t + buf_u->len); - - memcpy(buf_u->base + buf_u->len, dat_v, siz_t); - buf_u->len += siz_t; - buf_u->base[buf_u->len] = 0; - - return siz_t; -} - -/* _dawn_post_json(): POST JSON to url_c -*/ -static uv_buf_t -_dawn_post_json(c3_c* url_c, uv_buf_t lod_u) -{ - CURL *curl; - CURLcode result; - long cod_l; - struct curl_slist* hed_u = 0; - - uv_buf_t buf_u = uv_buf_init(c3_malloc(1), 0); - - if ( !(curl = curl_easy_init()) ) { - u3l_log("failed to initialize libcurl"); - exit(1); - } - - hed_u = curl_slist_append(hed_u, "Accept: application/json"); - hed_u = curl_slist_append(hed_u, "Content-Type: application/json"); - hed_u = curl_slist_append(hed_u, "charsets: utf-8"); - - // XX require TLS, pin default cert? - // - u3K.ssl_curl_f(curl); - curl_easy_setopt(curl, CURLOPT_URL, url_c); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _dawn_curl_alloc); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&buf_u); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hed_u); - - // note: must be terminated! - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, lod_u.base); - - result = curl_easy_perform(curl); - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &cod_l); - - // XX retry? - if ( CURLE_OK != result ) { - u3l_log("failed to fetch %s: %s", - url_c, curl_easy_strerror(result)); - exit(1); - } - if ( 300 <= cod_l ) { - u3l_log("error fetching %s: HTTP %ld", url_c, cod_l); - exit(1); - } - - curl_easy_cleanup(curl); - curl_slist_free_all(hed_u); - - return buf_u; -} - -/* _dawn_get_jam(): GET a jammed noun from url_c -*/ -static u3_noun -_dawn_get_jam(c3_c* url_c) -{ - CURL *curl; - CURLcode result; - long cod_l; - - uv_buf_t buf_u = uv_buf_init(c3_malloc(1), 0); - - if ( !(curl = curl_easy_init()) ) { - u3l_log("failed to initialize libcurl"); - exit(1); - } - - // XX require TLS, pin default cert? - // - u3K.ssl_curl_f(curl); - curl_easy_setopt(curl, CURLOPT_URL, url_c); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _dawn_curl_alloc); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&buf_u); - - result = curl_easy_perform(curl); - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &cod_l); - - // XX retry? - if ( CURLE_OK != result ) { - u3l_log("failed to fetch %s: %s", - url_c, curl_easy_strerror(result)); - exit(1); - } - if ( 300 <= cod_l ) { - u3l_log("error fetching %s: HTTP %ld", url_c, cod_l); - exit(1); - } - - curl_easy_cleanup(curl); - - // throw away the length from the octs - // - u3_noun octs = _dawn_buf_to_oct(buf_u); - u3_noun jammed = u3k(u3t(octs)); - u3z(octs); - - c3_free(buf_u.base); - - return u3ke_cue(jammed); -} - -/* _dawn_eth_rpc(): ethereum JSON RPC with request/response as +octs -*/ -static u3_noun -_dawn_eth_rpc(c3_c* url_c, u3_noun oct) -{ - uv_buf_t buf_u = _dawn_post_json(url_c, _dawn_oct_to_buf(oct)); - u3_noun pro = _dawn_buf_to_oct(buf_u); - - c3_free(buf_u.base); - - return pro; -} - -/* _dawn_fail(): pre-boot validation failed -*/ -static void -_dawn_fail(u3_noun who, u3_noun rac, u3_noun sas) -{ - u3_noun how = u3dc("scot", 'p', u3k(who)); - c3_c* how_c = u3r_string(u3k(how)); - - c3_c* rac_c; - - switch (rac) { - default: c3_assert(0); - case c3__czar: { - rac_c = "galaxy"; - break; - } - case c3__king: { - rac_c = "star"; - break; - } - case c3__duke: { - rac_c = "planet"; - break; - } - case c3__earl: { - rac_c = "moon"; - break; - } - case c3__pawn: { - rac_c = "comet"; - break; - } - } - - u3l_log("boot: invalid keys for %s '%s'", rac_c, how_c); - - // XX deconstruct sas, print helpful error messages - while ( u3_nul != sas ) { - u3m_p("pre-boot error", u3h(sas)); - sas = u3t(sas); - } - - u3z(how); - c3_free(how_c); - exit(1); -} - -/* _dawn_need_unit(): produce a value or print error and exit -*/ -static u3_noun -_dawn_need_unit(u3_noun nit, c3_c* msg_c) -{ - if ( u3_nul == nit ) { - u3l_log("%s", msg_c); - exit(1); - } - else { - u3_noun pro = u3k(u3t(nit)); - u3z(nit); - return pro; - } -} - -/* _dawn_turf(): override contract domains with -H -*/ -static u3_noun -_dawn_turf(c3_c* dns_c) -{ - u3_noun tuf; - - u3_noun par = u3v_wish("thos:de-purl:html"); - u3_noun dns = u3i_string(dns_c); - u3_noun rul = u3dc("rush", u3k(dns), u3k(par)); - - if ( (u3_nul == rul) || (c3n == u3h(u3t(rul))) ) { - u3l_log("boot: invalid domain specified with -H %s", dns_c); - exit(1); - } - else { - u3l_log("boot: overriding network domains with %s", dns_c); - u3_noun dom = u3t(u3t(rul)); - tuf = u3nc(u3k(dom), u3_nul); - } - - u3z(par); u3z(dns); u3z(rul); - - return tuf; -} - -/* _dawn_sponsor(): retrieve sponsor from point -*/ -static u3_noun -_dawn_sponsor(u3_noun who, u3_noun rac, u3_noun pot) -{ - u3_noun uni = u3dc("sponsor:dawn", u3k(who), u3k(pot)); - - if ( c3n == u3h(uni) ) { - _dawn_fail(who, rac, u3nc(u3t(uni), u3_nul)); - return u3_none; - } - - u3_noun pos = u3k(u3t(uni)); - - u3z(who); u3z(rac); u3z(pot); u3z(uni); - - return pos; -} - -/* u3_dawn_vent(): validated boot event -*/ -u3_noun -u3_dawn_vent(u3_noun ship, u3_noun feed) -{ - u3_noun sed, pos, pon, zar, tuf; - - u3_noun rank = u3do("clan:title", u3k(ship)); - - c3_c* url_c = ( 0 != u3_Host.ops_u.eth_c ) ? - u3_Host.ops_u.eth_c : - "https://roller.urbit.org/v1/azimuth"; - - { - // +point:azimuth: on-chain state - // - u3_noun pot; - - if ( c3__pawn == rank ) { - // irrelevant, just bunt +point - // - pot = u3v_wish("*point:azimuth"); - } - else if ( c3__earl == rank ) { - pot = u3v_wish("*point:azimuth"); - } - else { - u3l_log("boot: retrieving %s's public keys", - u3_Host.ops_u.who_c); - - { - u3_noun oct = u3do("point:give:dawn", u3k(ship)); - u3_noun luh = _dawn_eth_rpc(url_c, u3k(oct)); - - pot = _dawn_need_unit(u3dc("point:take:dawn", u3k(ship), u3k(luh)), - "boot: failed to retrieve public keys"); - u3z(oct); u3z(luh); - } - } - - // +live:dawn: network state - // XX actually make request - // - u3_noun liv = u3_nul; - // u3_noun liv = _dawn_get_json(parent, /some/url) - - u3l_log("boot: verifying keys"); - - // (each seed (lest error=@tas)) - // - sed = u3dq("veri:dawn", u3k(ship), u3k(feed), u3k(pot), u3k(liv)); - - if ( c3n == u3h(sed) ) { - // bails, won't return - _dawn_fail(ship, rank, u3t(sed)); - return u3_none; - } - - u3l_log("boot: getting sponsor"); - pos = _dawn_sponsor(u3k(ship), u3k(rank), u3k(pot)); - u3z(pot); u3z(liv); - } - - - // (map ship [=life =pass]): galaxy table - // - { - u3l_log("boot: retrieving galaxy table"); - - u3_noun oct = u3v_wish("czar:give:dawn"); - u3_noun raz = _dawn_eth_rpc(url_c, u3k(oct)); - - zar = _dawn_need_unit(u3do("czar:take:dawn", u3k(raz)), - "boot: failed to retrieve galaxy table"); - u3z(oct); u3z(raz); - } - - // (list turf): ames domains - // - if ( 0 != u3_Host.ops_u.dns_c ) { - tuf = _dawn_turf(u3_Host.ops_u.dns_c); - } - else { - u3l_log("boot: retrieving network domains"); - - u3_noun oct = u3v_wish("turf:give:dawn"); - u3_noun fut = _dawn_eth_rpc(url_c, u3k(oct)); - - tuf = _dawn_need_unit(u3do("turf:take:dawn", u3k(fut)), - "boot: failed to retrieve network domains"); - u3z(oct); u3z(fut); - } - - pon = u3_nul; - while (c3__czar != rank) { - u3_noun son; - // print message - // - { - u3_noun who = u3dc("scot", 'p', u3k(pos)); - c3_c* who_c = u3r_string(who); - u3l_log("boot: retrieving keys for sponsor %s", who_c); - u3z(who); - c3_free(who_c); - } - - // retrieve +point:azimuth of pos (sponsor of ship) - // - { - u3_noun oct = u3do("point:give:dawn", u3k(pos)); - u3_noun luh = _dawn_eth_rpc(url_c, u3k(oct)); - - son = _dawn_need_unit(u3dc("point:take:dawn", u3k(pos), u3k(luh)), - "boot: failed to retrieve sponsor keys"); - // append to sponsor chain list - // - pon = u3nc(u3nc(u3k(pos), u3k(son)), pon); - u3z(oct); u3z(luh); - } - - // find next sponsor - // - u3z(ship); u3z(rank); - ship = pos; - rank = u3do("clan:title", u3k(ship)); - pos = _dawn_sponsor(u3k(ship), u3k(rank), u3k(son)); - - u3z(son); - } - - // [%dawn seed sponsors galaxies domains block eth-url snap] - // - //NOTE blocknum of 0 is fine because jael ignores it. - // should probably be removed from dawn event. - u3_noun ven = u3nc(c3__dawn, - u3nq(u3k(u3t(sed)), pon, zar, u3nt(tuf, 0, u3_nul))); - - u3z(sed); u3z(rank); u3z(pos); u3z(ship); u3z(feed); - - return ven; -} - -/* _dawn_come(): mine a comet under a list of stars -*/ -static u3_noun -_dawn_come(u3_noun stars) -{ - u3_noun seed; - { - c3_w eny_w[16]; - u3_noun eny; - - c3_rand(eny_w); - eny = u3i_words(16, eny_w); - - u3l_log("boot: mining a comet. May take up to an hour."); - u3l_log("If you want to boot faster, get an Urbit identity."); - - seed = u3dc("come:dawn", u3k(stars), u3k(eny)); - u3z(eny); - } - - { - u3_noun who = u3dc("scot", 'p', u3k(u3h(seed))); - c3_c* who_c = u3r_string(who); - - u3l_log("boot: found comet %s", who_c); - - // enable to print and save comet private key for future reuse - // -#if 0 - { - u3_noun key = u3dc("scot", c3__uw, u3qe_jam(seed)); - c3_c* key_c = u3r_string(key); - - u3l_log("boot: comet private key\n %s", key_c); - - { - c3_c pat_c[64]; - snprintf(pat_c, 64, "%s.key", who_c + 1); - - FILE* fil_u = c3_fopen(pat_c, "w"); - fprintf(fil_u, "%s\n", key_c); - fclose(fil_u); - } - - c3_free(key_c); - u3z(key); - } -#endif - - c3_free(who_c); - u3z(who); - } - - u3z(stars); - - return seed; -} - -/* u3_dawn_come(): mine a comet under a list of stars we download -*/ -u3_noun -u3_dawn_come() -{ - return _dawn_come( - _dawn_get_jam("https://bootstrap.urbit.org/comet-stars.jam")); -} diff --git a/pkg/urbit/vere/db/lmdb.c b/pkg/urbit/vere/db/lmdb.c deleted file mode 100644 index 443f11525..000000000 --- a/pkg/urbit/vere/db/lmdb.c +++ /dev/null @@ -1,527 +0,0 @@ -/* vere/db/lmdb.c -*/ -#include "c/portable.h" -#include "c/types.h" -#include "c/defs.h" -#include "vere/db/lmdb.h" -#include - -/* mdb_logerror(): writes an error message and lmdb error code to f. -*/ -void mdb_logerror(FILE* f, int err, const char* fmt, ...); - -/* mdb_get_filesize(): gets the size of a lmdb database file on disk. -*/ -intmax_t mdb_get_filesize(mdb_filehandle_t han_u); - -// lmdb api wrapper -// -// this module implements a simple persistence api on top of lmdb. -// outside of its use of c3 type definitions, this module has no -// dependence on anything u3, or on any library besides lmdb itself. -// -// urbit requires very little from a persist store -- it merely -// needs to store variable-length buffers in: -// -// - a metadata store with c3_c (unsigned char) keys -// - an event store with contiguous c3_d (uint64_t) keys -// -// supported operations are as follows -// -// - open/close an environment -// - read/save metadata -// - read the first and last event numbers -// - read/save ranges of events -// - -/* u3_lmdb_init(): open lmdb at [pax_c], mmap up to [siz_i]. -*/ -MDB_env* -u3_lmdb_init(const c3_c* pax_c, size_t siz_i) -{ - MDB_env* env_u; - c3_w ret_w; - - if ( (ret_w = mdb_env_create(&env_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: init fail"); - return 0; - } - - // Our databases have two tables: META and EVENTS - // - if ( (ret_w = mdb_env_set_maxdbs(env_u, 2)) ) { - mdb_logerror(stderr, ret_w, "lmdb: failed to set number of databases"); - // XX dispose env_u - // - return 0; - } - - if ( (ret_w = mdb_env_set_mapsize(env_u, siz_i)) ) { - mdb_logerror(stderr, ret_w, "lmdb: failed to set database size"); - // XX dispose env_u - // - return 0; - } - - { -# if defined(U3_OS_no_ubc) - c3_w ops_w = MDB_WRITEMAP; -# else - c3_w ops_w = 0; -# endif - - if ( (ret_w = mdb_env_open(env_u, pax_c, ops_w, 0664)) ) { - mdb_logerror(stderr, ret_w, "lmdb: failed to open event log"); - // XX dispose env_u - // - return 0; - } - } - - return env_u; -} - -/* u3_lmdb_exit(): close lmdb. -*/ -void -u3_lmdb_exit(MDB_env* env_u) -{ - mdb_env_close(env_u); -} - -/* u3_lmdb_stat(): print env stats. -*/ -void -u3_lmdb_stat(MDB_env* env_u, FILE* fil_u) -{ - size_t siz_i; - - fprintf(fil_u, "lmdb info:\n"); - - { - MDB_stat mst_u; - MDB_envinfo mei_u; - - (void)mdb_env_stat(env_u, &mst_u); - (void)mdb_env_info(env_u, &mei_u); - - fprintf(fil_u, " map size: %zu\n", mei_u.me_mapsize); - fprintf(fil_u, " page size: %u\n", mst_u.ms_psize); - fprintf(fil_u, " max pages: %zu\n", mei_u.me_mapsize / mst_u.ms_psize); - fprintf(fil_u, " number of pages used: %zu\n", mei_u.me_last_pgno+1); - fprintf(fil_u, " last transaction ID: %zu\n", mei_u.me_last_txnid); - fprintf(fil_u, " max readers: %u\n", mei_u.me_maxreaders); - fprintf(fil_u, " number of readers used: %u\n", mei_u.me_numreaders); - - siz_i = mst_u.ms_psize * (mei_u.me_last_pgno+1); - } - - { - mdb_filehandle_t han_u; - mdb_env_get_fd(env_u, &han_u); - - intmax_t dis_i = mdb_get_filesize(han_u); - - if ( siz_i != dis_i ) { - fprintf(fil_u, "MISMATCH:\n"); - } - - fprintf(fil_u, " file size (page): %zu\n", siz_i); - fprintf(fil_u, " file size (stat): %jd\n", dis_i); - } -} - -/* u3_lmdb_gulf(): read first and last event numbers. -*/ -c3_o -u3_lmdb_gulf(MDB_env* env_u, c3_d* low_d, c3_d* hig_d) -{ - MDB_txn* txn_u; - MDB_dbi mdb_u; - c3_w ret_w; - - // create a read-only transaction. - // - // XX why no MDB_RDONLY? - // - if ( (ret_w = mdb_txn_begin(env_u, 0, 0, &txn_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: gulf: txn_begin fail"); - return c3n; - } - - // open the database in the transaction - // - { - c3_w ops_w = MDB_CREATE | MDB_INTEGERKEY; - - if ( (ret_w = mdb_dbi_open(txn_u, "EVENTS", ops_w, &mdb_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: gulf: dbi_open fail"); - // XX confirm - // - mdb_txn_abort(txn_u); - return c3n; - } - } - - { - MDB_cursor* cur_u; - MDB_val key_u; - MDB_val val_u; - c3_d fir_d, las_d; - - // creates a cursor to point to the last event - // - if ( (ret_w = mdb_cursor_open(txn_u, mdb_u, &cur_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: gulf: cursor_open fail"); - // XX confirm - // - mdb_txn_abort(txn_u); - return c3n; - } - - // read with the cursor from the start of the database - // - ret_w = mdb_cursor_get(cur_u, &key_u, &val_u, MDB_FIRST); - - if ( MDB_NOTFOUND == ret_w ) { - *low_d = 0; - *hig_d = 0; - mdb_cursor_close(cur_u); - mdb_txn_abort(txn_u); - return c3y; - } - else if ( ret_w ) { - mdb_logerror(stderr, ret_w, "lmdb: gulf: head fail"); - mdb_cursor_close(cur_u); - mdb_txn_abort(txn_u); - return c3n; - } - else { - fir_d = *(c3_d*)key_u.mv_data; - } - - // read with the cursor from the end of the database - // - ret_w = mdb_cursor_get(cur_u, &key_u, &val_u, MDB_LAST); - - if ( !ret_w ) { - las_d = *(c3_d*)key_u.mv_data; - } - - // clean up unconditionally, we're done - // - mdb_cursor_close(cur_u); - mdb_txn_abort(txn_u); - - if ( ret_w ) { - mdb_logerror(stderr, ret_w, "lmdb: gulf: last fail"); - return c3n; - } - else { - *low_d = fir_d; - *hig_d = las_d; - return c3y; - } - } -} - -/* u3_lmdb_read(): read [len_d] events starting at [eve_d]. -*/ -c3_o -u3_lmdb_read(MDB_env* env_u, - void* ptr_v, - c3_d eve_d, - c3_d len_d, - c3_o (*read_f)(void*, c3_d, size_t, void*)) -{ - MDB_txn* txn_u; - MDB_dbi mdb_u; - c3_w ret_w; - - // create a read-only transaction. - // - if ( (ret_w = mdb_txn_begin(env_u, 0, MDB_RDONLY, &txn_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: read txn_begin fail"); - return c3n; - } - - // open the database in the transaction - // - { - c3_w ops_w = MDB_CREATE | MDB_INTEGERKEY; - - if ( (ret_w = mdb_dbi_open(txn_u, "EVENTS", ops_w, &mdb_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: read: dbi_open fail"); - // XX confirm - // - mdb_txn_abort(txn_u); - return c3n; - } - } - - - { - MDB_cursor* cur_u; - MDB_val val_u; - // set the initial key to [eve_d] - // - MDB_val key_u = { .mv_size = sizeof(c3_d), .mv_data = &eve_d }; - - // creates a cursor to iterate over keys starting at [eve_d] - // - if ( (ret_w = mdb_cursor_open(txn_u, mdb_u, &cur_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: read: cursor_open fail"); - // XX confirm - // - mdb_txn_abort(txn_u); - return c3n; - } - - // set the cursor to the position of [eve_d] - // - if ( (ret_w = mdb_cursor_get(cur_u, &key_u, &val_u, MDB_SET_KEY)) ) { - mdb_logerror(stderr, ret_w, "lmdb: read: initial cursor_get failed at %" PRIu64, eve_d); - mdb_cursor_close(cur_u); - // XX confirm - // - mdb_txn_abort(txn_u); - return c3n; - } - - // load up to [len_d] events, iterating forward across the cursor. - // - { - c3_o ret_o = c3y; - c3_d i_d; - - for ( i_d = 0; (ret_w != MDB_NOTFOUND) && (i_d < len_d); ++i_d) { - c3_d cur_d = (eve_d + i_d); - if ( sizeof(c3_d) != key_u.mv_size ) { - fprintf(stderr, "lmdb: read: invalid key size\r\n"); - ret_o = c3n; - break; - } - - // sanity check: ensure contiguous event numbers - // - if ( *(c3_d*)key_u.mv_data != cur_d ) { - fprintf(stderr, "lmdb: read gap: expected %" PRIu64 - ", received %" PRIu64 "\r\n", - cur_d, - *(c3_d*)key_u.mv_data); - ret_o = c3n; - break; - } - - // invoke read callback with [val_u] - // - if ( c3n == read_f(ptr_v, cur_d, val_u.mv_size, val_u.mv_data) ) { - ret_o = c3n; - break; - } - - // read the next event from the cursor - // - if ( (ret_w = mdb_cursor_get(cur_u, &key_u, &val_u, MDB_NEXT)) - && (MDB_NOTFOUND != ret_w) ) - { - mdb_logerror(stderr, ret_w, "lmdb: read: error"); - ret_o = c3n; - break; - } - } - - mdb_cursor_close(cur_u); - - // read-only transactions are aborted when complete - // - mdb_txn_abort(txn_u); - - return ret_o; - } - } -} - -/* u3_lmdb_save(): save [len_d] events starting at [eve_d]. -*/ -c3_o -u3_lmdb_save(MDB_env* env_u, - c3_d eve_d, // first event - c3_d len_d, // number of events - void** byt_p, // array of bytes - size_t* siz_i) // array of lengths -{ - MDB_txn* txn_u; - MDB_dbi mdb_u; - c3_w ret_w; - - // create a write transaction - // - if ( (ret_w = mdb_txn_begin(env_u, 0, 0, &txn_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: write: txn_begin fail"); - return c3n; - } - - // opens the database in the transaction - // - { - c3_w ops_w = MDB_CREATE | MDB_INTEGERKEY; - - if ( (ret_w = mdb_dbi_open(txn_u, "EVENTS", ops_w, &mdb_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: write: dbi_open fail"); - mdb_txn_abort(txn_u); - return c3n; - } - } - - // write every event in the batch - // - { - c3_w ops_w = MDB_NOOVERWRITE; - c3_d las_d = (eve_d + len_d); - c3_d key_d, i_d; - - for ( i_d = 0; i_d < len_d; ++i_d) { - key_d = eve_d + i_d; - - { - MDB_val key_u = { .mv_size = sizeof(c3_d), .mv_data = &key_d }; - MDB_val val_u = { .mv_size = siz_i[i_d], .mv_data = byt_p[i_d] }; - - if ( (ret_w = mdb_put(txn_u, mdb_u, &key_u, &val_u, ops_w)) ) { - fprintf(stderr, "lmdb: write failed on event %" PRIu64 "\r\n", key_d); - mdb_txn_abort(txn_u); - return c3n; - } - } - } - } - - // commit transaction - // - if ( (ret_w = mdb_txn_commit(txn_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: write failed"); - return c3n; - } - - return c3y; -} - -/* u3_lmdb_read_meta(): read by string from the META db. -*/ -void -u3_lmdb_read_meta(MDB_env* env_u, - void* ptr_v, - const c3_c* key_c, - void (*read_f)(void*, size_t, void*)) -{ - MDB_txn* txn_u; - MDB_dbi mdb_u; - c3_w ret_w; - - // create a read transaction - // - if ( (ret_w = mdb_txn_begin(env_u, 0, MDB_RDONLY, &txn_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: meta read: txn_begin fail"); - return read_f(ptr_v, 0, 0); - } - - // open the database in the transaction - // - if ( (ret_w = mdb_dbi_open(txn_u, "META", 0, &mdb_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: meta read: dbi_open fail"); - mdb_txn_abort(txn_u); - return read_f(ptr_v, 0, 0); - } - - // read by string key, invoking callback with result - { - MDB_val key_u = { .mv_size = strlen(key_c), .mv_data = (void*)key_c }; - MDB_val val_u; - - if ( (ret_w = mdb_get(txn_u, mdb_u, &key_u, &val_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: read failed"); - mdb_txn_abort(txn_u); - return read_f(ptr_v, 0, 0); - } - else { - read_f(ptr_v, val_u.mv_size, val_u.mv_data); - - // read-only transactions are aborted when complete - // - mdb_txn_abort(txn_u); - } - } -} - -/* u3_lmdb_save_meta(): save by string into the META db. -*/ -c3_o -u3_lmdb_save_meta(MDB_env* env_u, - const c3_c* key_c, - size_t val_i, - void* val_p) -{ - MDB_txn* txn_u; - MDB_dbi mdb_u; - c3_w ret_w; - - // create a write transaction - // - if ( (ret_w = mdb_txn_begin(env_u, 0, 0, &txn_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: meta write: txn_begin fail"); - return c3n; - } - - // opens the database in the transaction - // - if ( (ret_w = mdb_dbi_open(txn_u, "META", MDB_CREATE, &mdb_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: meta write: dbi_open fail"); - mdb_txn_abort(txn_u); - return c3n; - } - - // put value by string key - // - { - MDB_val key_u = { .mv_size = strlen(key_c), .mv_data = (void*)key_c }; - MDB_val val_u = { .mv_size = val_i, .mv_data = val_p }; - - if ( (ret_w = mdb_put(txn_u, mdb_u, &key_u, &val_u, 0)) ) { - mdb_logerror(stderr, ret_w, "lmdb: write failed"); - mdb_txn_abort(txn_u); - return c3n; - } - } - - // commit txn - // - if ( (ret_w = mdb_txn_commit(txn_u)) ) { - mdb_logerror(stderr, ret_w, "lmdb: meta write: commit failed"); - return c3n; - } - - return c3y; -} - -#if !defined(U3_OS_mingw) -/* mdb_logerror(): writes an error message and lmdb error code to f. -*/ -void mdb_logerror(FILE* f, int err, const char* fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(f, fmt, ap); - va_end(ap); - fprintf(f, ": %s\r\n", mdb_strerror(err)); -} - -/* mdb_get_filesize(): gets the size of a lmdb database file on disk. -*/ -intmax_t mdb_get_filesize(mdb_filehandle_t han_u) -{ - struct stat sat_u; - fstat(han_u, &sat_u); - return (intmax_t)sat_u.st_size; -} -#endif diff --git a/pkg/urbit/vere/disk.c b/pkg/urbit/vere/disk.c deleted file mode 100644 index 817a424c1..000000000 --- a/pkg/urbit/vere/disk.c +++ /dev/null @@ -1,934 +0,0 @@ -/* vere/disk.c -*/ -#include "all.h" -#include "vere/vere.h" -#include - -struct _cd_read { - uv_timer_t tim_u; - c3_d eve_d; - c3_d len_d; - struct _u3_fact* ent_u; // queue entry - struct _u3_fact* ext_u; // queue exit - struct _u3_disk* log_u; -}; - -struct _cd_save { - c3_o ret_o; // result - c3_d eve_d; // first event - c3_d len_d; // number of events - c3_y** byt_y; // array of bytes - size_t* siz_i; // array of lengths - struct _u3_disk* log_u; -}; - -#undef VERBOSE_DISK -#undef DISK_TRACE_JAM -#undef DISK_TRACE_CUE - -static void -_disk_commit(u3_disk* log_u); - -/* _disk_free_save(): free write batch -*/ -static void -_disk_free_save(struct _cd_save* req_u) -{ - while ( req_u->len_d-- ) { - c3_free(req_u->byt_y[req_u->len_d]); - } - - c3_free(req_u->byt_y); - c3_free(req_u->siz_i); - c3_free(req_u); -} - -/* _disk_commit_done(): commit complete. - */ -static void -_disk_commit_done(struct _cd_save* req_u) -{ - u3_disk* log_u = req_u->log_u; - c3_d eve_d = req_u->eve_d; - c3_d len_d = req_u->len_d; - c3_o ret_o = req_u->ret_o; - - if ( c3n == ret_o ) { - log_u->cb_u.write_bail_f(log_u->cb_u.ptr_v, eve_d + (len_d - 1ULL)); - -#ifdef VERBOSE_DISK - if ( 1ULL == len_d ) { - fprintf(stderr, "disk: (%" PRIu64 "): commit: failed\r\n", eve_d); - } - else { - fprintf(stderr, "disk: (%" PRIu64 "-%" PRIu64 "): commit: failed\r\n", - eve_d, - eve_d + (len_d - 1ULL)); - } -#endif - } - else { - log_u->dun_d = eve_d + (len_d - 1ULL); - log_u->cb_u.write_done_f(log_u->cb_u.ptr_v, log_u->dun_d); - -#ifdef VERBOSE_DISK - if ( 1ULL == len_d ) { - fprintf(stderr, "disk: (%" PRIu64 "): commit: complete\r\n", eve_d); - } - else { - fprintf(stderr, "disk: (%" PRIu64 "-%" PRIu64 "): commit: complete\r\n", - eve_d, - eve_d + (len_d - 1ULL)); - } -#endif - } - - { - u3_fact* tac_u = log_u->put_u.ext_u; - - while ( tac_u && (tac_u->eve_d <= log_u->dun_d) ) { - log_u->put_u.ext_u = tac_u->nex_u; - u3_fact_free(tac_u); - tac_u = log_u->put_u.ext_u; - } - } - - if ( !log_u->put_u.ext_u ) { - log_u->put_u.ent_u = 0; - } - - _disk_free_save(req_u); - - _disk_commit(log_u); -} - -/* _disk_commit_after_cb(): on the main thread, finish write -*/ -static void -_disk_commit_after_cb(uv_work_t* ted_u, c3_i sas_i) -{ - struct _cd_save* req_u = ted_u->data; - - if ( UV_ECANCELED == sas_i ) { - _disk_free_save(req_u); - } - else { - ted_u->data = 0; - req_u->log_u->ted_o = c3n; - _disk_commit_done(req_u); - } -} - -/* _disk_commit_cb(): off the main thread, write event-batch. -*/ -static void -_disk_commit_cb(uv_work_t* ted_u) -{ - struct _cd_save* req_u = ted_u->data; - req_u->ret_o = u3_lmdb_save(req_u->log_u->mdb_u, - req_u->eve_d, - req_u->len_d, - (void**)req_u->byt_y, // XX safe? - req_u->siz_i); -} - -/* _disk_commit_start(): queue async event-batch write. -*/ -static void -_disk_commit_start(struct _cd_save* req_u) -{ - u3_disk* log_u = req_u->log_u; - - c3_assert( c3n == log_u->ted_o ); - log_u->ted_o = c3y; - log_u->ted_u.data = req_u; - - // queue asynchronous work to happen on another thread - // - uv_queue_work(u3L, &log_u->ted_u, _disk_commit_cb, - _disk_commit_after_cb); -} - -/* _disk_serialize_v1(): serialize events in format v1. -*/ -static c3_w -_disk_serialize_v1(u3_fact* tac_u, c3_y** out_y) -{ -#ifdef DISK_TRACE_JAM - u3t_event_trace("king disk jam", 'B'); -#endif - - { - u3_atom mat = u3qe_jam(tac_u->job); - c3_w len_w = u3r_met(3, mat); - c3_y* dat_y = c3_malloc(4 + len_w); - dat_y[0] = tac_u->mug_l & 0xff; - dat_y[1] = (tac_u->mug_l >> 8) & 0xff; - dat_y[2] = (tac_u->mug_l >> 16) & 0xff; - dat_y[3] = (tac_u->mug_l >> 24) & 0xff; - u3r_bytes(0, len_w, dat_y + 4, mat); - -#ifdef DISK_TRACE_JAM - u3t_event_trace("king disk jam", 'E'); -#endif - - u3z(mat); - - *out_y = dat_y; - return len_w + 4; - } -} - -/* _disk_batch(): create a write batch -*/ -static struct _cd_save* -_disk_batch(u3_disk* log_u, c3_d len_d) -{ - u3_fact* tac_u = log_u->put_u.ext_u; - - c3_assert( (1ULL + log_u->dun_d) == tac_u->eve_d ); - c3_assert( log_u->sen_d == log_u->put_u.ent_u->eve_d ); - - struct _cd_save* req_u = c3_malloc(sizeof(*req_u)); - req_u->log_u = log_u; - req_u->ret_o = c3n; - req_u->eve_d = tac_u->eve_d; - req_u->len_d = len_d; - req_u->byt_y = c3_malloc(len_d * sizeof(c3_y*)); - req_u->siz_i = c3_malloc(len_d * sizeof(size_t)); - - for ( c3_d i_d = 0ULL; i_d < len_d; ++i_d) { - c3_assert( (req_u->eve_d + i_d) == tac_u->eve_d ); - - req_u->siz_i[i_d] = _disk_serialize_v1(tac_u, &req_u->byt_y[i_d]); - - tac_u = tac_u->nex_u; - } - - return req_u; -} - -/* _disk_commit(): commit all available events, if idle. -*/ -static void -_disk_commit(u3_disk* log_u) -{ - if ( (c3n == log_u->ted_o) - && (log_u->sen_d > log_u->dun_d) ) - { - c3_d len_d = log_u->sen_d - log_u->dun_d; - struct _cd_save* req_u = _disk_batch(log_u, len_d); - -#ifdef VERBOSE_DISK - if ( 1ULL == len_d ) { - fprintf(stderr, "disk: (%" PRIu64 "): commit: request\r\n", - req_u->eve_d); - } - else { - fprintf(stderr, "disk: (%" PRIu64 "-%" PRIu64 "): commit: request\r\n", - req_u->eve_d, - (req_u->eve_d + len_d - 1ULL)); - } -#endif - - _disk_commit_start(req_u); - } -} - -/* u3_disk_plan(): enqueue completed event for persistence. -*/ -void -u3_disk_plan(u3_disk* log_u, u3_fact* tac_u) -{ - c3_assert( (1ULL + log_u->sen_d) == tac_u->eve_d ); - log_u->sen_d++; - - if ( !log_u->put_u.ent_u ) { - c3_assert( !log_u->put_u.ext_u ); - log_u->put_u.ent_u = log_u->put_u.ext_u = tac_u; - } - else { - log_u->put_u.ent_u->nex_u = tac_u; - log_u->put_u.ent_u = tac_u; - } - - _disk_commit(log_u); -} - -/* u3_disk_boot_plan(): enqueue boot sequence, without autocommit. -*/ -void -u3_disk_boot_plan(u3_disk* log_u, u3_noun job) -{ - // NB, boot mugs are 0 - // - u3_fact* tac_u = u3_fact_init(++log_u->sen_d, 0, job); - - if ( !log_u->put_u.ent_u ) { - c3_assert( !log_u->put_u.ext_u ); - c3_assert( 1ULL == log_u->sen_d ); - - log_u->put_u.ent_u = log_u->put_u.ext_u = tac_u; - } - else { - log_u->put_u.ent_u->nex_u = tac_u; - log_u->put_u.ent_u = tac_u; - } - -#ifdef VERBOSE_DISK - fprintf(stderr, "disk: (%" PRIu64 "): db boot plan\r\n", tac_u->eve_d); -#endif -} - -/* u3_disk_boot_save(): commit boot sequence. -*/ -void -u3_disk_boot_save(u3_disk* log_u) -{ - c3_assert( !log_u->dun_d ); - _disk_commit(log_u); -} - -static void -_disk_read_free(u3_read* red_u) -{ - // free facts (if the read failed) - // - { - u3_fact* tac_u = red_u->ext_u; - u3_fact* nex_u; - - while ( tac_u ) { - nex_u = tac_u->nex_u; - u3_fact_free(tac_u); - tac_u = nex_u; - } - } - - c3_free(red_u); -} - -/* _disk_read_close_cb(): -*/ -static void -_disk_read_close_cb(uv_handle_t* had_u) -{ - u3_read* red_u = had_u->data; - _disk_read_free(red_u); -} - -static void -_disk_read_close(u3_read* red_u) -{ - u3_disk* log_u = red_u->log_u; - - // unlink request - // - { - if ( red_u->pre_u ) { - red_u->pre_u->nex_u = red_u->nex_u; - } - else { - log_u->red_u = red_u->nex_u; - } - - if ( red_u->nex_u ) { - red_u->nex_u->pre_u = red_u->pre_u; - } - } - - uv_close(&red_u->had_u, _disk_read_close_cb); -} - -/* _disk_read_done_cb(): finalize read, invoke callback with response. -*/ -static void -_disk_read_done_cb(uv_timer_t* tim_u) -{ - u3_read* red_u = tim_u->data; - u3_disk* log_u = red_u->log_u; - u3_info pay_u = { .ent_u = red_u->ent_u, .ext_u = red_u->ext_u }; - - c3_assert( red_u->ent_u ); - c3_assert( red_u->ext_u ); - red_u->ent_u = 0; - red_u->ext_u = 0; - - log_u->cb_u.read_done_f(log_u->cb_u.ptr_v, pay_u); - _disk_read_close(red_u); -} - -/* _disk_read_one_cb(): lmdb read callback, invoked for each event in order -*/ -static c3_o -_disk_read_one_cb(void* ptr_v, c3_d eve_d, size_t val_i, void* val_p) -{ - u3_read* red_u = ptr_v; - u3_disk* log_u = red_u->log_u; - u3_fact* tac_u; - - if ( 4 >= val_i ) { - return c3n; - } - - { - u3_noun job; - c3_y* dat_y = val_p; - c3_l mug_l = dat_y[0] - ^ (dat_y[1] << 8) - ^ (dat_y[2] << 16) - ^ (dat_y[3] << 24); - -#ifdef DISK_TRACE_CUE - u3t_event_trace("king disk cue", 'B'); -#endif - - // XX u3m_soft? - // - job = u3ke_cue(u3i_bytes(val_i - 4, dat_y + 4)); - -#ifdef DISK_TRACE_CUE - u3t_event_trace("king disk cue", 'E'); -#endif - - tac_u = u3_fact_init(eve_d, mug_l, job); - } - - if ( !red_u->ent_u ) { - c3_assert( !red_u->ext_u ); - - c3_assert( red_u->eve_d == eve_d ); - red_u->ent_u = red_u->ext_u = tac_u; - } - else { - c3_assert( (1ULL + red_u->ent_u->eve_d) == eve_d ); - red_u->ent_u->nex_u = tac_u; - red_u->ent_u = tac_u; - } - - return c3y; -} - -/* _disk_read_start_cb(): the read from the db, trigger response -*/ -static void -_disk_read_start_cb(uv_timer_t* tim_u) -{ - u3_read* red_u = tim_u->data; - u3_disk* log_u = red_u->log_u; - - // read events synchronously - // - if ( c3n == u3_lmdb_read(log_u->mdb_u, - red_u, - red_u->eve_d, - red_u->len_d, - _disk_read_one_cb) ) - { - log_u->cb_u.read_bail_f(log_u->cb_u.ptr_v, red_u->eve_d); - _disk_read_close(red_u); - } - // finish the read asynchronously - // - else { - uv_timer_start(&red_u->tim_u, _disk_read_done_cb, 0, 0); - } -} - -/* u3_disk_read(): read [len_d] events starting at [eve_d]. -*/ -void -u3_disk_read(u3_disk* log_u, c3_d eve_d, c3_d len_d) -{ - u3_read* red_u = c3_malloc(sizeof(*red_u)); - red_u->log_u = log_u; - red_u->eve_d = eve_d; - red_u->len_d = len_d; - red_u->ent_u = red_u->ext_u = 0; - red_u->pre_u = 0; - red_u->nex_u = log_u->red_u; - - if ( log_u->red_u ) { - log_u->red_u->pre_u = red_u; - } - log_u->red_u = red_u; - - // perform the read asynchronously - // - uv_timer_init(u3L, &red_u->tim_u); - - red_u->tim_u.data = red_u; - uv_timer_start(&red_u->tim_u, _disk_read_start_cb, 0, 0); -} - -/* _disk_save_meta(): serialize atom, save as metadata at [key_c]. -*/ -static c3_o -_disk_save_meta(u3_disk* log_u, const c3_c* key_c, u3_atom dat) -{ - c3_w len_w = u3r_met(3, dat); - c3_y* byt_y = c3_malloc(len_w); - u3r_bytes(0, len_w, byt_y, dat); - - { - c3_o ret_o = u3_lmdb_save_meta(log_u->mdb_u, key_c, len_w, byt_y); - c3_free(byt_y); - return ret_o; - } -} - -/* u3_disk_save_meta(): save metadata. -*/ -c3_o -u3_disk_save_meta(u3_disk* log_u, - c3_d who_d[2], - c3_o fak_o, - c3_w lif_w) -{ - c3_assert( c3y == u3a_is_cat(lif_w) ); - - if ( (c3n == _disk_save_meta(log_u, "version", 1)) - || (c3n == _disk_save_meta(log_u, "who", u3i_chubs(2, who_d))) - || (c3n == _disk_save_meta(log_u, "fake", fak_o)) - || (c3n == _disk_save_meta(log_u, "life", lif_w)) ) - { - return c3n; - } - - return c3y; -} - -/* _disk_meta_read_cb(): copy [val_p] to atom [ptr_v] if present. -*/ -static void -_disk_meta_read_cb(void* ptr_v, size_t val_i, void* val_p) -{ - u3_weak* mat = ptr_v; - - if ( val_p ) { - *mat = u3i_bytes(val_i, val_p); - } -} - -/* _disk_read_meta(): read metadata at [key_c], deserialize. -*/ -static u3_weak -_disk_read_meta(u3_disk* log_u, const c3_c* key_c) -{ - u3_weak dat = u3_none; - u3_lmdb_read_meta(log_u->mdb_u, &dat, key_c, _disk_meta_read_cb); - return dat; -} - -/* u3_disk_read_meta(): read metadata. -*/ -c3_o -u3_disk_read_meta(u3_disk* log_u, - c3_d* who_d, - c3_o* fak_o, - c3_w* lif_w) -{ - u3_weak ver, who, fak, lif; - - if ( u3_none == (ver = _disk_read_meta(log_u, "version")) ) { - fprintf(stderr, "disk: read meta: no version\r\n"); - return c3n; - } - if ( u3_none == (who = _disk_read_meta(log_u, "who")) ) { - fprintf(stderr, "disk: read meta: no indentity\r\n"); - return c3n; - } - if ( u3_none == (fak = _disk_read_meta(log_u, "fake")) ) { - fprintf(stderr, "disk: read meta: no fake bit\r\n"); - return c3n; - } - if ( u3_none == (lif = _disk_read_meta(log_u, "life")) ) { - fprintf(stderr, "disk: read meta: no lifecycle length\r\n"); - return c3n; - } - - { - c3_o val_o = c3y; - - if ( 1 != ver ) { - fprintf(stderr, "disk: read meta: unknown version %u\r\n", ver); - val_o = c3n; - } - else if ( !((c3y == fak ) || (c3n == fak )) ) { - fprintf(stderr, "disk: read meta: invalid fake bit\r\n"); - val_o = c3n; - } - else if ( c3n == u3a_is_cat(lif) ) { - fprintf(stderr, "disk: read meta: invalid lifecycle length\r\n"); - val_o = c3n; - } - - if ( c3n == val_o ) { - u3z(ver); u3z(who); u3z(fak); u3z(lif); - return c3n; - } - } - - if ( who_d ) { - u3r_chubs(0, 2, who_d, who); - } - - if ( fak_o ) { - *fak_o = fak; - } - - if ( lif_w ) { - *lif_w = lif; - } - - u3z(who); - return c3y; -} - -/* _disk_lock(): lockfile path. -*/ -static c3_c* -_disk_lock(c3_c* pax_c) -{ - c3_w len_w = strlen(pax_c) + sizeof("/.vere.lock"); - c3_c* paf_c = c3_malloc(len_w); - c3_i wit_i; - - wit_i = snprintf(paf_c, len_w, "%s/.vere.lock", pax_c); - c3_assert(wit_i + 1 == len_w); - return paf_c; -} - -/* u3_disk_acquire(): acquire a lockfile, killing anything that holds it. -*/ -static void -u3_disk_acquire(c3_c* pax_c) -{ - c3_c* paf_c = _disk_lock(pax_c); - c3_w pid_w; - FILE* loq_u; - - if ( NULL != (loq_u = c3_fopen(paf_c, "r")) ) { - if ( 1 != fscanf(loq_u, "%" SCNu32, &pid_w) ) { - u3l_log("lockfile %s is corrupt!", paf_c); - kill(getpid(), SIGTERM); - sleep(1); c3_assert(0); - } - else if (pid_w != getpid()) { - c3_w i_w; - - int ret = kill(pid_w, SIGTERM); - - if ( -1 == ret && errno == EPERM ) { - u3l_log("disk: permission denied when trying to kill process %d!", pid_w); - kill(getpid(), SIGTERM); - sleep(1); c3_assert(0); - } - - if ( -1 != ret ) { - u3l_log("disk: stopping process %d, live in %s...", - pid_w, pax_c); - - for ( i_w = 0; i_w < 16; i_w++ ) { - sleep(1); - if ( -1 == kill(pid_w, SIGTERM) ) { - break; - } - } - if ( 16 == i_w ) { - for ( i_w = 0; i_w < 16; i_w++ ) { - if ( -1 == kill(pid_w, SIGKILL) ) { - break; - } - sleep(1); - } - } - if ( 16 == i_w ) { - u3l_log("disk: process %d seems unkillable!", pid_w); - c3_assert(0); - } - u3l_log("disk: stopped old process %u", pid_w); - } - } - fclose(loq_u); - c3_unlink(paf_c); - } - - if ( NULL == (loq_u = c3_fopen(paf_c, "w")) ) { - u3l_log("disk: unable to open %s", paf_c); - c3_assert(0); - } - - fprintf(loq_u, "%u\n", getpid()); - - { - c3_i fid_i = fileno(loq_u); - c3_sync(fid_i); - } - - fclose(loq_u); - c3_free(paf_c); -} - -/* u3_disk_release(): release a lockfile. -*/ -static void -u3_disk_release(c3_c* pax_c) -{ - c3_c* paf_c = _disk_lock(pax_c); - - c3_unlink(paf_c); - c3_free(paf_c); -} - -/* u3_disk_exit(): close the log. -*/ -void -u3_disk_exit(u3_disk* log_u) -{ - // cancel all outstanding reads - // - { - u3_read* red_u = log_u->red_u; - - while ( red_u ) { - _disk_read_close(red_u); - red_u = red_u->nex_u; - } - } - - // try to cancel write thread - // shortcircuit cleanup if we cannot - // - if ( (c3y == log_u->ted_o) - && (0 > uv_cancel(&log_u->req_u)) ) - { - // u3l_log("disk: unable to cleanup"); - return; - } - - // close database - // - u3_lmdb_exit(log_u->mdb_u); - - // dispose planned writes - // - - { - u3_fact* tac_u = log_u->put_u.ext_u; - u3_fact* nex_u; - - while ( tac_u ) { - nex_u = tac_u->nex_u; - u3_fact_free(tac_u); - tac_u = nex_u; - } - } - - u3_disk_release(log_u->dir_u->pax_c); - - u3_dire_free(log_u->dir_u); - u3_dire_free(log_u->urb_u); - u3_dire_free(log_u->com_u); - - c3_free(log_u); - -#if defined(DISK_TRACE_JAM) || defined(DISK_TRACE_CUE) - u3t_trace_close(); -#endif -} - -/* u3_disk_info(): status info as a (list mass). -*/ -u3_noun -u3_disk_info(u3_disk* log_u) -{ - u3_read* red_u = log_u->red_u; - u3_noun red = u3_nul; - u3_noun lit = u3i_list( - u3_pier_mase("live", log_u->liv_o), - u3_pier_mase("event", u3i_chub(log_u->dun_d)), - u3_none); - - if ( log_u->put_u.ext_u ) { - lit = u3nc( - u3_pier_mass( - c3__save, - u3i_list( - u3_pier_mase("save-start", u3i_chub(log_u->put_u.ext_u->eve_d)), - u3_pier_mase("save-final", u3i_chub(log_u->put_u.ent_u->eve_d)), - u3_none)), - lit); - } - - while ( red_u ) { - red = u3nc( - u3_pier_mass( - u3dc("scot", c3__ux, u3i_chub((c3_d)red_u)), - u3i_list( - u3_pier_mase("start", u3i_chub(red_u->eve_d)), - u3_pier_mase("final", u3i_chub(red_u->eve_d + red_u->len_d - 1)), - u3_none)), - red); - red_u = red_u->nex_u; - } - lit = u3nc(u3_pier_mass(c3__read, red), lit); - return u3_pier_mass(c3__disk, lit); -} - -/* u3_disk_slog(): print status info. -*/ -void -u3_disk_slog(u3_disk* log_u) -{ - u3l_log(" disk: live=%s, event=%" PRIu64, - ( c3y == log_u->liv_o ) ? "&" : "|", - log_u->dun_d); - - { - u3_read* red_u = log_u->red_u; - - while ( red_u ) { - u3l_log(" read: %" PRIu64 "-%" PRIu64, - red_u->eve_d, - (red_u->eve_d + red_u->len_d) - 1); - red_u = red_u->nex_u; - } - } - - if ( log_u->put_u.ext_u ) { - if ( log_u->put_u.ext_u != log_u->put_u.ent_u ) { - u3l_log(" save: %" PRIu64 "-%" PRIu64, - log_u->put_u.ext_u->eve_d, - log_u->put_u.ent_u->eve_d); - } - else { - u3l_log(" save: %" PRIu64, log_u->put_u.ext_u->eve_d); - } - } -} - -/* u3_disk_init(): load or create pier directories and event log. -*/ -u3_disk* -u3_disk_init(c3_c* pax_c, u3_disk_cb cb_u) -{ - u3_disk* log_u = c3_calloc(sizeof(*log_u)); - log_u->liv_o = c3n; - log_u->ted_o = c3n; - log_u->cb_u = cb_u; - log_u->red_u = 0; - log_u->put_u.ent_u = log_u->put_u.ext_u = 0; - - // create/load pier directory - // - { - if ( 0 == (log_u->dir_u = u3_foil_folder(pax_c)) ) { - fprintf(stderr, "disk: failed to load pier at %s\r\n", pax_c); - c3_free(log_u); - return 0; - } - } - - // acquire lockfile. - // - u3_disk_acquire(pax_c); - - // create/load $pier/.urb - // - { - c3_c* urb_c = c3_malloc(6 + strlen(pax_c)); - - strcpy(urb_c, pax_c); - strcat(urb_c, "/.urb"); - - if ( 0 == (log_u->urb_u = u3_foil_folder(urb_c)) ) { - fprintf(stderr, "disk: failed to load /.urb in %s\r\n", pax_c); - c3_free(urb_c); - c3_free(log_u); - return 0; - } - c3_free(urb_c); - } - - // create/load $pier/.urb/put and $pier/.urb/get - // - { - c3_c* dir_c = c3_malloc(10 + strlen(pax_c)); - - strcpy(dir_c, pax_c); - strcat(dir_c, "/.urb/put"); - c3_mkdir(dir_c, 0700); - - strcpy(dir_c, pax_c); - strcat(dir_c, "/.urb/get"); - c3_mkdir(dir_c, 0700); - - c3_free(dir_c); - } - - // create/load $pier/.urb/log, initialize db - // - { - c3_c* log_c = c3_malloc(10 + strlen(pax_c)); - - strcpy(log_c, pax_c); - strcat(log_c, "/.urb/log"); - - if ( 0 == (log_u->com_u = u3_foil_folder(log_c)) ) { - fprintf(stderr, "disk: failed to load /.urb/log in %s\r\n", pax_c); - c3_free(log_c); - c3_free(log_u); - return 0; - } - - // Arbitrarily choosing 1TB as a "large enough" mapsize - // - // per the LMDB docs: - // "[..] on 64-bit there is no penalty for making this huge (say 1TB)." - // - { - const size_t siz_i = - #if defined(U3_OS_mingw) - 0xf00000000; - // 500 GiB is as large as musl on aarch64 wants to allow - #elif (defined(U3_CPU_aarch64) && defined(U3_OS_linux)) - 0x7d00000000; - #else - 0x10000000000; - #endif - - if ( 0 == (log_u->mdb_u = u3_lmdb_init(log_c, siz_i)) ) { - fprintf(stderr, "disk: failed to initialize database\r\n"); - c3_free(log_c); - c3_free(log_u); - return 0; - } - } - - c3_free(log_c); - } - - // get the latest event number from the db - // - { - log_u->dun_d = 0; - c3_d fir_d; - - if ( c3n == u3_lmdb_gulf(log_u->mdb_u, &fir_d, &log_u->dun_d) ) { - fprintf(stderr, "disk: failed to load latest event from database\r\n"); - c3_free(log_u); - return 0; - } - - log_u->sen_d = log_u->dun_d; - } - - log_u->liv_o = c3y; - -#if defined(DISK_TRACE_JAM) || defined(DISK_TRACE_CUE) - u3t_trace_open(pax_c); -#endif - - return log_u; -} diff --git a/pkg/urbit/vere/foil.c b/pkg/urbit/vere/foil.c deleted file mode 100644 index 186c8fdec..000000000 --- a/pkg/urbit/vere/foil.c +++ /dev/null @@ -1,146 +0,0 @@ -/* vere/foil.c -** -** This file is in the public domain. -*/ - -#include "all.h" -#include "vere/vere.h" - - /* assumptions: - ** all measurements are in chubs (double-words, c3_d, uint64_t). - ** little-endian addressing is ASSUMED. - ** - ** framing: - ** the last two chubs of a frame: - ** - ** { - ** 64-bit frame length - ** { - ** (high 32 bits) mug of frame - ** (low 32 bits) mug of current address - ** } - ** } - ** - ** we can scan for one of these frames with very low probability - ** of a false positive. we always write to and read from the end - ** of a file. a frame position points to its end. - ** - ** protocol: - ** once the callback is called, all results are fully fsynced. - ** all callbacks are optional and can be passed 0. - */ - -/* _foil_fail(): fail with error. -*/ -static void -_foil_fail(const c3_c* why_c, c3_i err_i) -{ - if ( err_i ) { - u3l_log("%s: error: %s", why_c, uv_strerror(err_i)); - c3_assert(0); - } else { - u3l_log("%s: file error", why_c); - } - exit(1); -} - -/* _foil_close(): close file, blockingly. -*/ -static void -_foil_close(uv_file fil_f) -{ - c3_i err_i; - uv_fs_t ruq_u; - - if ( 0 != (err_i = uv_fs_close(u3L, &ruq_u, fil_f, 0)) ) { - _foil_fail("uv_fs_close", err_i); - } -} - -/* _foil_path(): allocate path. -*/ -static c3_c* -_foil_path(u3_dire* dir_u, - const c3_c* nam_c) -{ - c3_w len_w = strlen(dir_u->pax_c); - c3_c* pax_c; - - pax_c = c3_malloc(1 + len_w + 1 + strlen(nam_c)); - strcpy(pax_c, dir_u->pax_c); - pax_c[len_w] = '/'; - strcpy(pax_c + len_w + 1, nam_c); - - return pax_c; -} - -/* u3_foil_folder(): load directory, blockingly. null if nonexistent. -*/ -u3_dire* -u3_foil_folder(const c3_c* pax_c) -{ - u3_dire* dir_u; - uv_fs_t ruq_u; - uv_dirent_t den_u; - c3_i err_i; - - /* open directory, synchronously - */ - { - err_i = uv_fs_scandir(u3L, &ruq_u, pax_c, 0, 0); - - if ( err_i < 0 ) { - if ( UV_ENOENT != err_i ) { - _foil_fail(pax_c, err_i); - return 0; - } - else { - if ( 0 != (err_i = uv_fs_mkdir(u3L, &ruq_u, pax_c, 0700, 0)) ) { - _foil_fail(pax_c, err_i); - return 0; - } - else { - uv_fs_req_cleanup(&ruq_u); - return u3_foil_folder(pax_c); - } - } - } - - dir_u = u3_dire_init(pax_c); - } - - /* create entries for all files - */ - while ( UV_EOF != uv_fs_scandir_next(&ruq_u, &den_u) ) { - if ( UV_DIRENT_FILE == den_u.type ) { - u3_dent* det_u = u3_dent_init(den_u.name); - det_u->nex_u = dir_u->all_u; - dir_u->all_u = det_u; - } - } - - /* clean up request - */ - { - uv_fs_req_cleanup(&ruq_u); - } - - /* open directory file for reading, to fsync - */ - { - if ( 0 > (err_i = uv_fs_open(u3L, - &ruq_u, - pax_c, - O_RDONLY, - 0600, - 0)) ) - { - _foil_fail("open directory", err_i); - return 0; - } - dir_u->fil_u = ruq_u.result; - - uv_fs_req_cleanup(&ruq_u); - } - return dir_u; -} diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c deleted file mode 100644 index 913045b3e..000000000 --- a/pkg/urbit/vere/io/ames.c +++ /dev/null @@ -1,1601 +0,0 @@ -/* vere/ames.c -** -*/ -#include "all.h" -#include "vere/vere.h" -#include "ur/serial.h" - -/* u3_pact: outbound ames packet. -*/ - typedef struct _u3_pact { - uv_udp_send_t snd_u; // udp send request - u3_lane lan_u; // destination lane - c3_w len_w; // length in bytes - c3_y* hun_y; // packet buffer - c3_y imp_y; // galaxy number (optional) - c3_c* dns_c; // galaxy fqdn (optional) - struct _u3_ames* sam_u; // ames backpointer - } u3_pact; - -/* u3_ames: ames networking. -*/ - typedef struct _u3_ames { // packet network state - u3_auto car_u; // driver - u3_pier* pir_u; // pier - union { // uv udp handle - uv_udp_t wax_u; // - uv_handle_t had_u; // - }; // - c3_l sev_l; // instance number - ur_cue_test_t* tes_u; // cue-test handle - u3_cue_xeno* sil_u; // cue handle - c3_c* dns_c; // domain XX multiple/fallback - c3_y ver_y; // protocol version - u3p(u3h_root) lax_p; // lane scry cache - struct _u3_panc* pac_u; // packets pending forwards - c3_w imp_w[256]; // imperial IPs - time_t imp_t[256]; // imperial IP timestamps - c3_o imp_o[256]; // imperial print status - struct { // config: - c3_o net_o; // can send - c3_o see_o; // can scry - c3_o fit_o; // filtering active - } fig_u; // - struct { // stats: - c3_d dop_d; // drop count - c3_d fal_d; // crash count - c3_d saw_d; // successive scry failures - c3_d hed_d; // failed to read header - c3_d vet_d; // version mismatches filtered - c3_d mut_d; // invalid mugs filtered - c3_d bod_d; // failed to read body - c3_d foq_d; // forward queue size - c3_d fow_d; // forwarded count - c3_d fod_d; // forwards dropped count - c3_d bad_d; // bad ciphertext count - } sat_u; // - } u3_ames; - -/* u3_head: ames packet header -*/ - typedef struct _u3_head { - c3_o sim_o; // is ames protocol? - c3_y ver_y; // protocol version - c3_y sac_y; // sender class - c3_y rac_y; // receiver class - c3_l mug_l; // truncated mug hash of u3_body - c3_o rel_o; // relayed? - } u3_head; - -/* u3_body: ames packet body -*/ - typedef struct _u3_body { - c3_d sen_d[2]; // sender - c3_d rec_d[2]; // receiver - c3_y sic_y; // sender life tick - c3_y ric_y; // receiver life tick - c3_s con_s; // content size - c3_y* con_y; // content - c3_d rog_d; // origin lane (optional) - c3_l mug_l; // checksum - } u3_body; - -/* u3_panc: deconstructed incoming packet -*/ - typedef struct _u3_panc { - u3_ames* sam_u; // ames backpointer - struct _u3_panc* pre_u; // previous packet - struct _u3_panc* nex_u; // next packet - u3_lane ore_u; // origin lane - u3_head hed_u; // header - u3_body bod_u; // body - void* ptr_v; // buffer (to free) - } u3_panc; - -/* _ames_alloc(): libuv buffer allocator. -*/ -static void -_ames_alloc(uv_handle_t* had_u, - size_t len_i, - uv_buf_t* buf - ) -{ - // we allocate 2K, which gives us plenty of space - // for a single ames packet (max size 1060 bytes) - // - void* ptr_v = c3_malloc(2048); - *buf = uv_buf_init(ptr_v, 2048); -} - -/* _ames_pact_free(): free packet struct. -*/ -static void -_ames_pact_free(u3_pact* pac_u) -{ - c3_free(pac_u->hun_y); - c3_free(pac_u->dns_c); - c3_free(pac_u); -} - -/* _ames_panc_free(): remove references, lose refcounts and free struct -*/ -static void -_ames_panc_free(u3_panc* pac_u) -{ - if ( 0 != pac_u->nex_u ) { - pac_u->nex_u->pre_u = pac_u->pre_u; - } - - if ( 0 != pac_u->pre_u ) { - pac_u->pre_u->nex_u = pac_u->nex_u; - } - else { - c3_assert(pac_u == pac_u->sam_u->pac_u); - pac_u->sam_u->pac_u = pac_u->nex_u; - } - - c3_free(pac_u->ptr_v); - c3_free(pac_u); -} - -/* _ames_sift_head(): parse packet header. -*/ -static c3_o -_ames_sift_head(u3_head* hed_u, c3_y buf_y[4]) -{ - c3_w hed_w = buf_y[0] - | (buf_y[1] << 8) - | (buf_y[2] << 16) - | (buf_y[3] << 24); - - // first three bits are reserved - // - hed_u->sim_o = (hed_w >> 3) & 0x1; - hed_u->ver_y = (hed_w >> 4) & 0x7; - hed_u->sac_y = (hed_w >> 7) & 0x3; - hed_u->rac_y = (hed_w >> 9) & 0x3; - hed_u->mug_l = (hed_w >> 11) & 0xfffff; // 20 bits - hed_u->rel_o = (hed_w >> 31) & 0x1; - - // reject packets that don't even claim to be ames packets - // - return hed_u->sim_o; -} - - -/* _ames_chub_bytes(): c3_y[8] to c3_d -** XX factor out, deduplicate with other conversions -*/ -static inline c3_d -_ames_chub_bytes(c3_y byt_y[8]) -{ - return (c3_d)byt_y[0] - | (c3_d)byt_y[1] << 8 - | (c3_d)byt_y[2] << 16 - | (c3_d)byt_y[3] << 24 - | (c3_d)byt_y[4] << 32 - | (c3_d)byt_y[5] << 40 - | (c3_d)byt_y[6] << 48 - | (c3_d)byt_y[7] << 56; -} - -/* _ames_ship_to_chubs(): pack [len_y] bytes into c3_d[2] -*/ -static inline void -_ames_ship_to_chubs(c3_d sip_d[2], c3_y len_y, c3_y* buf_y) -{ - c3_y sip_y[16] = {0}; - memcpy(sip_y, buf_y, c3_min(16, len_y)); - - sip_d[0] = _ames_chub_bytes(sip_y); - sip_d[1] = _ames_chub_bytes(sip_y + 8); -} - -/* _ames_chub_bytes(): c3_d to c3_y[8] -** XX factor out, deduplicate with other conversions -*/ -static inline void -_ames_bytes_chub(c3_y byt_y[8], c3_d num_d) -{ - byt_y[0] = num_d & 0xff; - byt_y[1] = (num_d >> 8) & 0xff; - byt_y[2] = (num_d >> 16) & 0xff; - byt_y[3] = (num_d >> 24) & 0xff; - byt_y[4] = (num_d >> 32) & 0xff; - byt_y[5] = (num_d >> 40) & 0xff; - byt_y[6] = (num_d >> 48) & 0xff; - byt_y[7] = (num_d >> 56) & 0xff; -} - -/* _ames_ship_of_chubs(): unpack c3_d[2] into [len_y] bytes. -*/ -static inline void -_ames_ship_of_chubs(c3_d sip_d[2], c3_y len_y, c3_y* buf_y) -{ - c3_y sip_y[16] = {0}; - - _ames_bytes_chub(sip_y, sip_d[0]); - _ames_bytes_chub(sip_y + 8, sip_d[1]); - - memcpy(buf_y, sip_y, c3_min(16, len_y)); -} - -/* _ames_sift_body(): parse packet body. -*/ -static c3_o -_ames_sift_body(u3_head* hed_u, - u3_body* bod_u, - c3_w len_w, - c3_y* bod_y) -{ - c3_y rog_y, sen_y, rec_y; - - rog_y = ( c3y == hed_u->rel_o )? 6 : 0; - - sen_y = 2 << hed_u->sac_y; - rec_y = 2 << hed_u->rac_y; - - if ( (1 + sen_y + rec_y + rog_y) >= len_w ) { - return c3n; - } - else { - c3_y* gob_y; - c3_s gob_s; - - if ( rog_y) { - c3_y rag_y[8] = {0}; - memcpy(rag_y, bod_y, rog_y); - bod_u->rog_d = _ames_chub_bytes(rag_y); - } - else { - bod_u->rog_d = 0; - } - - gob_y = bod_y + rog_y; - gob_s = len_w - rog_y; - - bod_u->mug_l = u3r_mug_bytes(gob_y, gob_s) & 0xfffff; - - bod_u->sic_y = gob_y[0] & 0xf; - bod_u->ric_y = (gob_y[0] >> 4) & 0xf; - - _ames_ship_to_chubs(bod_u->sen_d, sen_y, gob_y + 1); - _ames_ship_to_chubs(bod_u->rec_d, rec_y, gob_y + 1 + sen_y); - - bod_u->con_s = gob_s - 1 - sen_y - rec_y; - bod_u->con_y = gob_y + 1 + sen_y + rec_y; - - return c3y; - } -} - -/* _ames_etch_head(): serialize packet header. -*/ -static void -_ames_etch_head(u3_head* hed_u, c3_y buf_y[4]) -{ - c3_w hed_w = ((hed_u->sim_o & 0x1) << 3) - ^ ((hed_u->ver_y & 0x7) << 4) - ^ ((hed_u->sac_y & 0x3) << 7) - ^ ((hed_u->rac_y & 0x3) << 9) - ^ ((hed_u->mug_l & 0xfffff) << 11) - ^ ((hed_u->rel_o & 0x1) << 31); - - // only version 0 currently recognized - // - c3_assert( 0 == hed_u->ver_y ); // XX remove after testing - - buf_y[0] = hed_w & 0xff; - buf_y[1] = (hed_w >> 8) & 0xff; - buf_y[2] = (hed_w >> 16) & 0xff; - buf_y[3] = (hed_w >> 24) & 0xff; -} - -/* _ames_etch_pack(): serialize packet header and body. -*/ -static c3_w -_ames_etch_pack(u3_head* hed_u, - u3_body* bod_u, - c3_y** out_y) -{ - c3_y sen_y = 2 << hed_u->sac_y; // sender len - c3_y rec_y = 2 << hed_u->rac_y; // receiver len - c3_y rog_y = ( c3y == hed_u->rel_o )? 6 : 0; // origin len - c3_w bod_w = rog_y + 1 + sen_y + rec_y + bod_u->con_s; // body len - c3_w len_w = 4 + bod_w; // packet len - c3_y* pac_y = c3_malloc(len_w); // output buf - c3_y* bod_y = pac_y + 4; // body cursor - c3_y* gob_y = bod_y + rog_y; // after origin - - // serialize the head - // - _ames_etch_head(hed_u, pac_y); - - // serialize the origin, if present - // - if ( rog_y ) { - c3_y rag_y[8] = {0}; - _ames_bytes_chub(rag_y, bod_u->rog_d); - memcpy(bod_y, rag_y, rog_y); - } - - // serialize the body - // - gob_y[0] = (bod_u->sic_y & 0xf) ^ ((bod_u->ric_y & 0xf) << 4); - - _ames_ship_of_chubs(bod_u->sen_d, sen_y, gob_y + 1); - _ames_ship_of_chubs(bod_u->rec_d, rec_y, gob_y + 1 + sen_y); - - memcpy(gob_y + 1 + sen_y + rec_y, bod_u->con_y, bod_u->con_s); - - *out_y = pac_y; - return len_w; -} - -/* _ames_send_cb(): send callback. -*/ -static void -_ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) -{ - u3_pact* pac_u = (u3_pact*)req_u; - u3_ames* sam_u = pac_u->sam_u; - - if ( sas_i && (c3y == sam_u->fig_u.net_o) ) { - u3l_log("ames: send fail: %s", uv_strerror(sas_i)); - sam_u->fig_u.net_o = c3n; - } - else { - sam_u->fig_u.net_o = c3y; - } - - _ames_pact_free(pac_u); -} - -/* _ames_send(): send buffer to address on port. -*/ -static void -_ames_send(u3_pact* pac_u) -{ - u3_ames* sam_u = pac_u->sam_u; - - if ( !pac_u->hun_y ) { - _ames_pact_free(pac_u); - return; - } - else { - struct sockaddr_in add_u; - - memset(&add_u, 0, sizeof(add_u)); - add_u.sin_family = AF_INET; - add_u.sin_addr.s_addr = htonl(pac_u->lan_u.pip_w); - add_u.sin_port = htons(pac_u->lan_u.por_s); - - { - uv_buf_t buf_u = uv_buf_init((c3_c*)pac_u->hun_y, pac_u->len_w); - c3_i sas_i = uv_udp_send(&pac_u->snd_u, - &sam_u->wax_u, - &buf_u, 1, - (const struct sockaddr*)&add_u, - _ames_send_cb); - - if ( sas_i ) { - if ( c3y == sam_u->fig_u.net_o ) { - u3l_log("ames: send fail: %s", uv_strerror(sas_i)); - sam_u->fig_u.net_o = c3n; - } - - _ames_pact_free(pac_u); - } - } - } -} - -/* u3_ames_decode_lane(): deserialize noun to lane; 0.0.0.0:0 if invalid -*/ -u3_lane -u3_ames_decode_lane(u3_atom lan) { - u3_lane lan_u; - c3_d lan_d; - - if ( c3n == u3r_safe_chub(lan, &lan_d) || (lan_d >> 48) != 0 ) { - return (u3_lane){0, 0}; - } - - u3z(lan); - - lan_u.pip_w = (c3_w)lan_d; - lan_u.por_s = (c3_s)(lan_d >> 32); - return lan_u; -} - -/* u3_ames_lane_to_chub(): serialize lane to double-word -*/ -c3_d -u3_ames_lane_to_chub(u3_lane lan) { - return ((c3_d)lan.por_s << 32) ^ (c3_d)lan.pip_w; -} - -/* u3_ames_encode_lane(): serialize lane to noun -*/ -u3_atom -u3_ames_encode_lane(u3_lane lan) { - return u3i_chub(u3_ames_lane_to_chub(lan)); -} - -/* _ames_lane_into_cache(): put las for who into cache, including timestamp -*/ -static void -_ames_lane_into_cache(u3p(u3h_root) lax_p, u3_noun who, u3_noun las) { - struct timeval tim_tv; - gettimeofday(&tim_tv, 0); - u3_noun now = u3_time_in_tv(&tim_tv); - u3_noun val = u3nc(las, now); - u3h_put(lax_p, who, val); - u3z(who); -} - -/* _ames_lane_from_cache(): retrieve lane for who from cache, if any & fresh -*/ -static u3_weak -_ames_lane_from_cache(u3p(u3h_root) lax_p, u3_noun who) { - u3_weak lac = u3h_git(lax_p, who); - - if ( u3_none != lac ) { - struct timeval tim_tv; - gettimeofday(&tim_tv, 0); - u3_noun now = u3_time_in_tv(&tim_tv); - u3_noun den = u3t(lac); - - // consider entries older than 2 minutes stale, ignore them - // - if ( 120000 > u3_time_gap_ms(u3k(den), now) ) { - lac = u3k(u3h(lac)); - } else { - lac = u3_none; - } - } - - u3z(who); - return lac; -} - -/* _ames_serialize_packet(): u3_panc to atom, updating the origin lane if dop_o -** (retains pac_u) -*/ -static u3_noun -_ames_serialize_packet(u3_panc* pac_u, c3_o dop_o) -{ - // update the body's lane, if: - // - we're supposed to (dop_o) - // - it hasn't already been updated (rel_o) - // - sender is not a galaxy - // - if ( c3y == dop_o - && c3n == pac_u->hed_u.rel_o - && !( ( 256 > pac_u->bod_u.sen_d[0] ) - && ( 0 == pac_u->bod_u.sen_d[1] ) ) ) - { - pac_u->hed_u.rel_o = c3y; - pac_u->bod_u.rog_d = u3_ames_lane_to_chub(pac_u->ore_u); - } - - // serialize the packet - // - // XX serialize on stack? - // - { - u3_noun pac; - c3_y* pac_y; - c3_w len_w = _ames_etch_pack(&pac_u->hed_u, - &pac_u->bod_u, - &pac_y); - pac = u3i_bytes(len_w, pac_y); - c3_free(pac_y); - - return pac; - } -} - -/* _ames_czar_port(): udp port for galaxy. -*/ -static c3_s -_ames_czar_port(c3_y imp_y) -{ - if ( c3n == u3_Host.ops_u.net ) { - return 31337 + imp_y; - } - else { - return 13337 + imp_y; - } -} - -/* _ames_czar_gone(): galaxy address resolution failed. -*/ -static void -_ames_czar_gone(u3_pact* pac_u, time_t now) -{ - u3_ames* sam_u = pac_u->sam_u; - - if ( c3y == sam_u->imp_o[pac_u->imp_y] ) { - u3l_log("ames: czar at %s: not found (b)", pac_u->dns_c); - sam_u->imp_o[pac_u->imp_y] = c3n; - } - - if ( (0 == sam_u->imp_w[pac_u->imp_y]) || - (0xffffffff == sam_u->imp_w[pac_u->imp_y]) ) - { - sam_u->imp_w[pac_u->imp_y] = 0xffffffff; - } - - // keep existing ip for 5 more minutes - // - sam_u->imp_t[pac_u->imp_y] = now; - - _ames_pact_free(pac_u); -} - -/* _ames_czar_here(): galaxy address resolution succeeded. -*/ -static void -_ames_czar_here(u3_pact* pac_u, time_t now, struct sockaddr_in* add_u) -{ - u3_ames* sam_u = pac_u->sam_u; - c3_w old_w = sam_u->imp_w[pac_u->imp_y]; - c3_w pip_w = ntohl(add_u->sin_addr.s_addr); - - if ( pip_w != old_w ) { - u3_noun nam = u3dc("scot", c3__if, u3i_word(pip_w)); - c3_c* nam_c = u3r_string(nam); - - u3l_log("ames: czar %s: ip %s", pac_u->dns_c, nam_c); - - c3_free(nam_c); - u3z(nam); - } - - sam_u->imp_w[pac_u->imp_y] = pip_w; - sam_u->imp_t[pac_u->imp_y] = now; - sam_u->imp_o[pac_u->imp_y] = c3y; - - pac_u->lan_u.pip_w = pip_w; - _ames_send(pac_u); -} - -/* _ames_czar_cb(): galaxy address resolution callback. -*/ -static void -_ames_czar_cb(uv_getaddrinfo_t* adr_u, - c3_i sas_i, - struct addrinfo* aif_u) -{ - { - u3_pact* pac_u = (u3_pact*)adr_u->data; - struct addrinfo* rai_u = aif_u; - time_t now = time(0); - - while ( rai_u ) { - if ( (AF_INET == rai_u->ai_family) ) { - _ames_czar_here(pac_u, now, (struct sockaddr_in *)rai_u->ai_addr); - break; - } - else { - rai_u = rai_u->ai_next; - } - } - - if ( !rai_u ) { - _ames_czar_gone(pac_u, now); - } - } - - c3_free(adr_u); - uv_freeaddrinfo(aif_u); -} - -/* _ames_czar(): galaxy address resolution. -*/ -static void -_ames_czar(u3_pact* pac_u) -{ - u3_ames* sam_u = pac_u->sam_u; - - pac_u->lan_u.por_s = _ames_czar_port(pac_u->imp_y); - - if ( c3n == u3_Host.ops_u.net ) { - pac_u->lan_u.pip_w = 0x7f000001; - _ames_send(pac_u); - return; - } - - // if we don't have a galaxy domain, no-op - // - if ( !sam_u->dns_c ) { - u3_noun nam = u3dc("scot", 'p', pac_u->imp_y); - c3_c* nam_c = u3r_string(nam); - u3l_log("ames: no galaxy domain for %s, no-op", nam_c); - - c3_free(nam_c); - u3z(nam); - return; - } - - { - c3_w pip_w = sam_u->imp_w[pac_u->imp_y]; - time_t wen = sam_u->imp_t[pac_u->imp_y]; - time_t now = time(0); - - // backoff for 5 minutes after failed lookup - // - if ( ( now < wen ) // time shenanigans! - || ( (0xffffffff == pip_w) // sentinal ip address - && ((now - wen) < 300) ) ) - { - _ames_pact_free(pac_u); - return; - } - // cached addresses have a 5 minute TTL - // - else if ( (0 != pip_w) && ((now - wen) < 300) ) { - pac_u->lan_u.pip_w = pip_w; - _ames_send(pac_u); - return; - } - else { - c3_i sas_i; - - { - u3_noun nam = u3dc("scot", 'p', pac_u->imp_y); - c3_c* nam_c = u3r_string(nam); - - // NB: . separator not counted, as [nam_c] includes a ~ that we skip - // - pac_u->dns_c = c3_malloc(1 + strlen(nam_c) + strlen(sam_u->dns_c)); - sas_i = snprintf(pac_u->dns_c, 255, "%s.%s", nam_c + 1, sam_u->dns_c); - - c3_free(nam_c); - u3z(nam); - } - - if ( 255 <= sas_i ) { - u3l_log("ames: czar: galaxy domain %s truncated", sam_u->dns_c); - _ames_pact_free(pac_u); - return; - } - - { - uv_getaddrinfo_t* adr_u = c3_malloc(sizeof(*adr_u)); - adr_u->data = pac_u; - - if ( 0 != (sas_i = uv_getaddrinfo(u3L, adr_u, - _ames_czar_cb, - pac_u->dns_c, 0, 0)) ) - { - u3l_log("ames: %s", uv_strerror(sas_i)); - _ames_czar_gone(pac_u, now); - return; - } - } - } - } -} - -/* _ames_ef_send(): send packet to network (v4). -*/ -static void -_ames_ef_send(u3_ames* sam_u, u3_noun lan, u3_noun pac) -{ - if ( c3n == sam_u->car_u.liv_o ) { - u3l_log("ames: not yet live, dropping outbound"); - u3z(lan); u3z(pac); - return; - } - - u3_pact* pac_u = c3_calloc(sizeof(*pac_u)); - pac_u->sam_u = sam_u; - pac_u->len_w = u3r_met(3, pac); - pac_u->hun_y = c3_malloc(pac_u->len_w); - - u3r_bytes(0, pac_u->len_w, pac_u->hun_y, pac); - - u3_noun tag, val; - u3x_cell(lan, &tag, &val); - c3_assert( (c3y == tag) || (c3n == tag) ); - - // galaxy lane; do DNS lookup and send packet - // - if ( c3y == tag ) { - c3_assert( c3y == u3a_is_cat(val) ); - c3_assert( val < 256 ); - - pac_u->imp_y = val; - _ames_czar(pac_u); - } - // non-galaxy lane - // - else { - u3_lane lan_u = u3_ames_decode_lane(u3k(val)); - // convert incoming localhost to outgoing localhost - // - lan_u.pip_w = ( 0 == lan_u.pip_w )? 0x7f000001 : lan_u.pip_w; - // if in local-only mode, don't send remote packets - // - if ( (c3n == u3_Host.ops_u.net) && (0x7f000001 != lan_u.pip_w) ) { - _ames_pact_free(pac_u); - } - // if the lane is uninterpretable, silently drop the packet - // - else if ( 0 == lan_u.por_s ) { - if ( u3C.wag_w & u3o_verbose ) { - u3l_log("ames: inscrutable lane"); - } - _ames_pact_free(pac_u); - } - // otherwise, mutate destination and send packet - // - else { - pac_u->lan_u = lan_u; - _ames_send(pac_u); - } - } - u3z(lan); u3z(pac); -} - -/* _ames_cap_queue(): cap ovum queue at 1k, dropping oldest packets. -*/ -static void -_ames_cap_queue(u3_ames* sam_u) -{ - u3_ovum* egg_u = sam_u->car_u.ext_u; - - while ( egg_u && (1000 < sam_u->car_u.dep_w) ) { - u3_ovum* nex_u = egg_u->nex_u; - - if ( c3__hear == u3h(egg_u->cad) ) { - u3_auto_drop(&sam_u->car_u, egg_u); - sam_u->sat_u.dop_d++; - - if ( u3C.wag_w & u3o_verbose ) { - u3l_log("ames: packet dropped (%" PRIu64 " total)", sam_u->sat_u.dop_d); - } - } - - egg_u = nex_u; - } - - if ( (sam_u->sat_u.dop_d && (0 == (sam_u->sat_u.dop_d % 1000))) - && !(u3C.wag_w & u3o_verbose) ) - { - u3l_log("ames: packet dropped (%" PRIu64 " total)", sam_u->sat_u.dop_d); - } -} - -/* _ames_hear_bail(): handle packet failure. -*/ -static void -_ames_hear_bail(u3_ovum* egg_u, u3_noun lud) -{ - u3_ames* sam_u = (u3_ames*)egg_u->car_u; - c3_w len_w = u3qb_lent(lud); - - if ( (1 == len_w) && c3__evil == u3h(u3h(lud)) ) { - sam_u->sat_u.bad_d++; - - if ( (u3C.wag_w & u3o_verbose) - || (0 == (sam_u->sat_u.bad_d % 100)) ) - { - u3l_log("ames: heard bad crypto (%" PRIu64 " total), " - "check azimuth state", - sam_u->sat_u.bad_d); - } - } - else { - sam_u->sat_u.fal_d++; - - if ( (u3C.wag_w & u3o_verbose) - || (0 == (sam_u->sat_u.fal_d % 100)) ) - { - if ( 2 == len_w ) { - u3_pier_punt_goof("hear", u3k(u3h(lud))); - u3_pier_punt_goof("crud", u3k(u3h(u3t(lud)))); - } - // !2 traces is unusual, just print the first if present - // - else if ( len_w ) { - u3_pier_punt_goof("hear", u3k(u3h(lud))); - } - - u3l_log("ames: packet failed (%" PRIu64 " total)", - sam_u->sat_u.fal_d); - } - } - - u3z(lud); - u3_ovum_free(egg_u); -} - -/* _ames_put_packet(): add packet to queue, drop old packets on pressure -*/ -static void -_ames_put_packet(u3_ames* sam_u, - u3_noun msg, - u3_lane lan_u) -{ - u3_noun wir = u3nc(c3__ames, u3_nul); - u3_noun cad = u3nt(c3__hear, u3nc(c3n, u3_ames_encode_lane(lan_u)), msg); - - u3_auto_peer( - u3_auto_plan(&sam_u->car_u, - u3_ovum_init(0, c3__a, wir, cad)), - 0, 0, _ames_hear_bail); - - _ames_cap_queue(sam_u); -} - -/* _ames_forward(): forward pac_u onto the (list lane) las, then free pac_u -*/ -static void -_ames_forward(u3_panc* pac_u, u3_noun las) -{ - u3_ames* sam_u = pac_u->sam_u; - - sam_u->sat_u.fow_d++; - if ( 0 == (sam_u->sat_u.fow_d % 1000000) ) { - u3l_log("ames: forwarded %" PRIu64 " total", sam_u->sat_u.fow_d); - } - - if ( u3C.wag_w & u3o_verbose ) { - u3_noun sen = u3dc("scot", 'p', u3i_chubs(2, pac_u->bod_u.sen_d)); - u3_noun rec = u3dc("scot", 'p', u3i_chubs(2, pac_u->bod_u.rec_d)); - c3_c* sen_c = u3r_string(sen); - c3_c* rec_c = u3r_string(rec); - c3_y* pip_y = (c3_y*)&pac_u->ore_u.pip_w; - - //NOTE ip byte order assumes little-endian - u3l_log("ames: forwarding for %s to %s from %d.%d.%d.%d:%d", - sen_c, rec_c, - pip_y[3], pip_y[2], pip_y[1], pip_y[0], - pac_u->ore_u.por_s); - - c3_free(sen_c); c3_free(rec_c); - u3z(sen); u3z(rec); - } - - { - u3_noun pac = _ames_serialize_packet(pac_u, c3y); - u3_noun tag, dat, lan, t = las; - - while ( u3_nul != t ) { - u3x_cell(t, &lan, &t); - - // validate lane and skip self if galaxy - // - if ( c3n == u3r_cell(lan, &tag, &dat) ) { - u3l_log("ames: bogus lane"); - u3m_p("lan", lan); - } - else { - c3_o sen_o = c3y; - c3_d who_d[2]; - - if ( c3y == tag ) { - u3r_chubs(0, 2, who_d, dat); - - if ( (who_d[0] == sam_u->pir_u->who_d[0]) - && (who_d[1] == sam_u->pir_u->who_d[1]) ) - { - sen_o = c3n; - if ( u3C.wag_w & u3o_verbose ) { - u3l_log("ames: forward skipping self"); - } - } - } - - if ( c3y == sen_o ) { - _ames_ef_send(sam_u, u3k(lan), u3k(pac)); - } - } - } - - u3z(pac); - } - - _ames_panc_free(pac_u); - u3z(las); -} - -/* _ames_lane_scry_cb(): learn lane to forward packet on -*/ -static void -_ames_lane_scry_cb(void* vod_p, u3_noun nun) -{ - u3_panc* pac_u = vod_p; - u3_ames* sam_u = pac_u->sam_u; - u3_weak las = u3r_at(7, nun); - - sam_u->sat_u.foq_d--; - - // if scry fails, remember we can't scry, and just inject the packet - // - if ( u3_none == las ) { - if ( 5 < ++sam_u->sat_u.saw_d ) { - u3l_log("ames: giving up scry"); - sam_u->fig_u.see_o = c3n; - } - _ames_put_packet(sam_u, _ames_serialize_packet(pac_u, c3n), pac_u->ore_u); - _ames_panc_free(pac_u); - } - else { - sam_u->sat_u.saw_d = 0; - - // cache the scry result for later use - // - _ames_lane_into_cache(sam_u->lax_p, - u3i_chubs(2, pac_u->bod_u.rec_d), - u3k(las)); - - // if there is no lane, drop the packet - // - if ( u3_nul == las ) { - _ames_panc_free(pac_u); - } - // if there is a lane, forward the packet on it - // - else { - _ames_forward(pac_u, u3k(las)); - } - } - - u3z(nun); -} - -/* _ames_try_forward(): try to forward a packet for another ship. -*/ -static void -_ames_try_forward(u3_ames* sam_u, - u3_lane* lan_u, - u3_head* hed_u, - u3_body* bod_u, - c3_y* hun_y) -{ - u3_weak lac; - - // if the recipient is a galaxy, their lane is always &+~gax - // - if ( (256 > bod_u->rec_d[0]) - && (0 == bod_u->rec_d[1]) ) - { - lac = u3nc(c3y, (c3_y)bod_u->rec_d[0]); - } - // otherwise, try to get the lane from cache - // - else { - lac = _ames_lane_from_cache(sam_u->lax_p, u3i_chubs(2, bod_u->rec_d)); - - // if we don't know the lane, and the scry queue is full, - // just drop the packet - // - //TODO drop oldest item in forward queue in favor of this one. - // ames.c doesn't/shouldn't know about the shape of scry events, - // so can't pluck these out of the event queue like it does in - // _ames_cap_queue. as such, blocked on u3_lord_peek_cancel or w/e. - // - if ( (u3_none == lac) && (1000 < sam_u->sat_u.foq_d) ) { - sam_u->sat_u.fod_d++; - if ( 0 == (sam_u->sat_u.fod_d % 10000) ) { - u3l_log("ames: dropped %" PRIu64 " forwards total", - sam_u->sat_u.fod_d); - } - - c3_free(hun_y); - return; - } - // if we know there's no lane, drop the packet - // - else if ( u3_nul == lac ) { - c3_free(hun_y); - return; - } - } - - // proceed with forwarding - // - { - // store the packet details for later processing - // - // XX allocates unnecessarily when we know the lane - // - u3_panc* pac_u = c3_calloc(sizeof(*pac_u)); - pac_u->sam_u = sam_u; - pac_u->hed_u = *hed_u; - pac_u->bod_u = *bod_u; - pac_u->ore_u = *lan_u; - pac_u->ptr_v = hun_y; - - if ( 0 != sam_u->pac_u ) { - pac_u->nex_u = sam_u->pac_u; - sam_u->pac_u->pre_u = pac_u; - } - sam_u->pac_u = pac_u; - - // if we already know the lane, just forward - // - if ( u3_none != lac ) { - _ames_forward(pac_u, lac); - } - // otherwise, there's space in the scry queue; scry the lane out of ames - // - else { - sam_u->sat_u.foq_d++; - u3_noun pax = u3nq(u3i_string("peers"), - u3dc("scot", 'p', u3i_chubs(2, bod_u->rec_d)), - u3i_string("forward-lane"), - u3_nul); - u3_pier_peek_last(sam_u->pir_u, u3_nul, c3__ax, - u3_nul, pax, pac_u, _ames_lane_scry_cb); - } - } -} - -#undef AMES_SKIP -#ifdef AMES_SKIP -/* _ames_skip(): decide whether to skip this packet, for rescue -*/ -static c3_o -_ames_skip(u3_body* bod_u) { - if ( bod_u->sen_d[1] == 0 && - ( bod_u->sen_d[0] == 0x743a17a6 - || bod_u->sen_d[0] == 0xea99acb6 - || bod_u->sen_d[0] == 0x10100 - ) ) { - return c3n; - } - else { - return c3y; - } -} -#endif - -/* _ames_hear(): parse a (potential) packet, dispatch appropriately. -*/ -static void -_ames_hear(u3_ames* sam_u, - u3_lane* lan_u, - c3_w len_w, - c3_y* hun_y) -{ - u3_head hed_u; - u3_body bod_u; - - // XX packet filtering needs to revised for two protocol-change scenarios - // - // - packets using old protocol versions from our sponsees - // these must be let through, and this is a transitive condition; - // they must also be forwarded where appropriate - // they can be validated, as we know their semantics - // - // - packets using newer protocol versions - // these should probably be let through, or at least - // trigger printfs suggesting upgrade. - // they cannot be filtered, as we do not know their semantics - // - - // unpack header, ensuring buffer is large enough - // - if ( (4 > len_w) - || (c3n == _ames_sift_head(&hed_u, hun_y)) ) - { - sam_u->sat_u.hed_d++; - if ( 0 == (sam_u->sat_u.hed_d % 100000) ) { - u3l_log("ames: %" PRIu64 " dropped, failed to read header", - sam_u->sat_u.hed_d); - } - - c3_free(hun_y); - return; - } - - // ensure the protocol version matches ours - // - // XX rethink use of [fit_o] here and elsewhere - // - if ( (c3y == sam_u->fig_u.fit_o) - && (sam_u->ver_y != hed_u.ver_y) ) - { - sam_u->sat_u.vet_d++; - if ( 0 == (sam_u->sat_u.vet_d % 100000) ) { - u3l_log("ames: %" PRIu64 " dropped for version mismatch", - sam_u->sat_u.vet_d); - } - - c3_free(hun_y); - return; - } - - { - c3_w bod_w = len_w - 4; - c3_y* bod_y = hun_y + 4; - - // unpack and validate the body - // - if ( (c3n == _ames_sift_body(&hed_u, &bod_u, bod_w, bod_y)) ) { - sam_u->sat_u.bod_d++; - if ( 0 == (sam_u->sat_u.bod_d % 100) ) { - u3l_log("ames: %" PRIu64 " dropped, failed to read body", - sam_u->sat_u.bod_d); - } - - c3_free(hun_y); - return; - } - - // ensure the mug is valid - // - if ( bod_u.mug_l != hed_u.mug_l ) { - sam_u->sat_u.mut_d++; - if ( 0 == (sam_u->sat_u.mut_d % 100000) ) { - u3l_log("ames: %" PRIu64 " dropped for invalid mug", - sam_u->sat_u.mut_d); - } - - c3_free(hun_y); - return; - } - } - - // if we can scry, - // and we are not the recipient, - // we might want to forward statelessly - // - if ( (c3y == sam_u->fig_u.see_o) - && ( (bod_u.rec_d[0] != sam_u->pir_u->who_d[0]) - || (bod_u.rec_d[1] != sam_u->pir_u->who_d[1]) ) ) - { - _ames_try_forward(sam_u, lan_u, &hed_u, &bod_u, hun_y); - } - // otherwise, inject the packet as an event - // - else { - u3_noun msg = u3i_bytes(len_w, hun_y); - c3_free(hun_y); -#ifdef AMES_SKIP - if (_ames_skip(&bod_u) == c3y ) { - u3z(msg); - } - else { -#endif - _ames_put_packet(sam_u, msg, *lan_u); -#ifdef AMES_SKIP - } -#endif - } -} - -/* _ames_recv_cb(): udp message receive callback. -*/ -static void -_ames_recv_cb(uv_udp_t* wax_u, - ssize_t nrd_i, - const uv_buf_t * buf_u, - const struct sockaddr* adr_u, - unsigned flg_i) -{ - if ( 0 > nrd_i ) { - if ( u3C.wag_w & u3o_verbose ) { - u3l_log("ames: recv: fail: %s", uv_strerror(nrd_i)); - } - c3_free(buf_u->base); - } - else if ( 0 == nrd_i ) { - c3_free(buf_u->base); - } - else if ( flg_i & UV_UDP_PARTIAL ) { - if ( u3C.wag_w & u3o_verbose ) { - u3l_log("ames: recv: fail: message truncated"); - } - c3_free(buf_u->base); - } - else { - u3_ames* sam_u = wax_u->data; - struct sockaddr_in* add_u = (struct sockaddr_in*)adr_u; - u3_lane lan_u; - - lan_u.por_s = ntohs(add_u->sin_port); - lan_u.pip_w = ntohl(add_u->sin_addr.s_addr); - - // NB: [nrd_i] will never exceed max length from _ames_alloc() - // - _ames_hear(sam_u, &lan_u, (c3_w)nrd_i, (c3_y*)buf_u->base); - } -} - -/* _ames_io_start(): initialize ames I/O. -*/ -static void -_ames_io_start(u3_ames* sam_u) -{ - c3_s por_s = sam_u->pir_u->por_s; - u3_noun who = u3i_chubs(2, sam_u->pir_u->who_d); - u3_noun rac = u3do("clan:title", u3k(who)); - c3_i ret_i; - - if ( c3__czar == rac ) { - c3_y num_y = (c3_y)sam_u->pir_u->who_d[0]; - c3_s zar_s = _ames_czar_port(num_y); - - if ( 0 == por_s ) { - por_s = zar_s; - } - else if ( por_s != zar_s ) { - u3l_log("ames: czar: overriding port %d with -p %d", zar_s, por_s); - u3l_log("ames: czar: WARNING: %d required for discoverability", zar_s); - } - } - - // Bind and stuff. - { - struct sockaddr_in add_u; - c3_i add_i = sizeof(add_u); - - memset(&add_u, 0, sizeof(add_u)); - add_u.sin_family = AF_INET; - add_u.sin_addr.s_addr = _(u3_Host.ops_u.net) ? - htonl(INADDR_ANY) : - htonl(INADDR_LOOPBACK); - add_u.sin_port = htons(por_s); - - if ( (ret_i = uv_udp_bind(&sam_u->wax_u, - (const struct sockaddr*)&add_u, 0)) != 0 ) - { - u3l_log("ames: bind: %s", uv_strerror(ret_i)); - - if ( (c3__czar == rac) && - (UV_EADDRINUSE == ret_i) ) - { - u3l_log(" ...perhaps you've got two copies of vere running?"); - } - - // XX revise - // - u3_pier_bail(u3_king_stub()); - } - - uv_udp_getsockname(&sam_u->wax_u, (struct sockaddr *)&add_u, &add_i); - c3_assert(add_u.sin_port); - - sam_u->pir_u->por_s = ntohs(add_u.sin_port); - } - - if ( c3y == u3_Host.ops_u.net ) { - u3l_log("ames: live on %d", sam_u->pir_u->por_s); - } - else { - u3l_log("ames: live on %d (localhost only)", sam_u->pir_u->por_s); - } - - uv_udp_recv_start(&sam_u->wax_u, _ames_alloc, _ames_recv_cb); - - sam_u->car_u.liv_o = c3y; - u3z(rac); - u3z(who); -} - -/* _ames_ef_turf(): initialize ames I/O on domain(s). -*/ -static void -_ames_ef_turf(u3_ames* sam_u, u3_noun tuf) -{ - if ( u3_nul != tuf ) { - // XX save all for fallback, not just first - // - u3_noun hot = u3k(u3h(tuf)); - c3_w len_w = u3_mcut_host(0, 0, u3k(hot)); - - sam_u->dns_c = c3_malloc(1 + len_w); - u3_mcut_host(sam_u->dns_c, 0, hot); - sam_u->dns_c[len_w] = 0; - - // XX invalidate sam_u->imp_w &c ? - // - - u3z(tuf); - } - else if ( (c3n == sam_u->pir_u->fak_o) && (0 == sam_u->dns_c) ) { - u3l_log("ames: turf: no domains"); - } - - // XX is this ever necessary? - // - if ( c3n == sam_u->car_u.liv_o ) { - _ames_io_start(sam_u); - } -} - -/* _ames_prot_scry_cb(): receive protocol version -*/ -static void -_ames_prot_scry_cb(void* vod_p, u3_noun nun) -{ - u3_ames* sam_u = vod_p; - u3_weak ver = u3r_at(7, nun); - - if ( u3_none == ver ) { - // assume protocol version 0 - // - sam_u->ver_y = 0; - } - else if ( (c3n == u3a_is_cat(ver)) - || (7 < ver) ) { - u3m_p("ames: strange protocol", nun); - sam_u->ver_y = 0; - } - else { - sam_u->ver_y = ver; - } - - // XX revise: filtering should probably be disabled if - // we get a protocol version above the latest one we know - // - sam_u->fig_u.fit_o = c3y; - u3z(nun); -} - -/* _ames_io_talk(): start receiving ames traffic. -*/ -static void -_ames_io_talk(u3_auto* car_u) -{ - u3_ames* sam_u = (u3_ames*)car_u; - _ames_io_start(sam_u); - - // send born event - // - { - // XX remove [sev_l] - // - u3_noun wir = u3nt(c3__newt, - u3dc("scot", c3__uv, sam_u->sev_l), - u3_nul); - u3_noun cad = u3nc(c3__born, u3_nul); - - u3_auto_plan(car_u, u3_ovum_init(0, c3__a, wir, cad)); - } - - // scry the protocol version out of arvo - // - // XX this should be re-triggered periodically, - // or, better yet, %ames should emit a %turf - // (or some other reconfig) effect when it is reset. - // - u3_pier_peek_last(car_u->pir_u, u3_nul, c3__ax, u3_nul, - u3nt(u3i_string("protocol"), u3i_string("version"), u3_nul), - sam_u, _ames_prot_scry_cb); -} - -/* _ames_kick_newt(): apply packet network outputs. -*/ -static c3_o -_ames_kick_newt(u3_ames* sam_u, u3_noun tag, u3_noun dat) -{ - c3_o ret_o; - - switch ( tag ) { - default: { - ret_o = c3n; - } break; - - case c3__send: { - u3_noun lan = u3k(u3h(dat)); - u3_noun pac = u3k(u3t(dat)); - _ames_ef_send(sam_u, lan, pac); - ret_o = c3y; - } break; - - case c3__turf: { - _ames_ef_turf(sam_u, u3k(dat)); - ret_o = c3y; - } break; - } - - u3z(tag); u3z(dat); - return ret_o; -} - -/* _ames_io_kick(): apply effects -*/ -static c3_o -_ames_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) -{ - u3_ames* sam_u = (u3_ames*)car_u; - - u3_noun tag, dat, i_wir; - c3_o ret_o; - - if ( (c3n == u3r_cell(wir, &i_wir, 0)) - || (c3n == u3r_cell(cad, &tag, &dat)) ) - { - ret_o = c3n; - } - else { - switch ( i_wir ) { - default: { - ret_o = c3n; - } break; - - // XX should also be c3__ames - // - case c3__newt: { - ret_o = _ames_kick_newt(sam_u, u3k(tag), u3k(dat)); - } break; - - // XX obsolete - // - // used to also handle %west and %woot for tcp proxy setup - // - case c3__ames: { - ret_o = _( c3__init == tag); - } break; - - // this can return through dill due to our fscked up boot sequence - // - // XX s/b obsolete, verify - // - case c3__term: { - if ( c3__send != tag ) { - ret_o = c3n; - } - else { - u3l_log("kick: strange send"); - ret_o = _ames_kick_newt(sam_u, u3k(tag), u3k(dat)); - } - } break; - } - } - - u3z(wir); u3z(cad); - return ret_o; -} - -/* _ames_exit_cb(): dispose resources aftr close. -*/ -static void -_ames_exit_cb(uv_handle_t* had_u) -{ - u3_ames* sam_u = had_u->data; - - u3_panc* pac_u = sam_u->pac_u; - while (0 != pac_u) { - u3_panc* nex_u = pac_u->nex_u; - _ames_panc_free(pac_u); - pac_u = nex_u; - } - - u3h_free(sam_u->lax_p); - - u3s_cue_xeno_done(sam_u->sil_u); - ur_cue_test_done(sam_u->tes_u); - - c3_free(sam_u); -} - -/* _ames_io_exit(): terminate ames I/O. -*/ -static void -_ames_io_exit(u3_auto* car_u) -{ - u3_ames* sam_u = (u3_ames*)car_u; - uv_close(&sam_u->had_u, _ames_exit_cb); -} - -/* _ames_io_info(): produce status info. -*/ -static u3_noun -_ames_io_info(u3_auto* car_u) -{ - u3_ames* sam_u = (u3_ames*)car_u; - - return u3i_list( - u3_pier_mase("filtering", sam_u->fig_u.fit_o), - u3_pier_mase("can-send", sam_u->fig_u.net_o), - u3_pier_mase("can-scry", sam_u->fig_u.see_o), - u3_pier_mase("dropped", u3i_chub(sam_u->sat_u.dop_d)), - u3_pier_mase("forwards-dropped", u3i_chub(sam_u->sat_u.fod_d)), - u3_pier_mase("forwards-pending", u3i_chub(sam_u->sat_u.foq_d)), - u3_pier_mase("forwarded", u3i_chub(sam_u->sat_u.fow_d)), - u3_pier_mase("filtered-hed", u3i_chub(sam_u->sat_u.hed_d)), - u3_pier_mase("filtered-ver", u3i_chub(sam_u->sat_u.vet_d)), - u3_pier_mase("filtered-mug", u3i_chub(sam_u->sat_u.mut_d)), - u3_pier_mase("filtered-bod", u3i_chub(sam_u->sat_u.bod_d)), - u3_pier_mase("crashed", u3i_chub(sam_u->sat_u.fal_d)), - u3_pier_mase("cached-lanes", u3i_word(u3h_wyt(sam_u->lax_p))), - u3_none); -} - -/* _ames_io_slog(): print status info. -*/ -static void -_ames_io_slog(u3_auto* car_u) -{ - u3_ames* sam_u = (u3_ames*)car_u; - -# define FLAG(a) ( (c3y == a) ? "&" : "|" ) - - // TODO rewrite in terms of info_f - // - u3l_log(" config:"); - u3l_log(" filtering: %s", FLAG(sam_u->fig_u.fit_o)); - u3l_log(" can send: %s", FLAG(sam_u->fig_u.net_o)); - u3l_log(" can scry: %s", FLAG(sam_u->fig_u.see_o)); - u3l_log(" counters:"); - u3l_log(" dropped: %" PRIu64, sam_u->sat_u.dop_d); - u3l_log(" forwards dropped: %" PRIu64, sam_u->sat_u.fod_d); - u3l_log(" forwards pending: %" PRIu64, sam_u->sat_u.foq_d); - u3l_log(" forwarded: %" PRIu64, sam_u->sat_u.fow_d); - u3l_log(" filtered (hed): %" PRIu64, sam_u->sat_u.hed_d); - u3l_log(" filtered (ver): %" PRIu64, sam_u->sat_u.vet_d); - u3l_log(" filtered (mug): %" PRIu64, sam_u->sat_u.mut_d); - u3l_log(" filtered (bod): %" PRIu64, sam_u->sat_u.bod_d); - u3l_log(" crashed: %" PRIu64, sam_u->sat_u.fal_d); - u3l_log(" cached lanes: %u", u3h_wyt(sam_u->lax_p)); -} - -/* u3_ames_io_init(): initialize ames I/O. -*/ -u3_auto* -u3_ames_io_init(u3_pier* pir_u) -{ - u3_ames* sam_u = c3_calloc(sizeof(*sam_u)); - sam_u->pir_u = pir_u; - sam_u->fig_u.net_o = c3y; - sam_u->fig_u.see_o = c3y; - sam_u->fig_u.fit_o = c3n; - - //NOTE some numbers on memory usage for the lane cache - // - // assuming we store: - // a (list lane) with 1 item, 1+8 + 1 + (6*2) = 22 words - // and a @da as timestamp, 8 words - // consed together, 6 words - // with worst-case (128-bit) @p keys, 8 words - // and an additional cell for the k-v pair, 6 words - // that makes for a per-entry memory use of 50 words => 200 bytes - // - // the 500k entries below would take about 100mb (in the worst case, but - // not accounting for hashtable overhead). - // we could afford more, but 500k entries is more than we'll likely use - // in the near future. - // - sam_u->lax_p = u3h_new_cache(500000); - - c3_assert( !uv_udp_init(u3L, &sam_u->wax_u) ); - sam_u->wax_u.data = sam_u; - - sam_u->sil_u = u3s_cue_xeno_init(); - sam_u->tes_u = ur_cue_test_init(); - - // Disable networking for fake ships - // - if ( c3y == sam_u->pir_u->fak_o ) { - u3_Host.ops_u.net = c3n; - } - - u3_auto* car_u = &sam_u->car_u; - car_u->nam_m = c3__ames; - car_u->liv_o = c3n; - car_u->io.talk_f = _ames_io_talk; - car_u->io.info_f = _ames_io_info; - car_u->io.slog_f = _ames_io_slog; - car_u->io.kick_f = _ames_io_kick; - car_u->io.exit_f = _ames_io_exit; - - { - u3_noun now; - struct timeval tim_u; - gettimeofday(&tim_u, 0); - - now = u3_time_in_tv(&tim_u); - sam_u->sev_l = u3r_mug(now); - u3z(now); - } - - return car_u; -} diff --git a/pkg/urbit/vere/io/behn.c b/pkg/urbit/vere/io/behn.c deleted file mode 100644 index 7f42805a3..000000000 --- a/pkg/urbit/vere/io/behn.c +++ /dev/null @@ -1,254 +0,0 @@ -/* vere/behn.c -** -*/ -#include "all.h" -#include "vere/vere.h" - -/* u3_behn: just a timer for ever -*/ - typedef struct _u3_behn { - u3_auto car_u; // driver - uv_timer_t tim_u; // behn timer - c3_o alm_o; // alarm - c3_l sev_l; // instance numbers - } u3_behn; - -// XX review, move -// -/* _behn_bail_dire(): c3y if fatal error. RETAIN -*/ -static c3_o -_behn_bail_dire(u3_noun lud) -{ - u3_noun mot = u3r_at(4, lud); - - if ( (c3__meme == mot) - || (c3__intr == mot) ) - { - return c3n; - } - - return c3y; -} - -/* _behn_wake_bail(): %wake is essential, retry failures. -*/ -static void -_behn_wake_bail(u3_ovum* egg_u, u3_noun lud) -{ - u3_auto* car_u = egg_u->car_u; - - if ( (2 > egg_u->try_w) - && (c3n == _behn_bail_dire(lud)) ) - { - u3z(lud); - u3_auto_redo(car_u, egg_u); - } - else { - u3_auto_bail_slog(egg_u, lud); - u3_ovum_free(egg_u); - - u3l_log("behn: timer failed; queue blocked"); - - // XX review, add flag to continue? - // - u3_pier_bail(car_u->pir_u); - } -} - -/* _behn_time_cb(): timer callback. -*/ -static void -_behn_time_cb(uv_timer_t* tim_u) -{ - u3_behn* teh_u = tim_u->data; - teh_u->alm_o = c3n; - - // start another timer for 10 minutes - // - // This is a backstop to deal with the case where a %doze is not - // properly sent, for example after a crash. If the timer continues - // to fail, we can't proceed with the timers, but if it was a - // transient error, this will get us past it. - // - { - c3_d gap_d = 10 * 60 * 1000; - teh_u->alm_o = c3y; - uv_timer_start(&teh_u->tim_u, _behn_time_cb, gap_d, 0); - } - - // send timer event - // - { - u3_noun wir = u3nc(c3__behn, u3_nul); - u3_noun cad = u3nc(c3__wake, u3_nul); - - u3_auto_peer( - u3_auto_plan(&teh_u->car_u, u3_ovum_init(0, c3__b, wir, cad)), - 0, 0, _behn_wake_bail); - } -} - -/* u3_behn_ef_doze(): set or cancel timer -*/ -static void -_behn_ef_doze(u3_behn* teh_u, u3_noun wen) -{ - if ( c3n == teh_u->car_u.liv_o ) { - teh_u->car_u.liv_o = c3y; - } - - if ( c3y == teh_u->alm_o ) { - uv_timer_stop(&teh_u->tim_u); - teh_u->alm_o = c3n; - } - - if ( (u3_nul != wen) && - (c3y == u3du(wen)) && - (c3y == u3ud(u3t(wen))) ) - { - struct timeval tim_tv; - gettimeofday(&tim_tv, 0); - - u3_noun now = u3_time_in_tv(&tim_tv); - c3_d gap_d = u3_time_gap_ms(now, u3k(u3t(wen))); - - teh_u->alm_o = c3y; - uv_timer_start(&teh_u->tim_u, _behn_time_cb, gap_d, 0); - } - - u3z(wen); -} - -/* _behn_born_news(): initialization complete on %born. -*/ -static void -_behn_born_news(u3_ovum* egg_u, u3_ovum_news new_e) -{ - u3_auto* car_u = egg_u->car_u; - - if ( u3_ovum_done == new_e ) { - car_u->liv_o = c3y; - } -} - -/* _behn_born_bail(): %born is essential, retry failures. -*/ -static void -_behn_born_bail(u3_ovum* egg_u, u3_noun lud) -{ - u3_auto* car_u = egg_u->car_u; - - if ( (2 > egg_u->try_w) - && (c3n == _behn_bail_dire(lud)) ) - { - u3z(lud); - u3_auto_redo(car_u, egg_u); - } - else { - u3_auto_bail_slog(egg_u, lud); - u3_ovum_free(egg_u); - - u3l_log("behn: initialization failed"); - - // XX review, add flag to continue? - // - u3_pier_bail(car_u->pir_u); - } -} -/* _behn_io_talk(): notify %behn that we're live -*/ -static void -_behn_io_talk(u3_auto* car_u) -{ - u3_behn* teh_u = (u3_behn*)car_u; - - // XX remove [sev_l] - // - u3_noun wir = u3nt(c3__behn, - u3dc("scot", c3__uv, teh_u->sev_l), - u3_nul); - u3_noun cad = u3nc(c3__born, u3_nul); - - u3_auto_peer( - u3_auto_plan(car_u, u3_ovum_init(0, c3__b, wir, cad)), - 0, - _behn_born_news, - _behn_born_bail); -} - -/* _behn_io_kick(): apply effects. -*/ -static c3_o -_behn_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) -{ - u3_behn* teh_u = (u3_behn*)car_u; - - u3_noun tag, dat, i_wir; - c3_o ret_o; - - if ( (c3n == u3r_cell(wir, &i_wir, 0)) - || (c3n == u3r_cell(cad, &tag, &dat)) - || (c3__behn != i_wir) - || (c3__doze != tag) ) - { - ret_o = c3n; - } - else { - ret_o = c3y; - _behn_ef_doze(teh_u, u3k(dat)); - } - - u3z(wir); u3z(cad); - return ret_o; -} - -/* _behn_exit_cb(); -*/ -static void -_behn_exit_cb(uv_timer_t* tim_u) -{ - u3_behn* teh_u = tim_u->data; - c3_free(teh_u); -} - -/* _behn_io_exit(): terminate timer. -*/ -static void -_behn_io_exit(u3_auto* car_u) -{ - u3_behn* teh_u = (u3_behn*)car_u; - uv_close((uv_handle_t*)&teh_u->tim_u, (uv_close_cb)_behn_exit_cb); -} - -/* u3_behn(): initialize time timer. -*/ -u3_auto* -u3_behn_io_init(u3_pier* pir_u) -{ - u3_behn* teh_u = c3_calloc(sizeof(*teh_u)); - teh_u->alm_o = c3n; - - uv_timer_init(u3L, &teh_u->tim_u); - teh_u->tim_u.data = teh_u; - - u3_auto* car_u = &teh_u->car_u; - car_u->nam_m = c3__behn; - - car_u->liv_o = c3n; - car_u->io.talk_f = _behn_io_talk; - car_u->io.kick_f = _behn_io_kick; - car_u->io.exit_f = _behn_io_exit; - - { - u3_noun now; - struct timeval tim_u; - gettimeofday(&tim_u, 0); - - now = u3_time_in_tv(&tim_u); - teh_u->sev_l = u3r_mug(now); - u3z(now); - } - - return car_u; -} diff --git a/pkg/urbit/vere/io/conn.c b/pkg/urbit/vere/io/conn.c deleted file mode 100644 index 86d9087ff..000000000 --- a/pkg/urbit/vere/io/conn.c +++ /dev/null @@ -1,920 +0,0 @@ -/* vere/conn.c -** -** implements the control plane: a socket that can be used to -** query and interact with an urbit ship from earth. -** -** the control plane nominally consumes input described by: -** -** $: request-id=@ :: id for response -** $% [%fyrd fyrd-args=*] :: run a thread -** [%peek peek-args=*] :: scry -** [%peel peel-args=*] :: runtime peek -** [%ovum ovum-args=*] :: inject raw ovum -** [%urth urth-args=*] :: runtime command -** == == :: -** -** request-id is a client-supplied atomic identifier that will -** be returned along with the response, to allow correlating -** responses with requests. -** -** responses are [request-id=@ data=*]. if the driver encounters -** an error, then it will try to send a %bail response with -** request-id set to 0, i.e.: -** -** [0 %bail error-code=@ error-string=@t] -** -** and subsequently close the connection. -** -** %fyrd is a request to run a thread. its arguments are -** described in the ++khan section of sys/lull.hoon. to -** summarize: -** -** +$ task $%(... [%fyrd p=(fyrd cast)]) :: -** +$ bear $@(desk beak) :: partial $beak -** +$ cast (pair mark page) :: output mark +input -** ++ fyrd |$ [a] [=bear name=term args=a] :: thread run request -** -** the cast's mark is applied to the output. the page (untyped -** cage, or pair of mark and noun) in args contains the input -** mark. e.g. to run -hi with the ship ~zod as input, receiving -** output as a tape, with request-id set to 32, send the +jam of -** this noun over the socket with newt framing: -** -** [32 %fyrd [%base %hi %tape [%ship ~zod]]] -** -** responses to %fyrd are: -** -** +$ gift $%(... [%avow p=(avow page)]) :: -** ++ avow |$ [a] (each a goof) :: -** -** %peek is a namespace read request (aka scry), and will be -** forwarded directly to arvo. its arguments are the nom of the -** external peek interface in arvo, at arm 22. (lyc is always -** `~, i.e. request from self.) that is: -** -** $+ each path -** $% [%once vis=view syd=desk tyl=spur] -** [%beam vis=view bem=beam] -** == -** -** %peel is a runtime "peek". it exposes an unprincipled -** scry-like namespace allowing querying of various metrics -** about the state of vere. it accepts $path-like arguments, -** i.e. nul-terminated lists of $knot. it responds with a -** (unit). -** -** the %peel path /help produces a list of available commands. -** /info produces runtime metrics at the moment in time that the -** request was received. the type produced by /info is $mass: -** -** +$ mass (pair cord (each * (list mass))) -** -** where the leaves are conventionally @ud, but the -** precise interpretation depends on the metric (e.g. -** loobean settings or integer counters.) it is acceptable -** to flatten the list by prepending the parent cord -** to each child element with a separator, e.g.: -** [%pier %| [%ames %| [%packets-sent %& 37] ~] ~] could be -** rendered as 'pier-ames-packets-sent'. this transformation is -** guaranteed to result in unique names. -** -** %ovum is a raw kernel move, to be injected directly into -** arvo. needless to say this will void your warranty. usually -** you want to use %fyrd instead. an update will be sent: %done -** on successful completion, %bail with a stack trace on error, -** or %drop if the ovum is dropped. -** -** %urth is a command for the runtime. these are acked with %.y -** on receipt. no further updates are provided. -** -** messages use newt framing. because the framing begins with -** a tag byte, any messages that do not contain that byte are -** reserved for future use. -** -*/ -#include -#include -#include -#include -#include -#include - -#include "all.h" -#include "vere/vere.h" - -/* u3_cran: control plane request. -*/ - typedef struct _u3_cran { - u3_atom rid; // client-supplied request id - struct _u3_chan* can_u; // connection backpointer - struct _u3_cran* nex_u; // next pointer - } u3_cran; - -/* u3_chan: incoming control plane connection. -*/ - typedef struct _u3_chan { - struct _u3_moor mor_u; // message handler - c3_l coq_l; // connection number - c3_o liv_o; // connection live - struct _u3_shan* san_u; // server backpointer - struct _u3_cran* ran_u; // request list - } u3_chan; - -/* u3_shan: control plane server. -*/ - typedef struct _u3_shan { - uv_pipe_t pyp_u; // server stream handler - c3_l nex_l; // next connection number - struct _u3_conn* con_u; // device backpointer - struct _u3_chan* can_u; // connection list - } u3_shan; - -/* u3_conn: control plane device. -*/ - typedef struct _u3_conn { - u3_auto car_u; // driver - c3_l sev_l; // instance number - struct _u3_shan* san_u; // server reference - u3_cue_xeno* sil_u; // cue handle - c3_o kan_o; // %khan present? - } u3_conn; - -static const c3_c URB_SOCK_PATH[] = ".urb/conn.sock"; - -/* _conn_close_cb(): socket close callback. -*/ -static void -_conn_close_cb(uv_handle_t* had_u) -{ - c3_free(had_u); -} - -/* _conn_mote_free(): u3_moat-shaped close callback. -*/ -static void -_conn_moat_free(void* ptr_v, ssize_t err_i, const c3_c* err_c) -{ - c3_free(ptr_v); -} - -/* _conn_send_noun(): jam and send noun over chan. -*/ -static void -_conn_send_noun(u3_chan* can_u, u3_noun nun) -{ - c3_y* byt_y; - c3_d len_d; - - u3s_jam_xeno(nun, &len_d, &byt_y); - u3z(nun); - u3_newt_send((u3_mojo*)&can_u->mor_u, len_d, byt_y); -} - -/* _conn_find_chan(): lookup channel by connection number. -*/ -static u3_chan* -_conn_find_chan(u3_conn* con_u, c3_l sev_l, c3_l coq_l) -{ - u3_chan* ret_u; - - for ( ret_u = con_u->san_u->can_u; - ret_u; - ret_u = (u3_chan*)ret_u->mor_u.nex_u ) { - if ( coq_l == ret_u->coq_l ) { - return ret_u; - } - } - return 0; -} - -/* _conn_read_wire(): check tag, decompose wire into /sev/coq/rid -*/ -static c3_o -_conn_read_wire(u3_noun wir, - c3_l tag_l, - c3_l* sev_l, - c3_l* coq_l, - u3_atom* rid) -{ - u3_noun i_wir, t_wir; - - if ( (c3n == u3r_cell(wir, &i_wir, &t_wir)) || - (tag_l != i_wir) ) - { - u3z(wir); return c3n; - } - else { - u3_noun pud = t_wir; - u3_noun p_pud, t_pud, tt_pud, q_pud, r_pud, s_pud, - uco, p_uco, q_uco; - - if ( (c3n == u3r_cell(pud, &p_pud, &t_pud)) || - (c3n == u3v_lily(c3__uv, u3k(p_pud), sev_l)) ) - { - u3z(wir); return c3n; - } - if ( u3_nul == t_pud ) { - *coq_l = 0; *rid = 0; - } - else { - if ( (c3n == u3r_cell(t_pud, &q_pud, &tt_pud)) || - (c3n == u3v_lily(c3__ud, u3k(q_pud), coq_l)) ) - { - u3z(wir); return c3n; - } - if ( u3_nul == tt_pud ) { - *rid = 0; - } - else { - if ( (c3n == u3r_cell(tt_pud, &r_pud, &s_pud)) || - (u3_nul != s_pud) || - (c3n == u3ud(r_pud)) ) - { - u3z(wir); return c3n; - } - uco = u3dc("slaw", c3__uv, u3k(r_pud)); - if ( (c3n == u3r_cell(uco, &p_uco, &q_uco)) || - (u3_nul != p_uco) ) - { - u3z(uco); u3z(wir); return c3n; - } - *rid = u3k(q_uco); - u3z(uco); - } - } - u3z(wir); return c3y; - } -} - -/* _conn_poke_bail(): error function on failed %fyrd. -*/ -static void -_conn_poke_bail(u3_ovum* egg_u, u3_noun lud) -{ - u3_conn* con_u = (u3_conn*)egg_u->car_u; - u3_chan* can_u; - u3_noun wir = egg_u->wir; - c3_l sev_l, coq_l; - u3_atom rid; - - u3_auto_bail_slog(egg_u, u3k(lud)); - if ( (c3n == _conn_read_wire(u3k(wir), c3__khan, &sev_l, &coq_l, &rid)) || - (con_u->sev_l != sev_l) ) - { - // wtf? - // - c3_assert(!"not reached"); - u3z(lud); return; - } - can_u = _conn_find_chan(con_u, sev_l, coq_l); - if ( can_u ) { - _conn_send_noun(can_u, u3nt(rid, c3__bail, lud)); - } - else { - u3z(rid); u3z(lud); - } - u3_ovum_free(egg_u); -} - -/* _conn_close_chan(): close given channel, freeing. -*/ -static void -_conn_close_chan(u3_shan* san_u, u3_chan* can_u) -{ - u3_conn* con_u = san_u->con_u; - u3_chan* inn_u; - u3_cran* ran_u; - - // unset chan on all pending requests. - // - for ( ran_u = can_u->ran_u; ran_u; ran_u = ran_u->nex_u ) { - ran_u->can_u = 0; - } - - // remove chan from server's connection list. - // - if ( san_u->can_u == can_u ) { - san_u->can_u = (u3_chan*)can_u->mor_u.nex_u; - } - else { - for ( inn_u = san_u->can_u; inn_u; inn_u = (u3_chan*)inn_u->mor_u.nex_u ) { - if ( (u3_chan*)inn_u->mor_u.nex_u == can_u ) { - inn_u->mor_u.nex_u = can_u->mor_u.nex_u; - break; - } - } - } - can_u->mor_u.nex_u = NULL; - - // send a close event to arvo and stop reading. - // - if ( _(con_u->kan_o) ) { - u3_noun wir, cad; - - wir = u3nq(c3__khan, - u3dc("scot", c3__uv, con_u->sev_l), - u3dc("scot", c3__ud, can_u->coq_l), - u3_nul); - cad = u3nc(c3__done, u3_nul); - u3_auto_peer( - u3_auto_plan(&con_u->car_u, - u3_ovum_init(0, c3__k, wir, cad)), - 0, 0, _conn_poke_bail); - } - u3_newt_moat_stop((u3_moat*)&can_u->mor_u, _conn_moat_free); -} - -/* _conn_moor_bail(): error callback for u3_moor. -*/ -static void -_conn_moor_bail(void* ptr_v, ssize_t err_i, const c3_c* err_c) -{ - u3_chan* can_u = (u3_chan*)ptr_v; - u3_shan* san_u = can_u->san_u; - - if ( err_i != UV_EOF ) { - u3l_log("conn: moor bail %zd %s", err_i, err_c); - if ( _(can_u->liv_o) ) { - _conn_send_noun(can_u, u3nq(0, c3__bail, u3i_word(err_i), - u3i_string(err_c))); - can_u->liv_o = c3n; - } - } - _conn_close_chan(san_u, can_u); -} - -/* _conn_drop_cran(): finalize/remove request from chan (does not u3z rid.) -*/ -static void -_conn_drop_cran(u3_chan* can_u, u3_cran* ran_u) -{ - u3_cran* inn_u; - - // remove from pending list, special-case for head. - // - if ( ran_u == can_u->ran_u ) { - can_u->ran_u = ran_u->nex_u; - } - else { - for ( inn_u = can_u->ran_u; inn_u; inn_u = inn_u->nex_u ) { - if ( ran_u == inn_u->nex_u ) { - inn_u->nex_u = ran_u->nex_u; - break; - } - } - } - c3_free(ran_u); -} - -/* _conn_peek_cb(): scry result handler. -*/ -static void -_conn_peek_cb(void* ptr_v, u3_noun res) -{ - u3_cran* ran_u = (u3_cran*)ptr_v; - u3_chan* can_u = ran_u->can_u; - - if ( !can_u ) { - // chan was closed; noop. - // - u3z(ran_u->rid); c3_free(ran_u); - u3z(res); return; - } - _conn_send_noun(can_u, u3nt(ran_u->rid, c3__peek, res)); - _conn_drop_cran(can_u, ran_u); -} - -/* _conn_ovum_bail(): bail callback on injected event. -*/ -static void -_conn_ovum_bail(u3_ovum* egg_u, u3_noun lud) -{ - u3_cran* ran_u = egg_u->ptr_v; - u3_chan* can_u = ran_u->can_u; - - u3_auto_bail_slog(egg_u, u3k(lud)); - if ( !can_u ) { - // chan was closed; noop. - // - u3z(ran_u->rid); c3_free(ran_u); - u3z(lud); return; - } - _conn_send_noun(can_u, u3nt(ran_u->rid, c3__bail, lud)); - _conn_drop_cran(can_u, ran_u); - u3_ovum_free(egg_u); -} - -/* _conn_ovum_news(): lifecycle callback for injected events. -*/ -static void -_conn_ovum_news(u3_ovum* egg_u, u3_ovum_news new_e) -{ - u3_cran* ran_u = egg_u->ptr_v; - u3_chan* can_u = ran_u->can_u; - - if ( u3_ovum_done == new_e || - u3_ovum_drop == new_e ) - { - if ( can_u ) { - _conn_send_noun(can_u, - u3nt(ran_u->rid, c3__news, - ( u3_ovum_done == new_e - ? c3__done - : c3__drop ))); - _conn_drop_cran(can_u, ran_u); - } - else { - u3z(ran_u->rid); c3_free(ran_u); - } - } -} - -/* _conn_read_peel(): response to a %peel request, sans rid. -*/ -static u3_noun -_conn_read_peel(u3_conn* con_u, u3_noun dat) -{ - u3_pier* pir_u = con_u->car_u.pir_u; - u3_noun i_dat, t_dat, it_dat, tt_dat; - u3_noun res; - - if ( c3n == u3r_cell(dat, &i_dat, &t_dat) ) { - res = u3_nul; - } - else if ( u3_nul == t_dat ) { - // zero-argument requests. - // - switch (i_dat) { - default: { - res = u3_nul; - } break; - // command list. - // - case c3__help: { - res = u3nc( - u3_nul, - u3i_list(u3nc(c3__help, u3_nul), u3nc(c3__info, u3_nul), - u3nc(c3__khan, u3_nul), u3nc(c3__live, u3_nul), - u3nc(c3__mass, u3_nul), - u3nc(c3__port, - u3i_list(c3__ames, c3__htls, c3__http, u3_none)), - u3nc(c3__v, u3_nul), u3nc(c3__who, u3_nul), - u3_none)); - } break; - // simple health check. - // - case c3__live: { - res = u3nc(u3_nul, pir_u->liv_o); - } break; - // true iff the %khan vane is live (meaning %fyrd is supported.) - // - case c3__khan: { - res = u3nc(u3_nul, con_u->kan_o); - } break; - // |mass output - // - case c3__mass: { - // TODO |mass - // - res = u3_nul; - } break; - // runtime metrics. - // - case c3__info: { - res = u3nc(u3_nul, u3_pier_info(pir_u)); - } break; - // vere version. - // - case c3__v: { - res = u3nc(u3_nul, u3i_string(URBIT_VERSION)); - } break; - // current ship. - // - case c3__who: { - res = u3nc(u3_nul, u3i_chubs(2, pir_u->who_d)); - } - } - } - else if ( c3n == u3r_cell(t_dat, &it_dat, &tt_dat) ) { - res = u3_nul; - } - else if ( u3_nul == tt_dat ) { - // one-argument requests. - // - switch (i_dat) { - default: { - res = u3_nul; - } break; - case c3__port: { - switch (it_dat) { - default: { - res = u3_nul; - } break; - case c3__ames: { - res = u3nc(u3_nul, pir_u->por_s); - } break; - case c3__htls: { - res = u3nc(u3_nul, pir_u->pes_s); - } break; - case c3__http: { - res = u3nc(u3_nul, pir_u->per_s); - } break; - } - } break; - } - } - else { - res = u3_nul; - } - u3z(dat); return res; -} - -/* _conn_make_cran(): alloc/init new request. -*/ -static u3_cran* -_conn_make_cran(u3_chan* can_u, u3_atom rid) -{ - u3_cran* ran_u = c3_calloc(sizeof(*ran_u)); - - ran_u->rid = rid; - ran_u->can_u = can_u; - ran_u->nex_u = can_u->ran_u; - can_u->ran_u = ran_u; - return ran_u; -} - -/* _conn_moor_poke(): called on message read from u3_moor. -*/ -static void -_conn_moor_poke(void* ptr_v, c3_d len_d, c3_y* byt_y) -{ - u3_weak jar; - u3_noun can, rid, tag, dat, rud = u3_nul, tar, wir, cad; - u3_chan* can_u = (u3_chan*)ptr_v; - u3_conn* con_u = can_u->san_u->con_u; - c3_i err_i = 0; - c3_c* err_c; - c3_c* tag_c; - c3_c* rid_c; - - jar = u3s_cue_xeno_with(con_u->sil_u, len_d, byt_y); - if ( u3_none == jar ) { - can_u->mor_u.bal_f(can_u, -1, "cue-none"); - return; - } - if ( (c3n == u3r_cell(jar, &rid, &can)) || - (c3n == u3r_cell(can, &tag, &dat)) || - (c3n == u3ud(rid)) ) - { - err_i = -2; err_c = "jar-bad"; - goto _moor_poke_out; - } - - rud = u3dc("scot", c3__uv, u3k(rid)); - tag_c = u3r_string(tag); - rid_c = u3r_string(rud); - u3l_log("conn: %s %s", tag_c, rid_c); - c3_free(tag_c); c3_free(rid_c); - - switch (tag) { - default: { - err_i = -3; err_c = "tag-unknown"; - goto _moor_poke_out; - } break; - - case c3__fyrd: { - if ( c3n == con_u->kan_o ) { - err_i = -8; err_c = "khan-miss"; - goto _moor_poke_out; - } - wir = u3nc(c3__khan, - u3nq(u3dc("scot", c3__uv, con_u->sev_l), - u3dc("scot", c3__ud, can_u->coq_l), u3k(rud), u3_nul)); - u3_auto_peer( - u3_auto_plan(&con_u->car_u, - u3_ovum_init(0, c3__k, wir, u3k(can))), - 0, 0, _conn_poke_bail); - } break; - - case c3__peek: { - u3_pier_peek(con_u->car_u.pir_u, u3nc(u3_nul, u3_nul), u3k(dat), - _conn_make_cran(can_u, u3k(rid)), _conn_peek_cb); - } break; - - case c3__peel: { - _conn_send_noun( - can_u, u3nc(u3k(rid), _conn_read_peel(con_u, u3k(dat)))); - } break; - - case c3__ovum: { - if ( (c3n == u3r_trel(dat, &tar, &wir, &cad)) ) { - err_i = -6; err_c = "ovum-bad"; - goto _moor_poke_out; - } - u3_auto_peer( - u3_auto_plan(&con_u->car_u, - u3_ovum_init(0, u3k(tar), u3k(wir), u3k(cad))), - _conn_make_cran(can_u, u3k(rid)), _conn_ovum_news, _conn_ovum_bail); - } break; - - case c3__urth: { - switch (dat) { - default: { - err_i = -7; err_c = "urth-bad"; - goto _moor_poke_out; - } break; - case c3__meld: { - _conn_send_noun(can_u, u3nc(u3k(rid), c3y)); - u3_pier_meld(con_u->car_u.pir_u); - } break; - case c3__pack: { - _conn_send_noun(can_u, u3nc(u3k(rid), c3y)); - u3_pier_pack(con_u->car_u.pir_u); - } break; - } - } break; - } -_moor_poke_out: - u3z(rud); u3z(jar); - if ( 0 != err_i ) { - can_u->mor_u.bal_f(can_u, err_i, err_c); - } -} - -/* _conn_sock_cb(): socket connection callback. -*/ -static void -_conn_sock_cb(uv_stream_t* sem_u, c3_i tas_i) -{ - u3_shan* san_u = (u3_shan*)sem_u; - u3_conn* con_u = san_u->con_u; - u3_chan* can_u; - c3_i err_i; - - can_u = c3_calloc(sizeof(u3_chan)); - can_u->mor_u.ptr_v = can_u; - can_u->mor_u.pok_f = _conn_moor_poke; - can_u->mor_u.bal_f = _conn_moor_bail; - can_u->coq_l = san_u->nex_l++; - can_u->san_u = san_u; - err_i = uv_timer_init(u3L, &can_u->mor_u.tim_u); - c3_assert(!err_i); - err_i = uv_pipe_init(u3L, &can_u->mor_u.pyp_u, 0); - c3_assert(!err_i); - err_i = uv_accept(sem_u, (uv_stream_t*)&can_u->mor_u.pyp_u); - c3_assert(!err_i); - u3_newt_read((u3_moat*)&can_u->mor_u); - can_u->mor_u.nex_u = (u3_moor*)san_u->can_u; - san_u->can_u = can_u; -} - -/* _conn_init_sock(): initialize socket device. -*/ -static void -_conn_init_sock(u3_shan* san_u) -{ -#ifdef _WIN32 - u3_pier* pir_u = san_u->con_u->car_u.pir_u; - u3_atom who = u3dc("scot", c3__p, u3i_chubs(2, pir_u->who_d)); - c3_c* who_c = u3r_string(who); - c3_c pip_c[256]; - c3_i ret_i; - - u3z(who); - ret_i = snprintf(pip_c, sizeof(pip_c), "\\\\.\\pipe\\urbit-conn-%s", who_c + 1); - c3_assert(19 + strlen(who_c) == ret_i); - c3_free(who_c); - ret_i = uv_pipe_init(u3L, &san_u->pyp_u, 0); - c3_assert(!ret_i); - ret_i = uv_pipe_bind(&san_u->pyp_u, pip_c); - c3_assert(!ret_i); - ret_i = uv_listen((uv_stream_t*)&san_u->pyp_u, 0, _conn_sock_cb); - c3_assert(!ret_i); - u3l_log("conn: listening on %s", pip_c); - -#else // _WIN32 - // the full socket path is limited to about 108 characters, - // and we want it to be relative to the pier. save our current - // path, chdir to the pier, open the socket at the desired - // path, then chdir back. hopefully there aren't any threads. - // - c3_c pax_c[2048]; - c3_i err_i; - - if ( NULL == getcwd(pax_c, sizeof(pax_c)) ) { - u3l_log("conn: getcwd: %s", uv_strerror(errno)); - u3_king_bail(); - } - if ( 0 != chdir(u3_Host.dir_c) ) { - u3l_log("conn: chdir: %s", uv_strerror(errno)); - u3_king_bail(); - } - if ( 0 != unlink(URB_SOCK_PATH) && errno != ENOENT ) { - u3l_log("conn: unlink: %s", uv_strerror(errno)); - goto _conn_sock_err_chdir; - } - if ( 0 != (err_i = uv_pipe_init(u3L, &san_u->pyp_u, 0)) ) { - u3l_log("conn: uv_pipe_init: %s", uv_strerror(err_i)); - goto _conn_sock_err_chdir; - } - if ( 0 != (err_i = uv_pipe_bind(&san_u->pyp_u, URB_SOCK_PATH)) ) { - u3l_log("conn: uv_pipe_bind: %s", uv_strerror(err_i)); - goto _conn_sock_err_chdir; - } - if ( 0 != (err_i = uv_listen((uv_stream_t*)&san_u->pyp_u, 0, - _conn_sock_cb)) ) { - u3l_log("conn: uv_listen: %s", uv_strerror(err_i)); - goto _conn_sock_err_unlink; - } - if ( 0 != chdir(pax_c) ) { - u3l_log("conn: chdir: %s", uv_strerror(errno)); - goto _conn_sock_err_close; - } - u3l_log("conn: listening on %s/%s", u3_Host.dir_c, URB_SOCK_PATH); - return; - -_conn_sock_err_close: - uv_close((uv_handle_t*)&san_u->pyp_u, _conn_close_cb); -_conn_sock_err_unlink: - if ( 0 != unlink(URB_SOCK_PATH) ) { - u3l_log("conn: unlink: %s", uv_strerror(errno)); - } -_conn_sock_err_chdir: - if ( 0 != chdir(pax_c) ) { - u3l_log("conn: chdir: %s", uv_strerror(errno)); - } - u3_king_bail(); -#endif // _WIN32 -} - -/* _conn_born_news(): initialization complete; %khan available. -*/ -static void -_conn_born_news(u3_ovum* egg_u, u3_ovum_news new_e) -{ - u3_conn* con_u = (u3_conn*)egg_u->car_u; - - if ( u3_ovum_done == new_e ) { - con_u->kan_o = c3y; - } -} - -/* _conn_born_bail(): nonessential failure; log it and keep going. -*/ -static void -_conn_born_bail(u3_ovum* egg_u, u3_noun lud) -{ - u3l_log("conn: %%born failure; %%fyrd not supported"); - u3z(lud); - u3_ovum_free(egg_u); -} - -/* _conn_io_talk(): open socket and notify %khan that we're live. -*/ -static void -_conn_io_talk(u3_auto* car_u) -{ - u3_conn* con_u = (u3_conn*)car_u; - u3_shan* san_u; - u3_noun wir = u3nt(c3__khan, - u3dc("scot", c3__uv, con_u->sev_l), - u3_nul); - u3_noun cad = u3nc(c3__born, u3_nul); - - u3_auto_peer( - u3_auto_plan(car_u, u3_ovum_init(0, c3__k, wir, cad)), - 0, - _conn_born_news, - _conn_born_bail); - - // initialize server, opening socket. - // - c3_assert(!con_u->san_u); - san_u = c3_calloc(sizeof(*san_u)); - san_u->nex_l = 1; - san_u->con_u = con_u; - con_u->san_u = san_u; - _conn_init_sock(san_u); - car_u->liv_o = c3y; -} - -/* _conn_ef_handle(): handle result. -*/ -static void -_conn_ef_handle(u3_conn* con_u, - c3_l sev_l, - c3_l coq_l, - u3_atom rid, - u3_noun tag, - u3_noun dat) -{ - u3_chan* can_u; - - if ( 0 != (can_u = _conn_find_chan(con_u, sev_l, coq_l)) ) { - if ( c3__avow == tag ) { - _conn_send_noun(can_u, u3nt(u3k(rid), c3__avow, u3k(dat))); - } - else { - can_u->mor_u.bal_f(can_u, -4, "handle-unknown"); - u3_king_bail(); - } - } - else { - u3l_log("conn: handle-no-coq %" PRIx32 " %" PRIu32, - sev_l, coq_l); - } - u3z(rid); u3z(tag); u3z(dat); -} - -/* _conn_io_kick(): apply effects. -*/ -static c3_o -_conn_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) -{ - u3_conn* con_u = (u3_conn*)car_u; - u3_noun tag, dat; - c3_l sev_l, coq_l; - u3_atom rid; - - if ( c3n == _conn_read_wire(wir, c3__khan, &sev_l, &coq_l, &rid) ) { - u3z(cad); return c3n; - } - if ( (con_u->sev_l != sev_l) || - (c3n == u3r_cell(cad, &tag, &dat)) ) - { - u3z(rid); u3z(cad); return c3n; - } - - _conn_ef_handle(con_u, sev_l, coq_l, rid, u3k(tag), u3k(dat)); - u3z(cad); return c3y; -} - -/* _conn_io_exit(): unlink socket, shut down connections. -*/ -static void -_conn_io_exit(u3_auto* car_u) -{ - u3_conn* con_u = (u3_conn*)car_u; - c3_c* pax_c = u3_Host.dir_c; - c3_w len_w = strlen(pax_c) + 1 + sizeof(URB_SOCK_PATH); - c3_c* paf_c = c3_malloc(len_w); - c3_i wit_i; - - wit_i = snprintf(paf_c, len_w, "%s/%s", pax_c, URB_SOCK_PATH); - c3_assert(wit_i > 0); - c3_assert(len_w == (c3_w)wit_i + 1); - - if ( 0 != unlink(paf_c) ) { - if ( ENOENT != errno ) { - u3l_log("conn: failed to unlink socket: %s", uv_strerror(errno)); - } - } - else { - // u3l_log("conn: unlinked %s", paf_c); - } - c3_free(paf_c); - - { - u3_shan* san_u = con_u->san_u; - - if ( san_u ) { - while ( san_u->can_u ) { - _conn_close_chan(san_u, san_u->can_u); - } - uv_close((uv_handle_t*)&san_u->pyp_u, _conn_close_cb); - } - } - - u3s_cue_xeno_done(con_u->sil_u); - c3_free(con_u); -} - -/* u3_conn(): initialize control plane socket. -*/ -u3_auto* -u3_conn_io_init(u3_pier* pir_u) -{ - u3_conn* con_u; - u3_auto* car_u; - u3_noun now; - struct timeval tim_u; - - if ( c3n == u3_Host.ops_u.con ) { - return NULL; - } - con_u = c3_calloc(sizeof(*con_u)); - con_u->sil_u = u3s_cue_xeno_init(); - con_u->kan_o = c3n; - car_u = &con_u->car_u; - car_u->nam_m = c3__conn; - car_u->liv_o = c3n; - car_u->io.talk_f = _conn_io_talk; - car_u->io.kick_f = _conn_io_kick; - car_u->io.exit_f = _conn_io_exit; - - gettimeofday(&tim_u, 0); - now = u3_time_in_tv(&tim_u); - con_u->sev_l = u3r_mug(now); - u3z(now); - return car_u; -} diff --git a/pkg/urbit/vere/io/cttp.c b/pkg/urbit/vere/io/cttp.c deleted file mode 100644 index 76c1dd396..000000000 --- a/pkg/urbit/vere/io/cttp.c +++ /dev/null @@ -1,1170 +0,0 @@ -/* vere/cttp.c -** -*/ -#include "all.h" -#include "vere/vere.h" -#include -#include - -/* u3_csat: client connection state. -*/ - typedef enum { - u3_csat_init = 0, // initialized - u3_csat_addr = 1, // address resolution begun - u3_csat_quit = 2, // cancellation requested - u3_csat_conn = 3, // sync connect phase - u3_csat_ripe = 4 // passed to libh2o - } u3_csat; - -/* u3_cres: response to http client. -*/ - typedef struct _u3_cres { - c3_w sas_w; // status code - u3_noun hed; // headers - u3_hbod* bod_u; // exit of body queue - u3_hbod* dob_u; // entry of body queue - } u3_cres; - -/* u3_creq: outgoing http request. -*/ - typedef struct _u3_creq { // client request - c3_l num_l; // request number - h2o_http1client_t* cli_u; // h2o client - u3_csat sat_e; // connection state - c3_o sec; // yes == https - c3_w ipf_w; // IP - c3_c* ipf_c; // IP (string) - c3_c* hot_c; // host - c3_s por_s; // port - c3_c* por_c; // port (string) - c3_c* met_c; // method - c3_c* url_c; // url - u3_hhed* hed_u; // headers - u3_hbod* bod_u; // body - u3_hbod* rub_u; // exit of send queue - u3_hbod* bur_u; // entry of send queue - h2o_iovec_t* vec_u; // send-buffer array - u3_cres* res_u; // nascent response - struct _u3_creq* nex_u; // next in list - struct _u3_creq* pre_u; // previous in list - struct _u3_cttp* ctp_u; // cttp backpointer - } u3_creq; - -/* u3_cttp: http client. -*/ - typedef struct _u3_cttp { - u3_auto car_u; // driver - c3_l sev_l; // instance number - u3_creq* ceq_u; // request list - uv_async_t nop_u; // unused handle (async close) - h2o_timeout_t tim_u; // request timeout - h2o_http1client_ctx_t // - ctx_u; // h2o client ctx - void* tls_u; // client SSL_CTX* - } u3_cttp; - -// XX deduplicate with _http_vec_to_atom -/* _cttp_vec_to_atom(): convert h2o_iovec_t to atom (cord) -*/ -static u3_noun -_cttp_vec_to_atom(h2o_iovec_t vec_u) -{ - return u3i_bytes(vec_u.len, (const c3_y*)vec_u.base); -} - -/* _cttp_bods_free(): free body structure. -*/ -static void -_cttp_bods_free(u3_hbod* bod_u) -{ - while ( bod_u ) { - u3_hbod* nex_u = bod_u->nex_u; - - c3_free(bod_u); - bod_u = nex_u; - } -} - -/* _cttp_bod_new(): create a data buffer -*/ -static u3_hbod* -_cttp_bod_new(c3_w len_w, c3_c* hun_c) -{ - u3_hbod* bod_u = c3_malloc(1 + len_w + sizeof(*bod_u)); - bod_u->hun_y[len_w] = 0; - bod_u->len_w = len_w; - memcpy(bod_u->hun_y, (const c3_y*)hun_c, len_w); - - bod_u->nex_u = 0; - return bod_u; -} - -/* _cttp_bod_from_hed(): create a data buffer from a header -*/ -static u3_hbod* -_cttp_bod_from_hed(u3_hhed* hed_u) -{ - c3_w len_w = hed_u->nam_w + 2 + hed_u->val_w + 2; - u3_hbod* bod_u = c3_malloc(1 + len_w + sizeof(*bod_u)); - bod_u->hun_y[len_w] = 0; - - memcpy(bod_u->hun_y, hed_u->nam_c, hed_u->nam_w); - memcpy(bod_u->hun_y + hed_u->nam_w, ": ", 2); - memcpy(bod_u->hun_y + hed_u->nam_w + 2, hed_u->val_c, hed_u->val_w); - memcpy(bod_u->hun_y + hed_u->nam_w + 2 + hed_u->val_w, "\r\n", 2); - - bod_u->len_w = len_w; - bod_u->nex_u = 0; - - return bod_u; -} - -/* _cttp_bods_to_octs: translate body buffer into octet-stream noun. -*/ -static u3_noun -_cttp_bods_to_octs(u3_hbod* bod_u) -{ - c3_w len_w; - c3_y* buf_y; - u3_noun cos; - - { - u3_hbod* bid_u = bod_u; - - len_w = 0; - while ( bid_u ) { - len_w += bid_u->len_w; - bid_u = bid_u->nex_u; - } - } - buf_y = c3_malloc(1 + len_w); - buf_y[len_w] = 0; - - { - c3_y* ptr_y = buf_y; - - while ( bod_u ) { - memcpy(ptr_y, bod_u->hun_y, bod_u->len_w); - ptr_y += bod_u->len_w; - bod_u = bod_u->nex_u; - } - } - cos = u3i_bytes(len_w, buf_y); - c3_free(buf_y); - return u3nc(len_w, cos); -} - -/* _cttp_bod_from_octs(): translate octet-stream noun into body. -*/ -static u3_hbod* -_cttp_bod_from_octs(u3_noun oct) -{ - c3_w len_w; - - if ( !_(u3a_is_cat(u3h(oct))) ) { // 2GB max - u3m_bail(c3__fail); return 0; - } - len_w = u3h(oct); - - { - u3_hbod* bod_u = c3_malloc(1 + len_w + sizeof(*bod_u)); - bod_u->hun_y[len_w] = 0; - bod_u->len_w = len_w; - u3r_bytes(0, len_w, bod_u->hun_y, u3t(oct)); - - bod_u->nex_u = 0; - - u3z(oct); - return bod_u; - } -} - -/* _cttp_bods_to_vec(): translate body buffers to array of h2o_iovec_t -*/ -static h2o_iovec_t* -_cttp_bods_to_vec(u3_hbod* bod_u, c3_w* tot_w) -{ - h2o_iovec_t* vec_u; - c3_w len_w; - - { - u3_hbod* bid_u = bod_u; - len_w = 0; - - while( bid_u ) { - len_w++; - bid_u = bid_u->nex_u; - } - } - - if ( 0 == len_w ) { - *tot_w = len_w; - return 0; - } - - vec_u = c3_malloc(sizeof(h2o_iovec_t) * len_w); - len_w = 0; - - while( bod_u ) { - vec_u[len_w] = h2o_iovec_init(bod_u->hun_y, bod_u->len_w); - len_w++; - bod_u = bod_u->nex_u; - } - - *tot_w = len_w; - - return vec_u; -} - -// XX deduplicate with _http_heds_free -/* _cttp_heds_free(): free header linked list -*/ -static void -_cttp_heds_free(u3_hhed* hed_u) -{ - while ( hed_u ) { - u3_hhed* nex_u = hed_u->nex_u; - - c3_free(hed_u->nam_c); - c3_free(hed_u->val_c); - c3_free(hed_u); - hed_u = nex_u; - } -} - -// XX deduplicate with _http_hed_new -/* _cttp_hed_new(): create u3_hhed from nam/val cords -*/ -static u3_hhed* -_cttp_hed_new(u3_atom nam, u3_atom val) -{ - c3_w nam_w = u3r_met(3, nam); - c3_w val_w = u3r_met(3, val); - u3_hhed* hed_u = c3_malloc(sizeof(*hed_u)); - - hed_u->nam_c = c3_malloc(1 + nam_w); - hed_u->val_c = c3_malloc(1 + val_w); - hed_u->nam_c[nam_w] = 0; - hed_u->val_c[val_w] = 0; - hed_u->nex_u = 0; - hed_u->nam_w = nam_w; - hed_u->val_w = val_w; - - u3r_bytes(0, nam_w, (c3_y*)hed_u->nam_c, nam); - u3r_bytes(0, val_w, (c3_y*)hed_u->val_c, val); - - return hed_u; -} - -// XX deduplicate with _http_heds_from_noun -/* _cttp_heds_from_noun(): convert (list (pair @t @t)) to u3_hhed -*/ -static u3_hhed* -_cttp_heds_from_noun(u3_noun hed) -{ - u3_noun deh = hed; - u3_noun i_hed; - - u3_hhed* hed_u = 0; - - while ( u3_nul != hed ) { - i_hed = u3h(hed); - u3_hhed* nex_u = _cttp_hed_new(u3h(i_hed), u3t(i_hed)); - nex_u->nex_u = hed_u; - - hed_u = nex_u; - hed = u3t(hed); - } - - u3z(deh); - return hed_u; -} - -// XX deduplicate with _http_heds_to_noun -/* _cttp_heds_to_noun(): convert h2o_header_t to (list (pair @t @t)) -*/ -static u3_noun -_cttp_heds_to_noun(h2o_header_t* hed_u, c3_d hed_d) -{ - u3_noun hed = u3_nul; - c3_d dex_d = hed_d; - - h2o_header_t deh_u; - - while ( 0 < dex_d ) { - deh_u = hed_u[--dex_d]; - hed = u3nc(u3nc(_cttp_vec_to_atom(*deh_u.name), - _cttp_vec_to_atom(deh_u.value)), hed); - } - - return hed; -} - -/* _cttp_cres_free(): free a u3_cres. -*/ -static void -_cttp_cres_free(u3_cres* res_u) -{ - _cttp_bods_free(res_u->bod_u); - c3_free(res_u); -} - -/* _cttp_cres_new(): create a response -*/ -static void -_cttp_cres_new(u3_creq* ceq_u, c3_w sas_w) -{ - ceq_u->res_u = c3_calloc(sizeof(*ceq_u->res_u)); - ceq_u->res_u->sas_w = sas_w; -} - -/* _cttp_cres_fire_body(): attach response body buffer -*/ -static void -_cttp_cres_fire_body(u3_cres* res_u, u3_hbod* bod_u) -{ - c3_assert(!bod_u->nex_u); - - if ( !(res_u->bod_u) ) { - res_u->bod_u = res_u->dob_u = bod_u; - } - else { - res_u->dob_u->nex_u = bod_u; - res_u->dob_u = bod_u; - } -} - -/* _cttp_mcut_pork(): measure/cut path/extension. -*/ -static c3_w -_cttp_mcut_pork(c3_c* buf_c, c3_w len_w, u3_noun pok) -{ - u3_noun h_pok = u3h(pok); - u3_noun t_pok = u3t(pok); - - len_w = u3_mcut_path(buf_c, len_w, '/', u3k(t_pok)); - if ( u3_nul != h_pok ) { - len_w = u3_mcut_char(buf_c, len_w, '.'); - len_w = u3_mcut_cord(buf_c, len_w, u3k(u3t(h_pok))); - } - u3z(pok); - return len_w; -} - -/* _cttp_mcut_quay(): measure/cut query. -*/ -static c3_w -_cttp_mcut_quay(c3_c* buf_c, c3_w len_w, u3_noun quy) -{ - u3_noun yuq = quy; - c3_o fir_o = c3y; - - while ( u3_nul != quy ) { - if ( c3y == fir_o ) { - len_w = u3_mcut_char(buf_c, len_w, '?'); - fir_o = c3n; - } - else { - len_w = u3_mcut_char(buf_c, len_w, '&'); - } - - { - u3_noun i_quy, t_quy; - u3_noun pi_quy, qi_quy; - u3x_cell(quy, &i_quy, &t_quy); - u3x_cell(i_quy, &pi_quy, &qi_quy); - - len_w = u3_mcut_cord(buf_c, len_w, u3k(pi_quy)); - len_w = u3_mcut_char(buf_c, len_w, '='); - len_w = u3_mcut_cord(buf_c, len_w, u3k(qi_quy)); - - quy = t_quy; - } - } - - u3z(yuq); - return len_w; -} - -/* _cttp_mcut_url(): measure/cut purl, producing relative URL. -*/ -static c3_w -_cttp_mcut_url(c3_c* buf_c, c3_w len_w, u3_noun pul) -{ - u3_noun q_pul = u3h(u3t(pul)); - u3_noun r_pul = u3t(u3t(pul)); - - len_w = u3_mcut_char(buf_c, len_w, '/'); - len_w = _cttp_mcut_pork(buf_c, len_w, u3k(q_pul)); - - if ( u3_nul != r_pul ) { - len_w = _cttp_mcut_quay(buf_c, len_w, u3k(r_pul)); - } - u3z(pul); - return len_w; -} - -/* _cttp_creq_port(): stringify port -*/ -static c3_c* -_cttp_creq_port(c3_s por_s) -{ - c3_c* por_c = c3_malloc(8); - snprintf(por_c, 7, "%d", 0xffff & por_s); - return por_c; -} - -/* _cttp_creq_url(): construct url from noun. -*/ -static c3_c* -_cttp_creq_url(u3_noun pul) -{ - c3_w len_w = _cttp_mcut_url(0, 0, u3k(pul)); - c3_c* url_c = c3_malloc(1 + len_w); - - _cttp_mcut_url(url_c, 0, pul); - url_c[len_w] = 0; - - return url_c; -} - -/* _cttp_creq_host(): construct host from noun. -*/ -static c3_c* -_cttp_creq_host(u3_noun hot) -{ - c3_w len_w = u3_mcut_host(0, 0, u3k(hot)); - c3_c* hot_c = c3_malloc(1 + len_w); - - u3_mcut_host(hot_c, 0, hot); - hot_c[len_w] = 0; - - return hot_c; -} - -/* _cttp_creq_ip(): stringify ip -*/ -static c3_c* -_cttp_creq_ip(c3_w ipf_w) -{ - c3_c* ipf_c = c3_malloc(17); - snprintf(ipf_c, 16, "%d.%d.%d.%d", (ipf_w >> 24), - ((ipf_w >> 16) & 255), - ((ipf_w >> 8) & 255), - (ipf_w & 255)); - return ipf_c; -} - -/* _cttp_creq_find(): find a request by number in the client -*/ -static u3_creq* -_cttp_creq_find(u3_cttp* ctp_u, c3_l num_l) -{ - u3_creq* ceq_u = ctp_u->ceq_u; - - // XX glories of linear search - // - while ( ceq_u ) { - if ( num_l == ceq_u->num_l ) { - return ceq_u; - } - ceq_u = ceq_u->nex_u; - } - return 0; -} - -/* _cttp_creq_link(): link request to client -*/ -static void -_cttp_creq_link(u3_cttp* ctp_u, u3_creq* ceq_u) -{ - ceq_u->nex_u = ctp_u->ceq_u; - - if ( 0 != ceq_u->nex_u ) { - ceq_u->nex_u->pre_u = ceq_u; - } - - ceq_u->ctp_u = ctp_u; - ctp_u->ceq_u = ceq_u; -} - -/* _cttp_creq_unlink(): unlink request from client -*/ -static void -_cttp_creq_unlink(u3_creq* ceq_u) -{ - u3_cttp* ctp_u = ceq_u->ctp_u; - - if ( ceq_u->pre_u ) { - ceq_u->pre_u->nex_u = ceq_u->nex_u; - - if ( 0 != ceq_u->nex_u ) { - ceq_u->nex_u->pre_u = ceq_u->pre_u; - } - } - else { - ctp_u->ceq_u = ceq_u->nex_u; - - if ( 0 != ceq_u->nex_u ) { - ceq_u->nex_u->pre_u = 0; - } - } -} - -/* _cttp_creq_free(): free a u3_creq. -*/ -static void -_cttp_creq_free(u3_creq* ceq_u) -{ - _cttp_creq_unlink(ceq_u); - - _cttp_heds_free(ceq_u->hed_u); - // Note: ceq_u->bod_u is covered here - _cttp_bods_free(ceq_u->rub_u); - - if ( ceq_u->res_u ) { - _cttp_cres_free(ceq_u->res_u); - } - - c3_free(ceq_u->hot_c); - c3_free(ceq_u->ipf_c); - c3_free(ceq_u->por_c); - c3_free(ceq_u->met_c); - c3_free(ceq_u->url_c); - c3_free(ceq_u->vec_u); - c3_free(ceq_u); -} - -/* _cttp_creq_new(): create a u3_creq from an +http-request - * - * If we were rewriting all of this from scratch, this isn't how we'd do it. - * - * We start with the (?? - JB) - */ -static u3_creq* -_cttp_creq_new(u3_cttp* ctp_u, c3_l num_l, u3_noun hes) -{ - u3_creq* ceq_u = c3_calloc(sizeof(*ceq_u)); - - u3_noun method, url, headers, body; - if (c3n == u3r_qual(hes, &method, &url, &headers, &body)) { - u3z(hes); - return 0; - } - - // parse the url out of the new style url passed to us. - // - u3_noun unit_pul = u3do("de-purl:html", u3k(url)); - - if ( c3n == u3r_du(unit_pul) ) { - c3_c* url_c = u3r_string(url); - u3l_log("cttp: unable to parse url:\n %s", url_c); - c3_free(url_c); - u3z(hes); - return 0; - } - - u3_noun pul = u3t(unit_pul); - - u3_noun hat = u3h(pul); // +hart - u3_noun sec = u3h(hat); - u3_noun por = u3h(u3t(hat)); - u3_noun hot = u3t(u3t(hat)); // +host - - ceq_u->sat_e = u3_csat_init; - ceq_u->num_l = num_l; - ceq_u->sec = sec; - - if ( c3y == u3h(hot) ) { - ceq_u->hot_c = _cttp_creq_host(u3k(u3t(hot))); - } else { - ceq_u->ipf_w = u3r_word(0, u3t(hot)); - ceq_u->ipf_c = _cttp_creq_ip(ceq_u->ipf_w); - } - - if ( u3_nul != por ) { - ceq_u->por_s = u3t(por); - ceq_u->por_c = _cttp_creq_port(ceq_u->por_s); - } - - // XX this should be checked against a whitelist - // - c3_assert( c3y == u3ud(method) ); - ceq_u->met_c = u3r_string(method); - ceq_u->url_c = _cttp_creq_url(u3k(pul)); - - ceq_u->hed_u = _cttp_heds_from_noun(u3k(headers)); - - if ( u3_nul != body ) { - ceq_u->bod_u = _cttp_bod_from_octs(u3k(u3t(body))); - } - - _cttp_creq_link(ctp_u, ceq_u); - - u3z(unit_pul); - u3z(hes); - - return ceq_u; -} - -/* _cttp_creq_fire_body(): attach body to request buffers. -*/ -static void -_cttp_creq_fire_body(u3_creq* ceq_u, u3_hbod *rub_u) -{ - c3_assert(!rub_u->nex_u); - - if ( !(ceq_u->rub_u) ) { - ceq_u->rub_u = ceq_u->bur_u = rub_u; - } - else { - ceq_u->bur_u->nex_u = rub_u; - ceq_u->bur_u = rub_u; - } -} - -/* _cttp_creq_fire_str(): attach string to request buffers. -*/ -static void -_cttp_creq_fire_str(u3_creq* ceq_u, c3_c* str_c) -{ - _cttp_creq_fire_body(ceq_u, _cttp_bod_new(strlen(str_c), str_c)); - c3_free(str_c); -} - -/* _cttp_creq_fire_heds(): attach output headers. -*/ -static void -_cttp_creq_fire_heds(u3_creq* ceq_u, u3_hhed* hed_u) -{ - while ( hed_u ) { - _cttp_creq_fire_body(ceq_u, _cttp_bod_from_hed(hed_u)); - hed_u = hed_u->nex_u; - } -} - -/* _cttp_creq_fire(): load request data for into buffers. -*/ -static void -_cttp_creq_fire(u3_creq* ceq_u) -{ - { - c3_w len_w = strlen(ceq_u->met_c) + 1 + strlen(ceq_u->url_c) + 12; - c3_c* lin_c = c3_malloc(len_w); - - len_w = snprintf(lin_c, len_w, "%s %s HTTP/1.1\r\n", - ceq_u->met_c, - ceq_u->url_c); - _cttp_creq_fire_str(ceq_u, lin_c); - } - - { - c3_c* hot_c = ceq_u->hot_c ? ceq_u->hot_c : ceq_u->ipf_c; - c3_c* hos_c; - c3_w len_w; - - if ( ceq_u->por_c ) { - len_w = 6 + strlen(hot_c) + 1 + strlen(ceq_u->por_c) + 3; - hos_c = c3_malloc(len_w); - len_w = snprintf(hos_c, len_w, "Host: %s:%s\r\n", hot_c, ceq_u->por_c); - } - else { - len_w = 6 + strlen(hot_c) + 3; - hos_c = c3_malloc(len_w); - len_w = snprintf(hos_c, len_w, "Host: %s\r\n", hot_c); - } - - _cttp_creq_fire_body(ceq_u, _cttp_bod_new(len_w, hos_c)); - c3_free(hos_c); - } - - _cttp_creq_fire_heds(ceq_u, ceq_u->hed_u); - - if ( !ceq_u->bod_u ) { - _cttp_creq_fire_body(ceq_u, _cttp_bod_new(2, "\r\n")); - } - else { - c3_c len_c[41]; - c3_w len_w = snprintf(len_c, 40, "Content-Length: %u\r\n\r\n", - ceq_u->bod_u->len_w); - - _cttp_creq_fire_body(ceq_u, _cttp_bod_new(len_w, len_c)); - _cttp_creq_fire_body(ceq_u, ceq_u->bod_u); - } -} - -/* _cttp_creq_quit(): cancel a u3_creq -*/ -static void -_cttp_creq_quit(u3_creq* ceq_u) -{ - if ( u3_csat_addr == ceq_u->sat_e ) { - ceq_u->sat_e = u3_csat_quit; - return; // wait to be called again on address resolution - } - - if ( ceq_u->cli_u ) { - h2o_http1client_cancel(ceq_u->cli_u); - } - - _cttp_creq_free(ceq_u); -} - -static void -_cttp_http_client_receive(u3_creq* ceq_u, c3_w sas_w, u3_noun mes, u3_noun uct) -{ - u3_cttp* ctp_u = ceq_u->ctp_u; - - // XX inject partial responses as separate events - // - u3_noun wir = u3nt(u3i_string("http-client"), - u3dc("scot", c3__uv, ctp_u->sev_l), - u3_nul); - u3_noun cad = u3nt(u3i_string("receive"), - ceq_u->num_l, - u3nq(u3i_string("start"), u3nc(sas_w, mes), uct, c3y)); - - u3_auto_plan(&ctp_u->car_u, u3_ovum_init(0, c3__i, wir, cad)); -} - -/* _cttp_creq_fail(): dispatch error response -*/ -static void -_cttp_creq_fail(u3_creq* ceq_u, const c3_c* err_c) -{ - // XX anything other than a 504? - c3_w cod_w = 504; - - u3l_log("http: fail (%d, %d): %s", ceq_u->num_l, cod_w, err_c); - - // XX include err_c as response body? - _cttp_http_client_receive(ceq_u, cod_w, u3_nul, u3_nul); - _cttp_creq_free(ceq_u); -} - -/* _cttp_creq_respond(): dispatch response -*/ -static void -_cttp_creq_respond(u3_creq* ceq_u) -{ - u3_cres* res_u = ceq_u->res_u; - - _cttp_http_client_receive(ceq_u, res_u->sas_w, res_u->hed, - ( !res_u->bod_u ) ? u3_nul : - u3nc(u3_nul, _cttp_bods_to_octs(res_u->bod_u))); - - _cttp_creq_free(ceq_u); -} - -// XX research: may be called with closed client? -/* _cttp_creq_on_body(): cb invoked by h2o upon receiving a response body -*/ -static c3_i -_cttp_creq_on_body(h2o_http1client_t* cli_u, const c3_c* err_c) -{ - u3_creq* ceq_u = (u3_creq *)cli_u->data; - - if ( 0 != err_c && h2o_http1client_error_is_eos != err_c ) { - _cttp_creq_fail(ceq_u, err_c); - return -1; - } - - h2o_buffer_t* buf_u = cli_u->sock->input; - - if ( buf_u->size ) { - _cttp_cres_fire_body(ceq_u->res_u, - _cttp_bod_new(buf_u->size, buf_u->bytes)); - h2o_buffer_consume(&cli_u->sock->input, buf_u->size); - } - - // We're using the end of stream thing here to queue event to urbit. we'll - // need to separate this into our own timer for partial progress sends. - if ( h2o_http1client_error_is_eos == err_c ) { - _cttp_creq_respond(ceq_u); - } - - return 0; -} - -/* _cttp_creq_on_head(): cb invoked by h2o upon receiving response headers -*/ -static h2o_http1client_body_cb -_cttp_creq_on_head(h2o_http1client_t* cli_u, const c3_c* err_c, c3_i ver_i, - c3_i sas_i, h2o_iovec_t sas_u, h2o_header_t* hed_u, - size_t hed_t, c3_i len_i) -{ - u3_creq* ceq_u = (u3_creq *)cli_u->data; - - if ( 0 != err_c && h2o_http1client_error_is_eos != err_c ) { - _cttp_creq_fail(ceq_u, err_c); - return 0; - } - - _cttp_cres_new(ceq_u, (c3_w)sas_i); - ceq_u->res_u->hed = _cttp_heds_to_noun(hed_u, hed_t); - - if ( h2o_http1client_error_is_eos == err_c ) { - _cttp_creq_respond(ceq_u); - return 0; - } - - return _cttp_creq_on_body; -} - -/* _cttp_creq_on_connect(): cb invoked by h2o upon successful connection -*/ -static h2o_http1client_head_cb -_cttp_creq_on_connect(h2o_http1client_t* cli_u, const c3_c* err_c, - h2o_iovec_t** vec_u, size_t* vec_i, c3_i* hed_i) -{ - u3_creq* ceq_u = (u3_creq *)cli_u->data; - - if ( 0 != err_c ) { - // if synchronously connecting, caller will cleanup - // - if ( u3_csat_conn == ceq_u->sat_e ) { - ceq_u->sat_e = u3_csat_quit; - } - else { - c3_assert( u3_csat_ripe == ceq_u->sat_e ); - _cttp_creq_fail(ceq_u, err_c); - } - return 0; - } - - // serialize request (populate rub_u) - // - _cttp_creq_fire(ceq_u); - - { - c3_w len_w; - ceq_u->vec_u = _cttp_bods_to_vec(ceq_u->rub_u, &len_w); - - *vec_i = len_w; - *vec_u = ceq_u->vec_u; - *hed_i = (0 == strcmp(ceq_u->met_c, "HEAD")); - } - - return _cttp_creq_on_head; -} - -/* _cttp_creq_connect(): establish connection -*/ -static void -_cttp_creq_connect(u3_creq* ceq_u) -{ - c3_assert( u3_csat_conn == ceq_u->sat_e ); - c3_assert( ceq_u->ipf_c ); - - // connect by ip/port, avoiding synchronous getaddrinfo() - // - { - h2o_iovec_t ipf_u = h2o_iovec_init(ceq_u->ipf_c, strlen(ceq_u->ipf_c)); - c3_t tls_t = ( c3y == ceq_u->sec ); - c3_s por_s = ( ceq_u->por_s ) - ? ceq_u->por_s - : ( tls_t ) ? 443 : 80; - - h2o_http1client_connect(&ceq_u->cli_u, ceq_u, &ceq_u->ctp_u->ctx_u, - ipf_u, por_s, tls_t, _cttp_creq_on_connect); - } - - // connect() failed, cb invoked synchronously - // - if ( u3_csat_conn != ceq_u->sat_e ) { - c3_assert( u3_csat_quit == ceq_u->sat_e ); - // only one such failure case - // - _cttp_creq_fail(ceq_u, "socket create error"); - } - else { - ceq_u->sat_e = u3_csat_ripe; - - // fixup hostname for TLS handshake - // - // must be synchronous, after successfull connect() call - // - if ( ceq_u->hot_c && (c3y == ceq_u->sec) ) { - c3_assert( ceq_u->cli_u ); - c3_free(ceq_u->cli_u->ssl.server_name); - ceq_u->cli_u->ssl.server_name = strdup(ceq_u->hot_c); - } - } -} - -/* _cttp_creq_resolve_cb(): cb upon IP address resolution -*/ -static void -_cttp_creq_resolve_cb(uv_getaddrinfo_t* adr_u, - c3_i sas_i, - struct addrinfo* aif_u) -{ - u3_creq* ceq_u = adr_u->data; - - if ( u3_csat_quit == ceq_u->sat_e ) { - _cttp_creq_quit(ceq_u);; - } - else if ( 0 != sas_i ) { - _cttp_creq_fail(ceq_u, uv_strerror(sas_i)); - } - else { - // XX traverse struct a la _ames_czar_cb - ceq_u->ipf_w = ntohl(((struct sockaddr_in *)aif_u->ai_addr)->sin_addr.s_addr); - ceq_u->ipf_c = _cttp_creq_ip(ceq_u->ipf_w); - - ceq_u->sat_e = u3_csat_conn; - _cttp_creq_connect(ceq_u); - } - - c3_free(adr_u); - uv_freeaddrinfo(aif_u); -} - -/* _cttp_creq_resolve(): resolve hostname to IP address -*/ -static void -_cttp_creq_resolve(u3_creq* ceq_u) -{ - c3_assert(u3_csat_addr == ceq_u->sat_e); - c3_assert(ceq_u->hot_c); - - uv_getaddrinfo_t* adr_u = c3_malloc(sizeof(*adr_u)); - adr_u->data = ceq_u; - - struct addrinfo hin_u; - memset(&hin_u, 0, sizeof(struct addrinfo)); - - hin_u.ai_family = PF_INET; - hin_u.ai_socktype = SOCK_STREAM; - hin_u.ai_protocol = IPPROTO_TCP; - - // XX is this necessary? - c3_c* por_c = ceq_u->por_c ? ceq_u->por_c : - ( c3y == ceq_u->sec ) ? "443" : "80"; - - c3_i sas_i; - - if ( 0 != (sas_i = uv_getaddrinfo(u3L, adr_u, _cttp_creq_resolve_cb, - ceq_u->hot_c, por_c, &hin_u)) ) { - _cttp_creq_fail(ceq_u, uv_strerror(sas_i)); - } -} - -/* _cttp_creq_start(): start a request -*/ -static void -_cttp_creq_start(u3_creq* ceq_u) -{ - if ( ceq_u->ipf_c ) { - ceq_u->sat_e = u3_csat_conn; - _cttp_creq_connect(ceq_u); - } else { - ceq_u->sat_e = u3_csat_addr; - _cttp_creq_resolve(ceq_u); - } -} - -/* _cttp_init_tls: initialize OpenSSL context -*/ -static SSL_CTX* -_cttp_init_tls(void) -{ - // XX require 1.1.0 and use TLS_client_method() - SSL_CTX* tls_u = SSL_CTX_new(SSLv23_client_method()); - // XX use SSL_CTX_set_max_proto_version() and SSL_CTX_set_min_proto_version() - SSL_CTX_set_options(tls_u, SSL_OP_NO_SSLv2 | - SSL_OP_NO_SSLv3 | - // SSL_OP_NO_TLSv1 | // XX test - SSL_OP_NO_COMPRESSION); - - u3K.ssl_x509_f(SSL_CTX_get_cert_store(tls_u)); - SSL_CTX_set_verify(tls_u, SSL_VERIFY_PEER, 0); - SSL_CTX_set_session_cache_mode(tls_u, SSL_SESS_CACHE_OFF); - SSL_CTX_set_cipher_list(tls_u, - "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:" - "ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:" - "RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS"); - - return tls_u; -} - -/* _cttp_ef_http_client(): send an %http-client (outgoing request) to cttp. -*/ -static c3_o -_cttp_ef_http_client(u3_cttp* ctp_u, u3_noun tag, u3_noun dat) -{ - u3_creq* ceq_u; - c3_o ret_o; - - if ( c3y == u3r_sing_c("request", tag) ) { - u3_noun num, req; - c3_l num_l; - - if ( (c3n == u3r_cell(dat, &num, &req)) - || (c3n == u3r_safe_word(num, &num_l)) ) - { - u3l_log("cttp: strange request"); - ret_o = c3n; - } - else if ( (ceq_u = _cttp_creq_new(ctp_u, num_l, u3k(req))) ) { - _cttp_creq_start(ceq_u); - ret_o = c3y; - } - else { - ret_o = c3n; - } - } - else if ( c3y == u3r_sing_c("cancel-request", tag) ) { - c3_l num_l; - - if ( c3n == u3r_safe_word(dat, &num_l) ) { - u3l_log("cttp: strange cancel-request"); - ret_o = c3n; - } - else if ( (ceq_u =_cttp_creq_find(ctp_u, num_l)) ) { - _cttp_creq_quit(ceq_u); - ret_o = c3y; - } - else { - // accepted whether or not request exists - // - ret_o = c3y; - } - } - else { - u3l_log("cttp: strange effect (unknown type)"); - ret_o = c3n; - } - - u3z(tag); u3z(dat); - return ret_o; -} - -/* _cttp_io_talk(): notify that we're live. -*/ -static void -_cttp_io_talk(u3_auto* car_u) -{ - u3_cttp* ctp_u = (u3_cttp*)car_u; - - // XX remove u3A->sen - // - u3_noun wir = u3nt(u3i_string("http-client"), - u3dc("scot", c3__uv, ctp_u->sev_l), - u3_nul); - u3_noun cad = u3nc(c3__born, u3_nul); - - u3_auto_plan(car_u, u3_ovum_init(0, c3__i, wir, cad)); -} - -/* _cttp_io_kick(): apply effects -*/ -static c3_o -_cttp_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) -{ - u3_cttp* ctp_u = (u3_cttp*)car_u; - - u3_noun tag, dat, i_wir; - c3_o ret_o; - - if ( (c3n == u3r_cell(wir, &i_wir, 0)) - || (c3n == u3r_cell(cad, &tag, &dat)) - || (c3n == u3r_sing_c("http-client", i_wir)) ) - { - ret_o = c3n; - } - else { - ret_o = _cttp_ef_http_client(ctp_u, u3k(tag), u3k(dat)); - } - - u3z(wir); u3z(cad); - return ret_o; -} - -/* _cttp_io_exit_cb(): free cttp. -*/ -static void -_cttp_io_exit_cb(uv_handle_t* han_u) -{ - u3_cttp* ctp_u = han_u->data; - - SSL_CTX_free(ctp_u->tls_u); - c3_free(ctp_u); -} - -/* _cttp_io_exit(): shut down cttp. -*/ -static void -_cttp_io_exit(u3_auto* car_u) -{ - u3_cttp* ctp_u = (u3_cttp*)car_u; - - // close unused handle to free [ctp_u] after h2o is done - // - uv_close((uv_handle_t*)&ctp_u->nop_u, _cttp_io_exit_cb); - - // cancel requests - // - { - u3_creq* ceq_u = ctp_u->ceq_u; - - while ( ceq_u ) { - _cttp_creq_quit(ceq_u); - ceq_u = ceq_u->nex_u; - } - } - - h2o_timeout_dispose(u3L, &ctp_u->tim_u); -} - -/* u3_cttp_io_init(): initialize http client I/O. -*/ -u3_auto* -u3_cttp_io_init(u3_pier* pir_u) -{ - u3_cttp* ctp_u = c3_calloc(sizeof(*ctp_u)); - - // link to event loop - // - ctp_u->ctx_u.loop = u3L; - - // unused handle for async close - // - uv_async_init(u3L, &ctp_u->nop_u, 0); - ctp_u->nop_u.data = ctp_u; - - // link to initialized request timeout - // - h2o_timeout_init(u3L, &ctp_u->tim_u, 300 * 1000); - ctp_u->ctx_u.io_timeout = &ctp_u->tim_u; - - // link to initialized tls ctx - // - ctp_u->tls_u = _cttp_init_tls(); - ctp_u->ctx_u.ssl_ctx = ctp_u->tls_u; - - u3_auto* car_u = &ctp_u->car_u; - car_u->nam_m = c3__cttp; - - // XX set in done_cb for %born - // - car_u->liv_o = c3y; - car_u->io.talk_f = _cttp_io_talk; - car_u->io.kick_f = _cttp_io_kick; - car_u->io.exit_f = _cttp_io_exit; - // XX retry up to N? - // - // car_u->ev.bail_f = ...; - - { - u3_noun now; - struct timeval tim_u; - gettimeofday(&tim_u, 0); - - now = u3_time_in_tv(&tim_u); - ctp_u->sev_l = u3r_mug(now); - u3z(now); - } - - return car_u; -} diff --git a/pkg/urbit/vere/io/fore.c b/pkg/urbit/vere/io/fore.c deleted file mode 100644 index 2fdd02237..000000000 --- a/pkg/urbit/vere/io/fore.c +++ /dev/null @@ -1,168 +0,0 @@ -/* vere/root.c -** -*/ -#include "all.h" -#include "vere/vere.h" - -/* _fore_inject_bail(): handle failure on arbitrary injection. -*/ -static void -_fore_inject_bail(u3_ovum* egg_u, u3_noun lud) -{ - u3_auto_bail_slog(egg_u, lud); - u3l_log("pier: injected event failed"); - - u3_ovum_free(egg_u); -} - -/* _fore_import_bail(): handle failure on arbitrary injection. -*/ -static void -_fore_import_bail(u3_ovum* egg_u, u3_noun lud) -{ - u3_auto_bail_slog(egg_u, lud); - u3l_log("pier: import failed"); - - u3_ovum_free(egg_u); -} - -/* _fore_inject(): inject an arbitrary ovum from a jammed file at [pax_c]. -*/ -static void -_fore_inject(u3_auto* car_u, c3_c* pax_c) -{ - // XX soft - // - u3_noun ovo = u3ke_cue(u3m_file(pax_c)); - u3_noun riw, cad, tar, wir; - - if ( c3n == u3r_cell(ovo, &riw, &cad) ) { - u3l_log("pier: invalid ovum in -I"); - } - else if ( (c3n == u3a_is_cell(cad)) - || (c3n == u3a_is_atom(u3h(cad))) ) - { - u3l_log("pier: invalid card in -I ovum"); - } - else if ( c3n == u3r_cell(riw, &tar, &wir) ) { - u3l_log("pier: invalid wire in -I ovum"); - } - else if ( (c3n == u3a_is_atom(tar)) - || (4 < u3r_met(3, tar)) ) - { - u3l_log("pier: invalid target in -I wire"); - } - else { - { - c3_c* tag_c = u3r_string(u3h(cad)); - u3_noun ser = u3do("spat", u3k(riw)); - c3_c* wir_c = u3r_string(ser); - - u3l_log("pier: injecting %%%s event on %s", tag_c, wir_c); - - c3_free(tag_c); - c3_free(wir_c); - u3z(ser); - } - - u3_auto_peer( - u3_auto_plan(car_u, u3_ovum_init(0, u3k(tar), u3k(wir), u3k(cad))), - 0, 0, _fore_inject_bail); - } - - u3z(ovo); -} - -/* _fore_import(): form an ovum from jammed archive at [pax_c] and inject it. -*/ -static void -_fore_import(u3_auto* car_u, c3_c* pax_c) -{ - u3_noun arc = u3ke_cue(u3m_file(pax_c)); - u3_noun imp = u3dt("cat", 3, u3i_string("#import_"), arc); - u3_noun siz = u3r_met(3, imp); - u3_noun dat = u3nt(u3_nul, siz, imp); - - u3_noun req = u3nt(c3n, - u3nc(u3i_string("ipv4"), u3i_word(0x7f000001)), - u3nq(u3i_string("POST"), u3i_string("/"), u3_nul, dat)); - u3_noun wir = u3nc(u3i_string("http-server"), u3_nul); - u3_noun cad = u3nc(u3i_string("request-local"), req); - u3_auto_peer( - u3_auto_plan(car_u, u3_ovum_init(0, c3__e, wir, cad)), - 0, 0, _fore_import_bail); -} - -/* _fore_io_talk(): -*/ -static void -_fore_io_talk(u3_auto* car_u) -{ - u3_noun wir, cad; - - // inject fresh entropy - // - { - c3_w eny_w[16]; - c3_rand(eny_w); - - wir = u3nc(c3__arvo, u3_nul); - cad = u3nc(c3__wack, u3i_words(16, eny_w)); - - u3_auto_plan(car_u, u3_ovum_init(0, u3_blip, wir, cad)); - } - - // set verbose as per -v - // - { - c3_o lac_o = ( c3y == u3_Host.ops_u.veb ) ? c3n : c3y; - wir = u3nc(c3__arvo, u3_nul); - cad = u3nt(c3__verb, u3_nul, lac_o); - u3_auto_plan(car_u, u3_ovum_init(0, u3_blip, wir, cad)); - } - - // inject arbitrary - // - if ( u3_Host.ops_u.jin_c ) { - _fore_inject(car_u, u3_Host.ops_u.jin_c); - } - - if ( u3_Host.ops_u.imp_c ) { - _fore_import(car_u, u3_Host.ops_u.imp_c); - } -} - -/* _fore_io_kick(): handle no effects. -*/ -static c3_o -_fore_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) -{ - u3z(wir); u3z(cad); - return c3n; -} - -/* _fore_io_exit(): -*/ -static void -_fore_io_exit(u3_auto* car_u) -{ - c3_free(car_u); -} - -/* u3_fore_io_init(): initialize fore -*/ -u3_auto* -u3_fore_io_init(u3_pier* pir_u) -{ - u3_auto* car_u = c3_calloc(sizeof(*car_u)); - car_u->nam_m = c3__fore; - // XX set in done_cb for %wack - // - car_u->liv_o = c3y; - car_u->io.talk_f = _fore_io_talk; - car_u->io.kick_f = _fore_io_kick; - car_u->io.exit_f = _fore_io_exit; - // car_u->ev.bail_f = ...; - - return car_u; -} diff --git a/pkg/urbit/vere/io/hind.c b/pkg/urbit/vere/io/hind.c deleted file mode 100644 index d15534806..000000000 --- a/pkg/urbit/vere/io/hind.c +++ /dev/null @@ -1,86 +0,0 @@ -/* vere/root.c -** -*/ -#include "all.h" -#include "vere/vere.h" - -/* _hind_io_talk(): -*/ -static void -_hind_io_talk(u3_auto* car_u) -{ -} - -/* _hind_io_kick(): handle generic effects, by tag -*/ -static c3_o -_hind_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) -{ - u3_noun tag, dat; - c3_o ret_o; - - if ( c3n == u3r_cell(cad, &tag, &dat) ) { - ret_o = c3n; - } - else { - switch ( tag ) { - default: { - ret_o = c3n; - } break; - - case c3__exit: { - ret_o = c3y; - u3l_log("<<>>"); - u3_pier_exit(car_u->pir_u); - } break; - - // XX fake effect, check //arvo wire? - // - case c3__trim: { - ret_o = c3y; - u3_auto_plan(car_u, u3_ovum_init(0, u3_blip, - u3nc(c3__arvo, u3_nul), u3k(cad))); - } break; - - case c3__vega: { - ret_o = c3y; - u3l_log("<<>>"); - } break; - - // NB: startup explicitly handled in pier.c - // - // XX review arvo upgrade scenaria - // - case c3__wend: { - ret_o = c3y; - } break; - } - } - - u3z(wir); u3z(cad); - return ret_o; -} - -/* _hind_io_exit(): -*/ -static void -_hind_io_exit(u3_auto* car_u) -{ - c3_free(car_u); -} - -/* u3_hind_io_init(): -*/ -u3_auto* -u3_hind_io_init(u3_pier* pir_u) -{ - u3_auto* car_u = c3_calloc(sizeof(*car_u)); - car_u->nam_m = c3__hind; - car_u->liv_o = c3y; - car_u->io.talk_f = _hind_io_talk; - car_u->io.kick_f = _hind_io_kick; - car_u->io.exit_f = _hind_io_exit; - // car_u->ev.bail_f = ...; - - return car_u; -} diff --git a/pkg/urbit/vere/io/http.c b/pkg/urbit/vere/io/http.c deleted file mode 100644 index 3f90df80d..000000000 --- a/pkg/urbit/vere/io/http.c +++ /dev/null @@ -1,2302 +0,0 @@ -/* vere/http.c -** -*/ -#include "all.h" -#include "vere/vere.h" -#include -#include -#include - -typedef struct _u3_h2o_serv { - h2o_globalconf_t fig_u; // h2o global config - h2o_context_t ctx_u; // h2o ctx - h2o_accept_ctx_t cep_u; // h2o accept ctx - h2o_hostconf_t* hos_u; // h2o host config - h2o_handler_t* han_u; // h2o request handler -} u3_h2o_serv; - -/* u3_rsat: http request state. -*/ - typedef enum { - u3_rsat_init = 0, // initialized - u3_rsat_plan = 1, // planned - u3_rsat_ripe = 2 // responded - } u3_rsat; - -/* u3_hreq: incoming http request. -*/ - typedef struct _u3_hreq { - h2o_req_t* rec_u; // h2o request - c3_w seq_l; // sequence within connection - u3_rsat sat_e; // request state - uv_timer_t* tim_u; // timeout - void* gen_u; // response generator - struct _u3_hcon* hon_u; // connection backlink - struct _u3_hreq* nex_u; // next in connection's list - struct _u3_hreq* pre_u; // prev in connection's list - } u3_hreq; - -/* u3_hcon: incoming http connection. -*/ - typedef struct _u3_hcon { - uv_tcp_t wax_u; // client stream handler - h2o_conn_t* con_u; // h2o connection - h2o_socket_t* sok_u; // h2o connection socket - c3_w ipf_w; // client ipv4 - c3_w coq_l; // connection number - c3_w seq_l; // next request number - struct _u3_http* htp_u; // server backlink - struct _u3_hreq* req_u; // request list - struct _u3_hcon* nex_u; // next in server's list - struct _u3_hcon* pre_u; // prev in server's list - } u3_hcon; - -/* u3_http: http server. -*/ - typedef struct _u3_http { - uv_tcp_t wax_u; // server stream handler - void* h2o_u; // libh2o configuration - c3_w sev_l; // server number - c3_w coq_l; // next connection number - c3_s por_s; // running port - c3_o dis; // manually-configured port - c3_o sec; // logically secure - c3_o lop; // loopback-only - c3_o liv; // c3n == shutdown - struct _u3_hcon* hon_u; // connection list - struct _u3_http* nex_u; // next in list - struct _u3_httd* htd_u; // device backpointer - } u3_http; - -/* u3_form: http config from %eyre -*/ - typedef struct _u3_form { - c3_o pro; // proxy - c3_o log; // keep access log - c3_o red; // redirect to HTTPS - uv_buf_t key_u; // PEM RSA private key - uv_buf_t cer_u; // PEM certificate chain - } u3_form; - -/* u3_hfig: general http configuration -*/ - typedef struct _u3_hfig { - u3_form* for_u; // config from %eyre - struct _u3_hreq* seq_u; // open slog requests - uv_timer_t* sit_u; // slog stream heartbeat - } u3_hfig; - -/* u3_httd: general http device -*/ -typedef struct _u3_httd { - u3_auto car_u; // driver - c3_l sev_l; // instance number - u3_hfig fig_u; // http configuration - u3_http* htp_u; // http servers - SSL_CTX* tls_u; // server SSL_CTX* -} u3_httd; - -static void _http_serv_free(u3_http* htp_u); -static void _http_serv_start_all(u3_httd* htd_u); -static void _http_form_free(u3_httd* htd_u); - -static const c3_i TCP_BACKLOG = 16; -static const c3_w HEARTBEAT_TIMEOUT = 20 * 1000; - -/* _http_close_cb(): uv_close_cb that just free's handle -*/ -static void -_http_close_cb(uv_handle_t* han_u) -{ - c3_free(han_u); -} - -/* _http_vec_to_meth(): convert h2o_iovec_t to meth -*/ -static u3_weak -_http_vec_to_meth(h2o_iovec_t vec_u) -{ - return ( 0 == strncmp(vec_u.base, "GET", vec_u.len) ) ? u3i_string("GET") : - ( 0 == strncmp(vec_u.base, "PUT", vec_u.len) ) ? u3i_string("PUT") : - ( 0 == strncmp(vec_u.base, "POST", vec_u.len) ) ? u3i_string("POST") : - ( 0 == strncmp(vec_u.base, "HEAD", vec_u.len) ) ? u3i_string("HEAD") : - ( 0 == strncmp(vec_u.base, "CONNECT", vec_u.len) ) ? u3i_string("CONNECT") : - ( 0 == strncmp(vec_u.base, "DELETE", vec_u.len) ) ? u3i_string("DELETE") : - ( 0 == strncmp(vec_u.base, "OPTIONS", vec_u.len) ) ? u3i_string("OPTIONS") : - ( 0 == strncmp(vec_u.base, "TRACE", vec_u.len) ) ? u3i_string("TRACE") : - // TODO ?? - // ( 0 == strncmp(vec_u.base, "PATCH", vec_u.len) ) ? c3__patc : - u3_none; -} - -/* _http_vec_to_atom(): convert h2o_iovec_t to atom (cord) -*/ -static u3_noun -_http_vec_to_atom(h2o_iovec_t vec_u) -{ - return u3i_bytes(vec_u.len, (const c3_y*)vec_u.base); -} - -/* _http_vec_to_octs(): convert h2o_iovec_t to (unit octs) -*/ -static u3_noun -_http_vec_to_octs(h2o_iovec_t vec_u) -{ - if ( 0 == vec_u.len ) { - return u3_nul; - } - - // XX correct size_t -> atom? - return u3nt(u3_nul, u3i_chubs(1, (const c3_d*)&vec_u.len), - _http_vec_to_atom(vec_u)); -} - -/* _cttp_bods_free(): free body structure. -*/ -static void -_cttp_bods_free(u3_hbod* bod_u) -{ - while ( bod_u ) { - u3_hbod* nex_u = bod_u->nex_u; - - c3_free(bod_u); - bod_u = nex_u; - } -} - -/* _cttp_bod_from_octs(): translate octet-stream noun into body. -*/ -static u3_hbod* -_cttp_bod_from_octs(u3_noun oct) -{ - c3_w len_w; - - if ( !_(u3a_is_cat(u3h(oct))) ) { // 2GB max - u3m_bail(c3__fail); return 0; - } - len_w = u3h(oct); - - { - u3_hbod* bod_u = c3_malloc(1 + len_w + sizeof(*bod_u)); - bod_u->hun_y[len_w] = 0; - bod_u->len_w = len_w; - u3r_bytes(0, len_w, bod_u->hun_y, u3t(oct)); - - bod_u->nex_u = 0; - - u3z(oct); - return bod_u; - } -} - -/* _cttp_bods_to_vec(): translate body buffers to array of h2o_iovec_t -*/ -static h2o_iovec_t* -_cttp_bods_to_vec(u3_hbod* bod_u, c3_w* tot_w) -{ - h2o_iovec_t* vec_u; - c3_w len_w; - - { - u3_hbod* bid_u = bod_u; - len_w = 0; - - while( bid_u ) { - len_w++; - bid_u = bid_u->nex_u; - } - } - - vec_u = c3_malloc(sizeof(h2o_iovec_t) * len_w); - len_w = 0; - - while( bod_u ) { - vec_u[len_w] = h2o_iovec_init(bod_u->hun_y, bod_u->len_w); - len_w++; - bod_u = bod_u->nex_u; - } - - *tot_w = len_w; - - return vec_u; -} - -/* _http_heds_to_noun(): convert h2o_header_t to (list (pair @t @t)) -*/ -static u3_noun -_http_heds_to_noun(h2o_header_t* hed_u, c3_d hed_d) -{ - u3_noun hed = u3_nul; - c3_d dex_d = hed_d; - - h2o_header_t deh_u; - - while ( 0 < dex_d ) { - deh_u = hed_u[--dex_d]; - hed = u3nc(u3nc(_http_vec_to_atom(*deh_u.name), - _http_vec_to_atom(deh_u.value)), hed); - } - - return hed; -} - -/* _http_heds_free(): free header linked list -*/ -static void -_http_heds_free(u3_hhed* hed_u) -{ - while ( hed_u ) { - u3_hhed* nex_u = hed_u->nex_u; - - c3_free(hed_u->nam_c); - c3_free(hed_u->val_c); - c3_free(hed_u); - hed_u = nex_u; - } -} - -/* _http_hed_new(): create u3_hhed from nam/val cords -*/ -static u3_hhed* -_http_hed_new(u3_atom nam, u3_atom val) -{ - c3_w nam_w = u3r_met(3, nam); - c3_w val_w = u3r_met(3, val); - u3_hhed* hed_u = c3_malloc(sizeof(*hed_u)); - - hed_u->nam_c = c3_malloc(1 + nam_w); - hed_u->val_c = c3_malloc(1 + val_w); - hed_u->nam_c[nam_w] = 0; - hed_u->val_c[val_w] = 0; - hed_u->nex_u = 0; - hed_u->nam_w = nam_w; - hed_u->val_w = val_w; - - u3r_bytes(0, nam_w, (c3_y*)hed_u->nam_c, nam); - u3r_bytes(0, val_w, (c3_y*)hed_u->val_c, val); - - return hed_u; -} - -/* _http_heds_from_noun(): convert (list (pair @t @t)) to u3_hhed -*/ -static u3_hhed* -_http_heds_from_noun(u3_noun hed) -{ - u3_noun deh = hed; - u3_noun i_hed; - - u3_hhed* hed_u = 0; - - while ( u3_nul != hed ) { - i_hed = u3h(hed); - u3_hhed* nex_u = _http_hed_new(u3h(i_hed), u3t(i_hed)); - nex_u->nex_u = hed_u; - - hed_u = nex_u; - hed = u3t(hed); - } - - u3z(deh); - return hed_u; -} - -/* _http_req_find(): find http request in connection by sequence. -*/ -static u3_hreq* -_http_req_find(u3_hcon* hon_u, c3_w seq_l) -{ - u3_hreq* req_u = hon_u->req_u; - - // XX glories of linear search - // - while ( req_u ) { - if ( seq_l == req_u->seq_l ) { - return req_u; - } - req_u = req_u->nex_u; - } - return 0; -} - -/* _http_req_link(): link http request to connection -*/ -static void -_http_req_link(u3_hcon* hon_u, u3_hreq* req_u) -{ - req_u->hon_u = hon_u; - req_u->seq_l = hon_u->seq_l++; - req_u->nex_u = hon_u->req_u; - - if ( 0 != req_u->nex_u ) { - req_u->nex_u->pre_u = req_u; - } - hon_u->req_u = req_u; -} - -/* _http_req_unlink(): remove http request from connection -*/ -static void -_http_req_unlink(u3_hreq* req_u) -{ - if ( 0 != req_u->pre_u ) { - req_u->pre_u->nex_u = req_u->nex_u; - - if ( 0 != req_u->nex_u ) { - req_u->nex_u->pre_u = req_u->pre_u; - } - } - else { - req_u->hon_u->req_u = req_u->nex_u; - - if ( 0 != req_u->nex_u ) { - req_u->nex_u->pre_u = 0; - } - } -} - -/* _http_seq_link(): store slog stream request in state -*/ -static void -_http_seq_link(u3_hcon* hon_u, u3_hreq* req_u) -{ - u3_hfig* fig_u = &hon_u->htp_u->htd_u->fig_u; - req_u->hon_u = hon_u; - req_u->seq_l = hon_u->seq_l++; - req_u->nex_u = fig_u->seq_u; - - if ( 0 != req_u->nex_u ) { - req_u->nex_u->pre_u = req_u; - } - fig_u->seq_u = req_u; -} - -/* _http_seq_unlink(): remove slog stream request from state -*/ -static void -_http_seq_unlink(u3_hreq* req_u) -{ - u3_hfig* fig_u = &req_u->hon_u->htp_u->htd_u->fig_u; - if ( 0 != req_u->pre_u ) { - req_u->pre_u->nex_u = req_u->nex_u; - - if ( 0 != req_u->nex_u ) { - req_u->nex_u->pre_u = req_u->pre_u; - } - } - else { - fig_u->seq_u = req_u->nex_u; - - if ( 0 != req_u->nex_u ) { - req_u->nex_u->pre_u = 0; - } - } -} - -/* _http_req_to_duct(): translate srv/con/req to duct -*/ -static u3_noun -_http_req_to_duct(u3_hreq* req_u) -{ - return u3nc(u3i_string("http-server"), - u3nq(u3dc("scot", c3__uv, req_u->hon_u->htp_u->sev_l), - u3dc("scot", c3__ud, req_u->hon_u->coq_l), - u3dc("scot", c3__ud, req_u->seq_l), - u3_nul)); -} - -/* _http_req_kill(): kill http request in %eyre. -*/ -static void -_http_req_kill(u3_hreq* req_u) -{ - u3_httd* htd_u = req_u->hon_u->htp_u->htd_u; - u3_noun wir = _http_req_to_duct(req_u); - u3_noun cad = u3nc(u3i_string("cancel-request"), u3_nul); - - u3_auto_plan(&htd_u->car_u, u3_ovum_init(0, c3__e, wir, cad)); -} - -typedef struct _u3_hgen { - h2o_generator_t neg_u; // response callbacks - c3_o red; // ready to send - c3_o dun; // done sending - u3_hbod* bod_u; // pending body - u3_hbod* nud_u; // pending free - u3_hhed* hed_u; // pending free - u3_hreq* req_u; // originating request -} u3_hgen; - -/* _http_req_close(): clean up & deallocate request -*/ -static void -_http_req_close(u3_hreq* req_u) -{ - // client canceled request before response - // - if ( u3_rsat_plan == req_u->sat_e ) { - _http_req_kill(req_u); - } - - if ( 0 != req_u->tim_u ) { - uv_close((uv_handle_t*)req_u->tim_u, _http_close_cb); - req_u->tim_u = 0; - } -} - -/* _http_req_done(): request finished, deallocation callback -*/ -static void -_http_req_done(void* ptr_v) -{ - u3_hreq* req_u = (u3_hreq*)ptr_v; - _http_req_close(req_u); - _http_req_unlink(req_u); -} - -/* _http_seq_done(): slog stream request finished, deallocation callback -*/ -static void -_http_seq_done(void* ptr_v) -{ - u3_hreq* seq_u = (u3_hreq*)ptr_v; - _http_req_close(seq_u); - _http_seq_unlink(seq_u); -} - -/* _http_req_timer_cb(): request timeout callback -*/ -static void -_http_req_timer_cb(uv_timer_t* tim_u) -{ - u3_hreq* req_u = tim_u->data; - - if ( u3_rsat_plan == req_u->sat_e ) { - _http_req_kill(req_u); - req_u->sat_e = u3_rsat_ripe; - - c3_c* msg_c = "gateway timeout"; - h2o_send_error_generic(req_u->rec_u, 504, msg_c, msg_c, 0); - } -} - -/* _http_req_new(): receive standard http request. -*/ -static u3_hreq* -_http_req_new(u3_hcon* hon_u, h2o_req_t* rec_u) -{ - u3_hreq* req_u = h2o_mem_alloc_shared(&rec_u->pool, sizeof(*req_u), - _http_req_done); - req_u->rec_u = rec_u; - req_u->sat_e = u3_rsat_init; - req_u->tim_u = 0; - req_u->gen_u = 0; - req_u->pre_u = 0; - - _http_req_link(hon_u, req_u); - - return req_u; -} - -/* _http_seq_new(): receive slog stream http request. -*/ -static u3_hreq* -_http_seq_new(u3_hcon* hon_u, h2o_req_t* rec_u) -{ - u3_hreq* req_u = h2o_mem_alloc_shared(&rec_u->pool, sizeof(*req_u), - _http_seq_done); - req_u->rec_u = rec_u; - req_u->sat_e = u3_rsat_plan; - req_u->tim_u = 0; - req_u->gen_u = 0; - req_u->pre_u = 0; - - _http_seq_link(hon_u, req_u); - - return req_u; -} - -/* _http_req_dispatch(): dispatch http request to %eyre -*/ -static void -_http_req_dispatch(u3_hreq* req_u, u3_noun req) -{ - c3_assert(u3_rsat_init == req_u->sat_e); - req_u->sat_e = u3_rsat_plan; - - { - u3_http* htp_u = req_u->hon_u->htp_u; - u3_httd* htd_u = htp_u->htd_u; - u3_noun wir = _http_req_to_duct(req_u); - u3_noun cad; - - { - u3_noun adr = u3nc(c3__ipv4, u3i_words(1, &req_u->hon_u->ipf_w)); - // XX loopback automatically secure too? - // - u3_noun dat = u3nt(htp_u->sec, adr, req); - - cad = ( c3y == req_u->hon_u->htp_u->lop ) - ? u3nc(u3i_string("request-local"), dat) - : u3nc(u3i_string("request"), dat); - } - - u3_auto_plan(&htd_u->car_u, u3_ovum_init(0, c3__e, wir, cad)); - } -} - -/* _http_hgen_dispose(): dispose response generator and buffers -*/ -static void -_http_hgen_dispose(void* ptr_v) -{ - u3_hgen* gen_u = (u3_hgen*)ptr_v; - _http_heds_free(gen_u->hed_u); - gen_u->hed_u = 0; - _cttp_bods_free(gen_u->nud_u); - gen_u->nud_u = 0; - _cttp_bods_free(gen_u->bod_u); - gen_u->bod_u = 0; -} - -static void -_http_hgen_send(u3_hgen* gen_u) -{ - c3_assert( c3y == gen_u->red ); - - u3_hreq* req_u = gen_u->req_u; - h2o_req_t* rec_u = req_u->rec_u; - - c3_w len_w; - h2o_iovec_t* vec_u = _cttp_bods_to_vec(gen_u->bod_u, &len_w); - - // not ready again until _proceed - // - gen_u->red = c3n; - - // stash [bod_u] to free later - // - _cttp_bods_free(gen_u->nud_u); - gen_u->nud_u = gen_u->bod_u; - gen_u->bod_u = 0; - - if ( c3n == gen_u->dun ) { - h2o_send(rec_u, vec_u, len_w, H2O_SEND_STATE_IN_PROGRESS); - uv_timer_start(req_u->tim_u, _http_req_timer_cb, 45 * 1000, 0); - } - else { - // close connection if shutdown pending - // - u3_h2o_serv* h2o_u = req_u->hon_u->htp_u->h2o_u; - - if ( 0 != h2o_u->ctx_u.shutdown_requested ) { - rec_u->http1_is_persistent = 0; - } - - h2o_send(rec_u, vec_u, len_w, H2O_SEND_STATE_FINAL); - } - - c3_free(vec_u); -} - -/* _http_hgen_stop(): h2o is closing an in-progress response. -*/ -static void -_http_hgen_stop(h2o_generator_t* neg_u, h2o_req_t* rec_u) -{ - u3_hgen* gen_u = (u3_hgen*)neg_u; - - // response not complete, enqueue cancel - // - if ( c3n == gen_u->dun ) { - _http_req_kill(gen_u->req_u); - } -} - -/* _http_hgen_proceed(): h2o is ready for more response data. -*/ -static void -_http_hgen_proceed(h2o_generator_t* neg_u, h2o_req_t* rec_u) -{ - u3_hgen* gen_u = (u3_hgen*)neg_u; - u3_hreq* req_u = gen_u->req_u; - - // sanity check - c3_assert( rec_u == req_u->rec_u ); - - gen_u->red = c3y; - - if ( 0 != gen_u->bod_u || c3y == gen_u->dun ) { - _http_hgen_send(gen_u); - } -} - -/* _http_start_respond(): write a [%http-response %start ...] to h2o_req_t->res -*/ -static void -_http_start_respond(u3_hreq* req_u, - u3_noun status, - u3_noun headers, - u3_noun data, - u3_noun complete) -{ - // u3l_log("start"); - - if ( u3_rsat_plan != req_u->sat_e ) { - //u3l_log("duplicate response"); - return; - } - - req_u->sat_e = u3_rsat_ripe; - - uv_timer_stop(req_u->tim_u); - - h2o_req_t* rec_u = req_u->rec_u; - - rec_u->res.status = status; - rec_u->res.reason = (status < 200) ? "weird" : - (status < 300) ? "ok" : - (status < 400) ? "moved" : - (status < 500) ? "missing" : - "hosed"; - - u3_hhed* hed_u = _http_heds_from_noun(u3k(headers)); - u3_hhed* deh_u = hed_u; - - c3_i has_len_i = 0; - - while ( 0 != hed_u ) { - if ( 0x200 <= rec_u->version ) { - h2o_strtolower(hed_u->nam_c, hed_u->nam_w); - - if ( 0 == strncmp(hed_u->nam_c, "connection", 10) ) { - hed_u = hed_u->nex_u; - continue; - } - } - if ( 0 == strncmp(hed_u->nam_c, "content-length", 14) ) { - has_len_i = 1; - } - else { - h2o_add_header_by_str(&rec_u->pool, &rec_u->res.headers, - hed_u->nam_c, hed_u->nam_w, 0, 0, - hed_u->val_c, hed_u->val_w); - } - - hed_u = hed_u->nex_u; - } - - u3_hgen* gen_u = h2o_mem_alloc_shared(&rec_u->pool, sizeof(*gen_u), - _http_hgen_dispose); - gen_u->neg_u = (h2o_generator_t){ _http_hgen_proceed, _http_hgen_stop }; - gen_u->red = c3y; - gen_u->dun = complete; - gen_u->bod_u = ( u3_nul == data ) ? - 0 : _cttp_bod_from_octs(u3k(u3t(data))); - gen_u->nud_u = 0; - gen_u->hed_u = deh_u; - gen_u->req_u = req_u; - - // if we don't explicitly set this field, h2o will send with - // transfer-encoding: chunked - // - if ( 1 == has_len_i ) { - rec_u->res.content_length = ( 0 == gen_u->bod_u ) ? - 0 : gen_u->bod_u->len_w; - } - - req_u->gen_u = gen_u; - - h2o_start_response(rec_u, &gen_u->neg_u); - - _http_hgen_send(gen_u); - - u3z(status); u3z(headers); u3z(data); u3z(complete); -} - -/* _http_continue_respond(): write a [%http-response %continue ...] to - * h2o_req_t->res -*/ -static void -_http_continue_respond(u3_hreq* req_u, - /* u3_noun status, */ - /* u3_noun headers, */ - u3_noun data, - u3_noun complete) -{ - // u3l_log("continue"); - - // XX add sequence numbers for %continue effects? - // Arvo does not (currently) guarantee effect idempotence!! - - // response has not yet been started - if ( u3_rsat_ripe != req_u->sat_e ) { - // u3l_log("duplicate response"); - return; - } - - u3_hgen* gen_u = req_u->gen_u; - - uv_timer_stop(req_u->tim_u); - - // XX proposed sequence number safety check - // if ( sequence <= gen_u->sequence ) { - // return; - // } - // - // c3_assert( sequence == ++gen_u->sequence ); - - gen_u->dun = complete; - - if ( u3_nul != data ) { - u3_hbod* bod_u = _cttp_bod_from_octs(u3k(u3t(data))); - - if ( 0 == gen_u->bod_u ) { - gen_u->bod_u = bod_u; - } - else { - u3_hbod* pre_u = gen_u->bod_u; - - while ( 0 != pre_u->nex_u ) { - pre_u = pre_u->nex_u; - } - - pre_u->nex_u = bod_u; - } - } - - if ( c3y == gen_u->red ) { - _http_hgen_send(gen_u); - } - - u3z(data); u3z(complete); -} - -/* _http_rec_to_httq(): convert h2o_req_t to httq -*/ -static u3_weak -_http_rec_to_httq(h2o_req_t* rec_u) -{ - u3_noun med = _http_vec_to_meth(rec_u->method); - - if ( u3_none == med ) { - return u3_none; - } - - u3_noun url = _http_vec_to_atom(rec_u->path); - u3_noun hed = _http_heds_to_noun(rec_u->headers.entries, - rec_u->headers.size); - - // restore host header - hed = u3nc(u3nc(u3i_string("host"), - _http_vec_to_atom(rec_u->authority)), - hed); - - u3_noun bod = _http_vec_to_octs(rec_u->entity); - - return u3nq(med, url, hed, bod); -} - -typedef struct _h2o_uv_sock { // see private st_h2o_uv_socket_t - h2o_socket_t sok_u; // socket - uv_stream_t* han_u; // client stream handler (u3_hcon) -} h2o_uv_sock; - -/* _http_rec_sock(): u3 http connection from h2o request; hacky. -*/ -static u3_hcon* -_http_rec_sock(h2o_req_t* rec_u) -{ - h2o_uv_sock* suv_u = (h2o_uv_sock*)rec_u->conn-> - callbacks->get_socket(rec_u->conn); - u3_hcon* hon_u = (u3_hcon*)suv_u->han_u; - - // sanity check - // - c3_assert( hon_u->sok_u == &suv_u->sok_u ); - - return hon_u; -} - -/* _http_req_prepare(): creates u3 req from h2o req and initializes its timer -*/ -static u3_hreq* -_http_req_prepare(h2o_req_t* rec_u, - u3_hreq* (*new_f)(u3_hcon*, h2o_req_t*)) -{ - u3_hcon* hon_u = _http_rec_sock(rec_u); - u3_hreq* seq_u = new_f(hon_u, rec_u); - - seq_u->tim_u = c3_malloc(sizeof(*seq_u->tim_u)); - seq_u->tim_u->data = seq_u; - uv_timer_init(u3L, seq_u->tim_u); - uv_timer_start(seq_u->tim_u, _http_req_timer_cb, 600 * 1000, 0); - - return seq_u; -} - -/* _http_seq_continue(): respond to slogstream request based on auth scry result -*/ -static void -_http_seq_continue(void* vod_p, u3_noun nun) -{ - h2o_req_t* rec_u = vod_p; - u3_weak aut = u3r_at(7, nun); - - // if the request is authenticated properly, send slogstream/sse headers - // - //TODO authentication might expire after the connection has been opened! - // eyre could notify us about this, or we could re-check periodically. - // - if ( c3y == aut ) { - u3_hreq* req_u = _http_req_prepare(rec_u, _http_seq_new); - u3_noun hed = u3nl(u3nc(u3i_string("Content-Type"), - u3i_string("text/event-stream")), - u3nc(u3i_string("Cache-Control"), - u3i_string("no-cache")), - u3nc(u3i_string("Connection"), - u3i_string("keep-alive")), - u3_none); - - _http_start_respond(req_u, 200, hed, u3_nul, c3n); - } - // if the scry failed, the result is unexpected, or there is no auth, - // respond with the appropriate status code - // - else { - //NOTE we use req_new because we don't want to consider this a slog stream - // request, but this means we need to manually skip past the "in event - // queue" state on the hreq. - u3_hreq* req_u = _http_req_prepare(rec_u, _http_req_new); - req_u->sat_e = u3_rsat_plan; - - if ( c3n == aut ) { - _http_start_respond(req_u, 403, u3_nul, u3_nul, c3y); - } - else if ( u3_none == aut ) { - u3l_log("http: authentication scry failed"); - _http_start_respond(req_u, 500, u3_nul, u3_nul, c3y); - } - else { - u3m_p("http: weird authentication scry result", aut); - _http_start_respond(req_u, 500, u3_nul, u3_nul, c3y); - } - } - - u3z(nun); -} - -/* _http_seq_accept(): handle incoming http request on slogstream endpoint -*/ -static c3_i -_http_seq_accept(h2o_handler_t* han_u, h2o_req_t* rec_u) -{ - // try to find a cookie header - // - u3_weak coo = u3_none; - { - //TODO http2 allows the client to put multiple 'cookie' headers - ssize_t hin_i = h2o_find_header_by_str(&rec_u->headers, "cookie", 6, -1); - if ( hin_i != -1 ) { - coo = _http_vec_to_atom(rec_u->headers.entries[hin_i].value); - } - } - - // if there is no cookie header, it can't possibly be authenticated - // - if ( u3_none == coo ) { - u3_hreq* req_u = _http_req_prepare(rec_u, _http_req_new); - req_u->sat_e = u3_rsat_plan; - _http_start_respond(req_u, 403, u3_nul, u3_nul, c3y); - } - // if there is a cookie, scry to see if it constitutes authentication - // - else { - u3_hcon* hon_u = _http_rec_sock(rec_u); - - u3_noun pax = u3nq(u3i_string("authenticated"), - u3i_string("cookie"), - u3dc("scot", 't', coo), - u3_nul); - u3_pier_peek_last(hon_u->htp_u->htd_u->car_u.pir_u, u3_nul, c3__ex, - u3_nul, pax, rec_u, _http_seq_continue); - } - - return 0; -} - -/* _http_sat_accept(): handle incoming http request on status endpoint -*/ -static c3_i -_http_sat_accept(h2o_handler_t* han_u, h2o_req_t* rec_u) -{ - c3_o bus_o; - { - u3_hcon* hon_u = _http_rec_sock(rec_u); - u3_httd* htd_u = hon_u->htp_u->htd_u; - u3_pier* pir_u = htd_u->car_u.pir_u; - bus_o = pir_u->god_u->pin_o; - } - - if ( c3y == bus_o ) { - rec_u->res.status = 429; - rec_u->res.reason = "busy"; - } - else { - rec_u->res.status = 204; - rec_u->res.reason = "no content"; - } - - rec_u->res.content_length = 0; - h2o_send_inline(rec_u, NULL, 0); - - return 0; -} - -/* _http_rec_accept(); handle incoming http request from h2o. -*/ -static c3_i -_http_rec_accept(h2o_handler_t* han_u, h2o_req_t* rec_u) -{ - u3_weak req = _http_rec_to_httq(rec_u); - - if ( u3_none == req ) { - if ( (u3C.wag_w & u3o_verbose) ) { - u3l_log("strange %.*s request", (c3_i)rec_u->method.len, - rec_u->method.base); - } - c3_c* msg_c = "bad request"; - h2o_send_error_generic(rec_u, 400, msg_c, msg_c, 0); - } - else { - u3_hreq* req_u = _http_req_prepare(rec_u, _http_req_new); - _http_req_dispatch(req_u, req); - } - - return 0; -} - -/* _http_conn_find(): find http connection in server by sequence. -*/ -static u3_hcon* -_http_conn_find(u3_http *htp_u, c3_w coq_l) -{ - u3_hcon* hon_u = htp_u->hon_u; - - // XX glories of linear search - // - while ( hon_u ) { - if ( coq_l == hon_u->coq_l ) { - return hon_u; - } - hon_u = hon_u->nex_u; - } - return 0; -} - -/* _http_conn_link(): link http request to connection -*/ -static void -_http_conn_link(u3_http* htp_u, u3_hcon* hon_u) -{ - hon_u->htp_u = htp_u; - hon_u->coq_l = htp_u->coq_l++; - hon_u->nex_u = htp_u->hon_u; - - if ( 0 != hon_u->nex_u ) { - hon_u->nex_u->pre_u = hon_u; - } - htp_u->hon_u = hon_u; -} - -/* _http_conn_unlink(): remove http request from connection -*/ -static void -_http_conn_unlink(u3_hcon* hon_u) -{ - if ( 0 != hon_u->pre_u ) { - hon_u->pre_u->nex_u = hon_u->nex_u; - - if ( 0 != hon_u->nex_u ) { - hon_u->nex_u->pre_u = hon_u->pre_u; - } - } - else { - hon_u->htp_u->hon_u = hon_u->nex_u; - - if ( 0 != hon_u->nex_u ) { - hon_u->nex_u->pre_u = 0; - } - } -} - -/* _http_conn_free(): free http connection on close. -*/ -static void -_http_conn_free(uv_handle_t* han_t) -{ - u3_hcon* hon_u = (u3_hcon*)han_t; - u3_http* htp_u = hon_u->htp_u; - u3_h2o_serv* h2o_u = htp_u->h2o_u; - - c3_assert( 0 == hon_u->req_u ); - -#if 0 - { - c3_w len_w = 0; - - u3_hcon* noh_u = htp_u->hon_u; - - while ( 0 != noh_u ) { - len_w++; - noh_u = noh_u->nex_u; - } - - u3l_log("http conn free %d of %u server %d", hon_u->coq_l, len_w, htp_u->sev_l); - } -#endif - - _http_conn_unlink(hon_u); - -#if 0 - { - c3_w len_w = 0; - - u3_hcon* noh_u = htp_u->hon_u; - - while ( 0 != noh_u ) { - len_w++; - noh_u = noh_u->nex_u; - } - - u3l_log("http conn free %u remaining", len_w); - } -#endif - - if ( (0 == htp_u->hon_u) && (0 != h2o_u->ctx_u.shutdown_requested) ) { -#if 0 - u3l_log("http conn free %d free server %d", hon_u->coq_l, htp_u->sev_l); -#endif - _http_serv_free(htp_u); - } - - c3_free(hon_u); -} - -/* _http_conn_new(): create and accept http connection. -*/ -static u3_hcon* -_http_conn_new(u3_http* htp_u) -{ - u3_hcon* hon_u = c3_malloc(sizeof(*hon_u)); - hon_u->seq_l = 1; - hon_u->ipf_w = 0; - hon_u->req_u = 0; - hon_u->sok_u = 0; - hon_u->con_u = 0; - hon_u->pre_u = 0; - - _http_conn_link(htp_u, hon_u); - -#if 0 - u3l_log("http conn neww %d server %d", hon_u->coq_l, htp_u->sev_l); -#endif - - return hon_u; -} - -/* _http_serv_find(): find http server by sequence. -*/ -static u3_http* -_http_serv_find(u3_httd* htd_u, c3_l sev_l) -{ - u3_http* htp_u = htd_u->htp_u; - - // XX glories of linear search - // - while ( htp_u ) { - if ( sev_l == htp_u->sev_l ) { - return htp_u; - } - htp_u = htp_u->nex_u; - } - return 0; -} - -/* _http_serv_link(): link http server to global state. -*/ -static void -_http_serv_link(u3_httd* htd_u, u3_http* htp_u) -{ - // XX link elsewhere initially, relink on start? - - if ( 0 != htd_u->htp_u ) { - htp_u->sev_l = 1 + htd_u->htp_u->sev_l; - } - else { - htp_u->sev_l = htd_u->sev_l; - } - - htp_u->nex_u = htd_u->htp_u; - htp_u->htd_u = htd_u; - htd_u->htp_u = htp_u; -} - -/* _http_serv_unlink(): remove http server from global state. -*/ -static void -_http_serv_unlink(u3_http* htp_u) -{ - // XX link elsewhere initially, relink on start? -#if 0 - u3l_log("http serv unlink %d", htp_u->sev_l); -#endif - u3_http* pre_u = htp_u->htd_u->htp_u; - - if ( pre_u == htp_u ) { - pre_u = htp_u->nex_u; - } - else { - // XX glories of linear search - // - while ( pre_u ) { - if ( pre_u->nex_u == htp_u ) { - pre_u->nex_u = htp_u->nex_u; - } - else pre_u = pre_u->nex_u; - } - } -} - -/* _http_h2o_context_dispose(): h2o_context_dispose, inlined and cleaned up. -*/ -static void -_http_h2o_context_dispose(h2o_context_t* ctx) -{ - h2o_globalconf_t *config = ctx->globalconf; - size_t i, j; - - for (i = 0; config->hosts[i] != NULL; ++i) { - h2o_hostconf_t *hostconf = config->hosts[i]; - for (j = 0; j != hostconf->paths.size; ++j) { - h2o_pathconf_t *pathconf = hostconf->paths.entries + j; - h2o_context_dispose_pathconf_context(ctx, pathconf); - } - h2o_context_dispose_pathconf_context(ctx, &hostconf->fallback_path); - } - - c3_free(ctx->_pathconfs_inited.entries); - c3_free(ctx->_module_configs); - - h2o_timeout_dispose(ctx->loop, &ctx->zero_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->hundred_ms_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->handshake_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->http1.req_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->http2.idle_timeout); - - // NOTE: linked in http2/connection, never unlinked - h2o_timeout_unlink(&ctx->http2._graceful_shutdown_timeout); - - h2o_timeout_dispose(ctx->loop, &ctx->http2.graceful_shutdown_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->proxy.io_timeout); - h2o_timeout_dispose(ctx->loop, &ctx->one_sec_timeout); - - h2o_filecache_destroy(ctx->filecache); - ctx->filecache = NULL; - - /* clear storage */ - for (i = 0; i != ctx->storage.size; ++i) { - h2o_context_storage_item_t *item = ctx->storage.entries + i; - if (item->dispose != NULL) { - item->dispose(item->data); - } - } - - c3_free(ctx->storage.entries); - - h2o_multithread_unregister_receiver(ctx->queue, &ctx->receivers.hostinfo_getaddr); - h2o_multithread_destroy_queue(ctx->queue); - - if (ctx->_timestamp_cache.value != NULL) { - h2o_mem_release_shared(ctx->_timestamp_cache.value); - } - - // NOTE: explicit uv_run removed -} - -/* _http_serv_really_free(): free http server. -*/ -static void -_http_serv_really_free(u3_http* htp_u) -{ - c3_assert( 0 == htp_u->hon_u ); - - if ( 0 != htp_u->h2o_u ) { - u3_h2o_serv* h2o_u = htp_u->h2o_u; - - if ( 0 != h2o_u->cep_u.ssl_ctx ) { - SSL_CTX_free(h2o_u->cep_u.ssl_ctx); - } - - h2o_config_dispose(&h2o_u->fig_u); - - // XX h2o_cleanup_thread if not restarting? - - c3_free(htp_u->h2o_u); - htp_u->h2o_u = 0; - } - - _http_serv_unlink(htp_u); - c3_free(htp_u); -} - -/* http_serv_free_cb(): timer callback for freeing http server. -*/ -static void -http_serv_free_cb(uv_timer_t* tim_u) -{ - u3_http* htp_u = tim_u->data; - -#if 0 - u3l_log("http serv free cb %d", htp_u->sev_l); -#endif - - _http_serv_really_free(htp_u); - - uv_close((uv_handle_t*)tim_u, _http_close_cb); -} - -/* _http_serv_free(): begin to free http server. -*/ -static void -_http_serv_free(u3_http* htp_u) -{ -#if 0 - u3l_log("http serv free %d", htp_u->sev_l); -#endif - - c3_assert( 0 == htp_u->hon_u ); - - if ( 0 == htp_u->h2o_u ) { - _http_serv_really_free(htp_u); - } - else { - u3_h2o_serv* h2o_u = htp_u->h2o_u; - - _http_h2o_context_dispose(&h2o_u->ctx_u); - - // NOTE: free deferred to allow timers to be closed - // this is a heavy-handed workaround for the lack of - // close callbacks in h2o_timer_t - // it's unpredictable how many event-loop turns will - // be required to finish closing the underlying uv_timer_t - // and we can't free until that's done (or we have UB) - // testing reveals 5s to be a long enough deferral - uv_timer_t* tim_u = c3_malloc(sizeof(*tim_u)); - - tim_u->data = htp_u; - - uv_timer_init(u3L, tim_u); - uv_timer_start(tim_u, http_serv_free_cb, 5000, 0); - } -} - -/* _http_serv_close_cb(): http server uv_close callback. -*/ -static void -_http_serv_close_cb(uv_handle_t* han_u) -{ - u3_http* htp_u = (u3_http*)han_u; - u3_httd* htd_u = htp_u->htd_u; - htp_u->liv = c3n; - - // otherwise freed by the last linked connection - if ( 0 == htp_u->hon_u ) { - _http_serv_free(htp_u); - } - - // restart if all linked servers have been shutdown - { - htp_u = htd_u->htp_u; - c3_o res = c3y; - - while ( 0 != htp_u ) { - if ( c3y == htp_u->liv ) { - res = c3n; - } - htp_u = htp_u->nex_u; - } - - if ( (c3y == res) && (0 != htd_u->fig_u.for_u) ) { - _http_serv_start_all(htd_u); - } - } -} - -/* _http_serv_close(): close http server gracefully. -*/ -static void -_http_serv_close(u3_http* htp_u) -{ - u3_h2o_serv* h2o_u = htp_u->h2o_u; - h2o_context_request_shutdown(&h2o_u->ctx_u); - -#if 0 - u3l_log("http serv close %d %p", htp_u->sev_l, &htp_u->wax_u); -#endif - - uv_close((uv_handle_t*)&htp_u->wax_u, _http_serv_close_cb); -} - -/* _http_serv_new(): create new http server. -*/ -static u3_http* -_http_serv_new(u3_httd* htd_u, c3_s por_s, c3_o dis, c3_o sec, c3_o lop) -{ - u3_http* htp_u = c3_malloc(sizeof(*htp_u)); - - htp_u->coq_l = 1; - htp_u->por_s = por_s; - htp_u->dis = dis; - htp_u->sec = sec; - htp_u->lop = lop; - htp_u->liv = c3y; - htp_u->h2o_u = 0; - htp_u->hon_u = 0; - htp_u->nex_u = 0; - - _http_serv_link(htd_u, htp_u); - - return htp_u; -} - -/* _http_serv_accept(): accept new http connection. -*/ -static void -_http_serv_accept(u3_http* htp_u) -{ - u3_hcon* hon_u = _http_conn_new(htp_u); - - uv_tcp_init(u3L, &hon_u->wax_u); - - c3_i sas_i; - - if ( 0 != (sas_i = uv_accept((uv_stream_t*)&htp_u->wax_u, - (uv_stream_t*)&hon_u->wax_u)) ) { - if ( (u3C.wag_w & u3o_verbose) ) { - u3l_log("http: accept: %s", uv_strerror(sas_i)); - } - - uv_close((uv_handle_t*)&hon_u->wax_u, _http_conn_free); - return; - } - - hon_u->sok_u = h2o_uv_socket_create((uv_stream_t*)&hon_u->wax_u, - _http_conn_free); - - h2o_accept(&((u3_h2o_serv*)htp_u->h2o_u)->cep_u, hon_u->sok_u); - - // capture h2o connection (XX fragile) - hon_u->con_u = (h2o_conn_t*)hon_u->sok_u->data; - - struct sockaddr_in adr_u; - h2o_socket_getpeername(hon_u->sok_u, (struct sockaddr*)&adr_u); - hon_u->ipf_w = ( adr_u.sin_family != AF_INET ) ? - 0 : ntohl(adr_u.sin_addr.s_addr); -} - -/* _http_serv_listen_cb(): uv_connection_cb for uv_listen -*/ -static void -_http_serv_listen_cb(uv_stream_t* str_u, c3_i sas_i) -{ - u3_http* htp_u = (u3_http*)str_u; - - if ( 0 != sas_i ) { - u3l_log("http: listen_cb: %s", uv_strerror(sas_i)); - } - else { - _http_serv_accept(htp_u); - } -} - -/* _http_serv_init_h2o(): initialize h2o ctx and handlers for server. -*/ -static u3_h2o_serv* -_http_serv_init_h2o(SSL_CTX* tls_u, c3_o log, c3_o red) -{ - u3_h2o_serv* h2o_u = c3_calloc(sizeof(*h2o_u)); - - h2o_config_init(&h2o_u->fig_u); - h2o_u->fig_u.server_name = h2o_iovec_init( - H2O_STRLIT("urbit/vere-" URBIT_VERSION)); - - // set maximum request size to 512 MiB - // - h2o_u->fig_u.max_request_entity_size = 512 * 1024 * 1024; - - // XX default pending vhost/custom-domain design - // XX revisit the effect of specifying the port - h2o_u->hos_u = h2o_config_register_host(&h2o_u->fig_u, - h2o_iovec_init(H2O_STRLIT("default")), - 65535); - - h2o_u->cep_u.ctx = (h2o_context_t*)&h2o_u->ctx_u; - h2o_u->cep_u.hosts = h2o_u->fig_u.hosts; - h2o_u->cep_u.ssl_ctx = tls_u; - - h2o_u->han_u = h2o_create_handler(&h2o_u->hos_u->fallback_path, - sizeof(*h2o_u->han_u)); - if ( c3y == red ) { - // XX h2o_redirect_register - h2o_u->han_u->on_req = _http_rec_accept; - } - else { - h2o_u->han_u->on_req = _http_rec_accept; - } - - // register runtime endpoints - // - { - h2o_pathconf_t* pac_u; - h2o_handler_t* han_u; - - // slog stream - // - pac_u = h2o_config_register_path(h2o_u->hos_u, "/~_~/slog", 0); - han_u = h2o_create_handler(pac_u, sizeof(*han_u)); - han_u->on_req = _http_seq_accept; - - // status (per spinner) - // - pac_u = h2o_config_register_path(h2o_u->hos_u, "/~_~/healthz", 0); - han_u = h2o_create_handler(pac_u, sizeof(*han_u)); - han_u->on_req = _http_sat_accept; - } - - if ( c3y == log ) { - // XX move this to post serv_start and put the port in the name -#if 0 - c3_c* pax_c = u3_Host.dir_c; - u3_noun now = u3dc("scot", c3__da, u3k(u3A->now)); - c3_c* now_c = u3r_string(now); - c3_c* nam_c = ".access.log"; - c3_w len_w = 1 + strlen(pax_c) + 1 + strlen(now_c) + strlen(nam_c); - - c3_c* paf_c = c3_malloc(len_w); - snprintf(paf_c, len_w, "%s/%s%s", pax_c, now_c, nam_c); - - h2o_access_log_filehandle_t* fil_u = - h2o_access_log_open_handle(paf_c, 0, H2O_LOGCONF_ESCAPE_APACHE); - - h2o_access_log_register(&h2o_u->hos_u->fallback_path, fil_u); - - c3_free(paf_c); - c3_free(now_c); - u3z(now); -#endif - } - - // XX h2o_compress_register - - h2o_context_init(&h2o_u->ctx_u, u3L, &h2o_u->fig_u); - - return h2o_u; -} - -/* _http_serv_start(): start http server. -*/ -static void -_http_serv_start(u3_http* htp_u) -{ - u3_pier* pir_u = htp_u->htd_u->car_u.pir_u; - struct sockaddr_in adr_u; - - memset(&adr_u, 0, sizeof(adr_u)); - adr_u.sin_family = AF_INET; - adr_u.sin_addr.s_addr = ( c3y == htp_u->lop ) ? - htonl(INADDR_LOOPBACK) : - INADDR_ANY; - - if ( 0 != u3_Host.ops_u.bin_c && c3n == htp_u->lop ) { - inet_pton(AF_INET, u3_Host.ops_u.bin_c, &adr_u.sin_addr); - } - - uv_tcp_init(u3L, &htp_u->wax_u); - - /* Try ascending ports. - */ - while ( 1 ) { - c3_i sas_i; - - adr_u.sin_port = htons(htp_u->por_s); - - if ( 0 != (sas_i = uv_tcp_bind(&htp_u->wax_u, - (const struct sockaddr*)&adr_u, 0)) || - 0 != (sas_i = uv_listen((uv_stream_t*)&htp_u->wax_u, - TCP_BACKLOG, _http_serv_listen_cb)) ) { - if ( UV_EADDRNOTAVAIL == sas_i ) { - u3l_log("http: ip address not available\n"); - u3_king_bail(); - } - if ( c3y == htp_u->dis ) { - u3l_log("http: listen (%" PRIu16 "): %s\n", htp_u->por_s, - uv_strerror(sas_i)); - u3_king_bail(); - } - if ( (UV_EADDRINUSE == sas_i) || (UV_EACCES == sas_i) ) { - if ( (c3y == htp_u->sec) && (443 == htp_u->por_s) ) { - htp_u->por_s = 8443; - } - else if ( (c3n == htp_u->sec) && (80 == htp_u->por_s) ) { - htp_u->por_s = 8080; - } - else { - htp_u->por_s++; - // XX - // - if ( c3n == htp_u->lop ) { - if ( c3y == htp_u->sec ) { - pir_u->pes_s = htp_u->por_s; - } - else { - pir_u->per_s = htp_u->por_s; - } - } - } - - continue; - } - - u3l_log("http: listen: %s\n", uv_strerror(sas_i)); - - _http_serv_free(htp_u); - return; - } - - u3l_log("http: %s live on %s://localhost:%d", - (c3y == htp_u->lop) ? "loopback" : "web interface", - (c3y == htp_u->sec) ? "https" : "http", - htp_u->por_s); - - break; - } -} - -static uv_buf_t -_http_wain_to_buf(u3_noun wan) -{ - c3_w len_w = u3_mcut_path(0, 0, (c3_c)10, u3k(wan)); - c3_c* buf_c = c3_malloc(1 + len_w); - - u3_mcut_path(buf_c, 0, (c3_c)10, wan); - buf_c[len_w] = 0; - - return uv_buf_init(buf_c, len_w); -} - -/* _http_init_tls: initialize OpenSSL context -*/ -static SSL_CTX* -_http_init_tls(uv_buf_t key_u, uv_buf_t cer_u) -{ - // XX require 1.1.0 and use TLS_server_method() - SSL_CTX* tls_u = SSL_CTX_new(SSLv23_server_method()); - // XX use SSL_CTX_set_max_proto_version() and SSL_CTX_set_min_proto_version() - SSL_CTX_set_options(tls_u, SSL_OP_NO_SSLv2 | - SSL_OP_NO_SSLv3 | - // SSL_OP_NO_TLSv1 | // XX test - SSL_OP_NO_COMPRESSION); - - SSL_CTX_set_default_verify_paths(tls_u); - SSL_CTX_set_session_cache_mode(tls_u, SSL_SESS_CACHE_OFF); - SSL_CTX_set_cipher_list(tls_u, - "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:" - "ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:" - "RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS"); - - // enable ALPN for HTTP 2 support -#if H2O_USE_ALPN - { - SSL_CTX_set_ecdh_auto(tls_u, 1); - h2o_ssl_register_alpn_protocols(tls_u, h2o_http2_alpn_protocols); - } -#endif - - { - BIO* bio_u = BIO_new_mem_buf(key_u.base, key_u.len); - EVP_PKEY* pky_u = PEM_read_bio_PrivateKey(bio_u, 0, 0, 0); - c3_i sas_i = SSL_CTX_use_PrivateKey(tls_u, pky_u); - - EVP_PKEY_free(pky_u); - BIO_free(bio_u); - - if( 0 == sas_i ) { - u3l_log("http: load private key failed:"); - FILE* fil_u = u3_term_io_hija(); - ERR_print_errors_fp(fil_u); - u3_term_io_loja(1, fil_u); - - SSL_CTX_free(tls_u); - - return 0; - } - } - - { - BIO* bio_u = BIO_new_mem_buf(cer_u.base, cer_u.len); - X509* xer_u = PEM_read_bio_X509_AUX(bio_u, 0, 0, 0); - c3_i sas_i = SSL_CTX_use_certificate(tls_u, xer_u); - - X509_free(xer_u); - - if( 0 == sas_i ) { - u3l_log("http: load certificate failed:"); - FILE* fil_u = u3_term_io_hija(); - ERR_print_errors_fp(fil_u); - u3_term_io_loja(1,fil_u); - - BIO_free(bio_u); - SSL_CTX_free(tls_u); - - return 0; - } - - // get any additional CA certs, ignoring errors - while ( 0 != (xer_u = PEM_read_bio_X509(bio_u, 0, 0, 0)) ) { - // XX require 1.0.2 or newer and use SSL_CTX_add0_chain_cert - SSL_CTX_add_extra_chain_cert(tls_u, xer_u); - } - - BIO_free(bio_u); - } - - return tls_u; -} - -/* _http_write_ports_file(): update .http.ports -*/ -static void -_http_write_ports_file(u3_httd* htd_u, c3_c *pax_c) -{ - c3_c* nam_c = ".http.ports"; - c3_w len_w = 1 + strlen(pax_c) + 1 + strlen(nam_c); - - c3_c* paf_c = c3_malloc(len_w); - snprintf(paf_c, len_w, "%s/%s", pax_c, nam_c); - - c3_i por_i = c3_open(paf_c, O_WRONLY | O_CREAT | O_TRUNC, 0666); - c3_free(paf_c); - - u3_http* htp_u = htd_u->htp_u; - u3_pier* pir_u = htd_u->car_u.pir_u; - - c3_c temp[32]; - while ( 0 != htp_u ) { - if ( 0 < htp_u->por_s ) { - u3_write_fd(por_i, temp, snprintf(temp, 32, "%u %s %s\n", htp_u->por_s, - (c3y == htp_u->sec) ? "secure" : "insecure", - (c3y == htp_u->lop) ? "loopback" : "public")); - } - - htp_u = htp_u->nex_u; - } - - c3_sync(por_i); - close(por_i); -} - -/* _http_release_ports_file(): remove .http.ports -*/ -static void -_http_release_ports_file(c3_c *pax_c) -{ - c3_c* nam_c = ".http.ports"; - c3_w len_w = 1 + strlen(pax_c) + 1 + strlen(nam_c); - c3_c* paf_c = c3_malloc(len_w); - c3_i wit_i; - - wit_i = snprintf(paf_c, len_w, "%s/%s", pax_c, nam_c); - c3_assert(wit_i > 0); - c3_assert(len_w == (c3_w)wit_i + 1); - - c3_unlink(paf_c); - c3_free(paf_c); -} - -static u3_hreq* -_http_search_req(u3_httd* htd_u, - c3_l sev_l, - c3_l coq_l, - c3_l seq_l) -{ - u3_http* htp_u; - u3_hcon* hon_u; - u3_hreq* req_u; - c3_w bug_w = u3C.wag_w & u3o_verbose; - - if ( !(htp_u = _http_serv_find(htd_u, sev_l)) ) { - if ( bug_w ) { - u3l_log("http: server not found: %x", sev_l); - } - return 0; - } - else if ( !(hon_u = _http_conn_find(htp_u, coq_l)) ) { - if ( bug_w ) { - u3l_log("http: connection not found: %x/%d", sev_l, coq_l); - } - return 0; - } - else if ( !(req_u = _http_req_find(hon_u, seq_l)) ) { - if ( bug_w ) { - u3l_log("http: request not found: %x/%d/%d", - sev_l, coq_l, seq_l); - } - return 0; - } - - return req_u; -} - -/* _http_serv_start_all(): initialize and start servers based on saved config. -*/ -static void -_http_serv_start_all(u3_httd* htd_u) -{ - u3_http* htp_u; - u3_pier* pir_u = htd_u->car_u.pir_u; - c3_s por_s; - u3_noun sec = u3_nul; - u3_noun non = u3_none; - u3_noun dis; - u3_form* for_u = htd_u->fig_u.for_u; - - c3_assert( 0 != for_u ); - - // if the SSL_CTX existed, it'll be freed with the servers - htd_u->tls_u = 0; - - // HTTPS server. - if ( (0 != for_u->key_u.base) && (0 != for_u->cer_u.base) ) { - htd_u->tls_u = _http_init_tls(for_u->key_u, for_u->cer_u); - - // Note: if tls_u is used for additional servers, - // its reference count must be incremented with SSL_CTX_up_ref - - if ( 0 != htd_u->tls_u ) { - if ( 0 == pir_u->pes_s ) { - por_s = ( c3y == for_u->pro ) ? 8443 : 443; - dis = c3n; - } - else { - por_s = pir_u->pes_s; - dis = c3y; - } - htp_u = _http_serv_new(htd_u, por_s, dis, c3y, c3n); - htp_u->h2o_u = _http_serv_init_h2o(htd_u->tls_u, for_u->log, for_u->red); - - _http_serv_start(htp_u); - sec = u3nc(u3_nul, htp_u->por_s); - } - } - - // HTTP server. - { - if ( 0 == pir_u->per_s ) { - por_s = ( c3y == for_u->pro ) ? 8080 : 80; - dis = c3n; - } - else { - por_s = pir_u->per_s; - dis = c3y; - } - htp_u = _http_serv_new(htd_u, por_s, dis, c3n, c3n); - htp_u->h2o_u = _http_serv_init_h2o(0, for_u->log, for_u->red); - - _http_serv_start(htp_u); - non = htp_u->por_s; - } - - // Loopback server. - { - por_s = 12321; - htp_u = _http_serv_new(htd_u, por_s, c3n, c3n, c3y); - htp_u->h2o_u = _http_serv_init_h2o(0, for_u->log, for_u->red); - - _http_serv_start(htp_u); - } - - // send listening ports to %eyre - { - c3_assert( u3_none != non ); - - // XX remove [sen] - // - u3_noun wir = u3nt(u3i_string("http-server"), - u3dc("scot", c3__uv, htd_u->sev_l), - u3_nul); - u3_noun cad = u3nt(c3__live, non, sec); - - u3_auto_plan(&htd_u->car_u, u3_ovum_init(0, c3__e, wir, cad)); - } - - _http_write_ports_file(htd_u, u3_Host.dir_c); - _http_form_free(htd_u); -} - -/* _http_serv_restart(): gracefully shutdown, then start servers. -*/ -static void -_http_serv_restart(u3_httd* htd_u) -{ - u3_http* htp_u = htd_u->htp_u; - - if ( 0 == htp_u ) { - _http_serv_start_all(htd_u); - } - else { - u3l_log("http: restarting servers to apply configuration"); - - while ( 0 != htp_u ) { - if ( c3y == htp_u->liv ) { - _http_serv_close(htp_u); - } - htp_u = htp_u->nex_u; - } - - _http_release_ports_file(u3_Host.dir_c); - } -} - -/* _http_form_free(): free and unlink saved config. -*/ -static void -_http_form_free(u3_httd* htd_u) -{ - u3_form* for_u = htd_u->fig_u.for_u; - - if ( 0 == for_u ) { - return; - } - - if ( 0 != for_u->key_u.base ) { - c3_free(for_u->key_u.base); - } - - if ( 0 != for_u->cer_u.base ) { - c3_free(for_u->cer_u.base); - } - - c3_free(for_u); - htd_u->fig_u.for_u = 0; -} - -/* u3_http_ef_form(): apply configuration, restart servers. -*/ -void -u3_http_ef_form(u3_httd* htd_u, u3_noun fig) -{ - u3_noun sec, pro, log, red; - - if ( (c3n == u3r_qual(fig, &sec, &pro, &log, &red) ) || - // confirm sec is a valid (unit ^) - !( u3_nul == sec || ( c3y == u3du(sec) && - c3y == u3du(u3t(sec)) && - u3_nul == u3h(sec) ) ) || - // confirm valid flags ("loobeans") - !( c3y == pro || c3n == pro ) || - !( c3y == log || c3n == log ) || - !( c3y == red || c3n == red ) ) { - u3l_log("http: form: invalid card"); - u3z(fig); - return; - } - - u3_form* for_u = c3_malloc(sizeof(*for_u)); - for_u->pro = (c3_o)pro; - for_u->log = (c3_o)log; - for_u->red = (c3_o)red; - - if ( u3_nul != sec ) { - u3_noun key = u3h(u3t(sec)); - u3_noun cer = u3t(u3t(sec)); - - for_u->key_u = _http_wain_to_buf(u3k(key)); - for_u->cer_u = _http_wain_to_buf(u3k(cer)); - } - else { - for_u->key_u = uv_buf_init(0, 0); - for_u->cer_u = uv_buf_init(0, 0); - } - - u3z(fig); - _http_form_free(htd_u); - - htd_u->fig_u.for_u = for_u; - - _http_serv_restart(htd_u); - - htd_u->car_u.liv_o = c3y; -} - -/* _http_io_talk(): start http I/O. -*/ -static void -_http_io_talk(u3_auto* car_u) -{ - u3_httd* htd_u = (u3_httd*)car_u; - - // XX remove [sen] - // - u3_noun wir = u3nt(u3i_string("http-server"), - u3dc("scot", c3__uv, htd_u->sev_l), - u3_nul); - u3_noun cad = u3nc(c3__born, u3_nul); - - u3_auto_plan(car_u, u3_ovum_init(0, c3__e, wir, cad)); - - // XX set liv_o on done/swap? - // -} - -/* _http_ef_http_server(): dispatch an %http-server effect from %light. -*/ -void -_http_ef_http_server(u3_httd* htd_u, - c3_l sev_l, - c3_l coq_l, - c3_l seq_l, - u3_noun tag, - u3_noun dat) -{ - u3_hreq* req_u; - - // sets server configuration - // - if ( c3y == u3r_sing_c("set-config", tag) ) { - u3_http_ef_form(htd_u, u3k(dat)); - } - // responds to an open request - // - else if ( 0 != (req_u = _http_search_req(htd_u, sev_l, coq_l, seq_l)) ) { - if ( c3y == u3r_sing_c("response", tag) ) { - u3_noun response = dat; - - if ( c3y == u3r_sing_c("start", u3h(response)) ) { - // Separate the %start message into its components. - // - u3_noun response_header, data, complete; - u3_noun status, headers; - u3x_trel(u3t(response), &response_header, &data, &complete); - u3x_cell(response_header, &status, &headers); - - _http_start_respond(req_u, u3k(status), u3k(headers), u3k(data), - u3k(complete)); - } - else if ( c3y == u3r_sing_c("continue", u3h(response)) ) { - // Separate the %continue message into its components. - // - u3_noun data, complete; - u3x_cell(u3t(response), &data, &complete); - - _http_continue_respond(req_u, u3k(data), u3k(complete)); - } - else if (c3y == u3r_sing_c("cancel", u3h(response))) { - u3l_log("http: %%cancel not handled yet"); - } - else { - u3l_log("http: strange response"); - } - } - else { - u3l_log("http: strange response"); - } - } - - u3z(tag); - u3z(dat); -} - -/* _http_stream_slog(): emit slog to open connections -*/ -static void -_http_stream_slog(void* vop_p, c3_w pri_w, u3_noun tan) -{ - u3_httd* htd_u = (u3_httd*)vop_p; - u3_hreq* seq_u = htd_u->fig_u.seq_u; - - // only do the work if there are open slog streams - // - if ( 0 != seq_u ) { - u3_weak data = u3_none; - - if ( c3y == u3a_is_atom(tan) ) { - u3_noun lin = u3i_list(u3i_string("data:"), - u3k(tan), - c3_s2('\n', '\n'), - u3_none); - u3_atom txt = u3qc_rap(3, lin); - data = u3nt(u3_nul, u3r_met(3, txt), txt); - u3z(lin); - } - else { - u3_weak wol = u3_none; - - // if we have no arvo kernel and can't evaluate nock, - // only send %leaf tanks - // - if ( 0 == u3A->roc ) { - if ( c3__leaf == u3h(tan) ) { - wol = u3nc(u3k(u3t(tan)), u3_nul); - } - } - else { - u3_noun blu = u3_term_get_blew(0); - c3_l col_l = u3h(blu); - wol = u3dc("wash", u3nc(0, col_l), u3k(tan)); - u3z(blu); - } - - if ( u3_none != wol ) { - u3_noun low = wol; - u3_noun paz = u3_nul; - while ( u3_nul != low ) { - u3_noun lin = u3i_list(u3i_string("data:"), - u3qc_rap(3, u3h(low)), - c3_s2('\n', '\n'), - u3_none); - paz = u3kb_weld(paz, lin); - low = u3t(low); - } - u3_atom txt = u3qc_rap(3, paz); - data = u3nt(u3_nul, u3r_met(3, txt), txt); - u3z(paz); - } - - u3z(wol); - } - - if ( u3_none != data ) { - while ( 0 != seq_u ) { - _http_continue_respond(seq_u, u3k(data), c3n); - seq_u = seq_u->nex_u; - } - } - - u3z(data); - } - - u3z(tan); -} - -/* _http_seq_heartbeat_cb(): send heartbeat to slog streams and restart timer -*/ -static void -_http_seq_heartbeat_cb(uv_timer_t* tim_u) -{ - u3_httd* htd_u = tim_u->data; - u3_hreq* seq_u = htd_u->fig_u.seq_u; - - if ( 0 != seq_u ) { - u3_noun dat = u3nt(u3_nul, 1, c3_s1('\n')); - while ( 0 != seq_u ) { - _http_continue_respond(seq_u, u3k(dat), c3n); - seq_u = seq_u->nex_u; - } - u3z(dat); - } - - uv_timer_start(htd_u->fig_u.sit_u, _http_seq_heartbeat_cb, - HEARTBEAT_TIMEOUT, 0); -} - -/* _http_io_kick(): apply effects. -*/ -static c3_o -_http_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) -{ - u3_httd* htd_u = (u3_httd*)car_u; - - u3_noun tag, dat, i_wir, t_wir; - - if ( (c3n == u3r_cell(wir, &i_wir, &t_wir)) - || (c3n == u3r_cell(cad, &tag, &dat)) - || (c3n == u3r_sing_c("http-server", i_wir)) ) - { - u3z(wir); u3z(cad); - return c3n; - } - - // XX this needs to be rewritten, it defers (c3n) in cases it should not - // - { - u3_noun pud = t_wir; - u3_noun p_pud, t_pud, tt_pud, q_pud, r_pud, s_pud; - c3_l sev_l, coq_l, seq_l; - - - if ( (c3n == u3r_cell(pud, &p_pud, &t_pud)) || - (c3n == u3v_lily(c3__uv, u3k(p_pud), &sev_l)) ) - { - u3z(wir); u3z(cad); - return c3n; - } - - if ( u3_nul == t_pud ) { - coq_l = seq_l = 0; - } - else { - if ( (c3n == u3r_cell(t_pud, &q_pud, &tt_pud)) || - (c3n == u3v_lily(c3__ud, u3k(q_pud), &coq_l)) ) - { - u3z(wir); u3z(cad); - return c3n; - } - - if ( u3_nul == tt_pud ) { - seq_l = 0; - } else { - if ( (c3n == u3r_cell(tt_pud, &r_pud, &s_pud)) || - (u3_nul != s_pud) || - (c3n == u3v_lily(c3__ud, u3k(r_pud), &seq_l)) ) - { - u3z(wir); u3z(cad); - return c3n; - } - } - } - - _http_ef_http_server(htd_u, sev_l, coq_l, seq_l, u3k(tag), u3k(dat)); - u3z(wir); u3z(cad); - return c3y; - } -} - -/* _http_io_exit(): shut down http. -*/ -static void -_http_io_exit(u3_auto* car_u) -{ - u3_httd* htd_u = (u3_httd*)car_u; - - // dispose of configuration to avoid restarts - // - _http_form_free(htd_u); - - // close all servers - // - // XX broken - // - // for ( u3_http* htp_u = htd_u->htp_u; htp_u; htp_u = htp_u->nex_u ) { - // _http_serv_close(htp_u); - // } - - { - u3_atom lin = u3i_string("data:urbit shutting down\n\n"); - u3_noun dat = u3nt(u3_nul, u3r_met(3, lin), lin); - u3_hreq* seq_u = htd_u->fig_u.seq_u; - while ( 0 != seq_u ) { - _http_continue_respond(seq_u, u3k(dat), c3y); - seq_u = seq_u->nex_u; - } - u3z(dat); - } - - _http_release_ports_file(u3_Host.dir_c); -} - -/* _http_io_info(): produce status info. -*/ -static u3_noun -_http_io_info(u3_auto* car_u) -{ - u3_httd* htd_u = (u3_httd*)car_u; - u3_http* htp_u = htd_u->htp_u; - c3_w sec_w = 0; - u3_hreq* seq_u = htd_u->fig_u.seq_u; - u3_noun res; - - // XX review: metrics - // - while ( 0 != seq_u ) { - sec_w++; - seq_u = seq_u->nex_u; - } - res = u3i_list( - u3_pier_mase("instance", htd_u->sev_l), - u3_pier_mase("open-slogstreams", u3i_word(sec_w)), - u3_none); - - while ( 0 != htp_u ) { - res = u3nc( - u3_pier_mass( - u3dc("scot", c3__uv, htp_u->sev_l), - u3i_list( - u3_pier_mase("secure", htp_u->sec), - u3_pier_mase("loopback", htp_u->lop), - u3_pier_mase("live", htp_u->liv), - u3_pier_mase("port", htp_u->por_s), - u3_pier_mase("connections", htp_u->coq_l), - u3_none)), - res); - htp_u = htp_u->nex_u; - } - return u3kb_flop(res); -} - -/* _http_io_slog(): print status info. -*/ -static void -_http_io_slog(u3_auto* car_u) -{ - u3_httd* htd_u = (u3_httd*)car_u; - c3_y sec_y = 0; - u3_hreq* seq_u = htd_u->fig_u.seq_u; - while ( 0 != seq_u ) { - sec_y++; - seq_u = seq_u->nex_u; - } - u3l_log(" open slogstreams: %d", sec_y); -} - -/* u3_http_io_init(): initialize http I/O. -*/ -u3_auto* -u3_http_io_init(u3_pier* pir_u) -{ - u3_httd* htd_u = c3_calloc(sizeof(*htd_u)); - - u3_auto* car_u = &htd_u->car_u; - car_u->nam_m = c3__http; - car_u->liv_o = c3n; - car_u->io.talk_f = _http_io_talk; - car_u->io.info_f = _http_io_info; - car_u->io.slog_f = _http_io_slog; - car_u->io.kick_f = _http_io_kick; - car_u->io.exit_f = _http_io_exit; - - pir_u->sop_p = htd_u; - pir_u->sog_f = _http_stream_slog; - - uv_timer_t* sit_u = c3_malloc(sizeof(*sit_u)); - sit_u->data = htd_u; - uv_timer_init(u3L, sit_u); - uv_timer_start(sit_u, _http_seq_heartbeat_cb, HEARTBEAT_TIMEOUT, 0); - htd_u->fig_u.sit_u = sit_u; - - { - u3_noun now; - struct timeval tim_u; - gettimeofday(&tim_u, 0); - - now = u3_time_in_tv(&tim_u); - htd_u->sev_l = u3r_mug(now); - u3z(now); - } - - // XX retry up to N? - // - // car_u->ev.bail_f = ...; - - return car_u; -} diff --git a/pkg/urbit/vere/io/term.c b/pkg/urbit/vere/io/term.c deleted file mode 100644 index 5970a56e1..000000000 --- a/pkg/urbit/vere/io/term.c +++ /dev/null @@ -1,1799 +0,0 @@ -/* vere/term.c -** -*/ -#include "all.h" -#include "vere/vere.h" - -// macros for string literal args/buffers -// -// since (sizeof(s) - 1) is used for vector length, parameters -// must be appropriately typed. use with care! -// -#define TERM_LIT(s) sizeof(s) - 1, (const c3_y*)(s) -#define TERM_LIT_BUF(s) uv_buf_init(s, sizeof(s) - 1) - -static u3_utty* _term_main(); -static void _term_read_cb(uv_stream_t* tcp_u, - ssize_t siz_i, - const uv_buf_t* buf_u); -static void _term_it_send_stub(u3_utty* uty_u, u3_noun tub); - -/* u3_write_fd(): retry interrupts, continue partial writes, assert errors. -*/ -void -u3_write_fd(c3_i fid_i, const void* buf_v, size_t len_i) -{ - ssize_t ret_i; - - while ( len_i > 0 ) { - c3_w lop_w = 0; - // retry interrupt/async errors - // - do { - // abort pathological retry loop - // - if ( 100 == ++lop_w ) { - fprintf(stderr, "term: write loop: %s\r\n", strerror(errno)); - return; - } - ret_i = write(fid_i, buf_v, len_i); - } - while ( (ret_i < 0) - && ( (errno == EINTR) - || (errno == EAGAIN) - || (errno == EWOULDBLOCK) )); - - // assert on true errors - // - // NB: can't call u3l_log here or we would re-enter u3_write_fd() - // - if ( ret_i < 0 ) { - fprintf(stderr, "term: write failed %s\r\n", strerror(errno)); - c3_assert(0); - } - // continue partial writes - // - else { - len_i -= ret_i; - buf_v += ret_i; - } - } -} - -/* _term_msc_out_host(): unix microseconds from current host time. -*/ -static c3_d -_term_msc_out_host() -{ - struct timeval tim_tv; - gettimeofday(&tim_tv, 0); - return 1000000ULL * tim_tv.tv_sec + tim_tv.tv_usec; -} - -/* _term_alloc(): libuv buffer allocator. -*/ -static void -_term_alloc(uv_handle_t* had_u, - size_t len_i, - uv_buf_t* buf - ) -{ - // this read can range from a single byte to a paste buffer - // 123 bytes has been chosen because its not a power of 2 - // this is probably still broken - // - void* ptr_v = c3_malloc(123); - *buf = uv_buf_init(ptr_v, 123); -} - -/* u3_term_log_init(): initialize terminal for logging -*/ -void -u3_term_log_init(void) -{ - u3_utty* uty_u; - - if ( c3y == u3_Host.ops_u.tem ) { - uty_u = c3_calloc(sizeof(u3_utty)); - uty_u->fid_i = 1; - - uv_pipe_init(u3L, &(uty_u->pin_u.pip_u), 0); - uv_pipe_init(u3L, &(uty_u->pop_u.pip_u), 0); - uv_pipe_open(&(uty_u->pop_u.pip_u), uty_u->fid_i); - } - else { - // Initialize event processing. Rawdog it. - // - const c3_c* err_c; - if ( NULL == (uty_u = u3_ptty_init(u3L, &err_c)) ) { - fprintf(stderr, "vere: unable to initialize terminal (%s)\r\n" - " use -t to disable interactivity\r\n", err_c); - u3_king_bail(); - } - - // configure output escape sequences - // - // our requirements are minimal here, so we bypass terminfo - // and simply use constant sequences. - // - { - uty_u->ufo_u.mon_u = TERM_LIT_BUF("\033[?9h"); - uty_u->ufo_u.mof_u = TERM_LIT_BUF("\033[?9l"); - - uty_u->ufo_u.reg_u = TERM_LIT_BUF("\033[r"); - - uty_u->ufo_u.suc_u = TERM_LIT_BUF("\033[s"); - uty_u->ufo_u.ruc_u = TERM_LIT_BUF("\033[u"); - uty_u->ufo_u.cub_u = TERM_LIT_BUF("\x8"); - - uty_u->ufo_u.clr_u = TERM_LIT_BUF("\033[H\033[2J"); - uty_u->ufo_u.cel_u = TERM_LIT_BUF("\033[K"); - - uty_u->ufo_u.bel_u = TERM_LIT_BUF("\x7"); - } - - // Initialize mirror and accumulator state. - // - { - uty_u->tat_u.mir.lin = u3_nul; - uty_u->tat_u.mir.rus_w = 0; - uty_u->tat_u.mir.cus_w = 0; - - uty_u->tat_u.esc.ape = c3n; - uty_u->tat_u.esc.bra = c3n; - uty_u->tat_u.esc.mou = c3n; - uty_u->tat_u.esc.ton_y = 0; - uty_u->tat_u.esc.col_y = 0; - - uty_u->tat_u.fut.len_w = 0; - uty_u->tat_u.fut.wid_w = 0; - uty_u->tat_u.fut.imp = u3_nul; - } - - // default size - // - { - uty_u->tat_u.siz.col_l = 80; - uty_u->tat_u.siz.row_l = 0; - } - - // initialize spinner state - // - { - uty_u->tat_u.sun_u.diz_o = c3n; - uty_u->tat_u.sun_u.eve_d = 0; - uty_u->tat_u.sun_u.end_d = 0; - } - } - - // This is terminal 1, linked in host. - // - { - uty_u->tid_l = 1; - uty_u->nex_u = 0; - u3_Host.uty_u = uty_u; - } - - // Disable I/O buffering on terminal streams. - // This is not necessary if output is a tty, - // but helps when output is redirected. - // - { - fflush(stdout); - fflush(stderr); - setvbuf(stdout, NULL, _IONBF, 0); - setvbuf(stderr, NULL, _IONBF, 0); - } - - // if terminal/tty is enabled - // - if ( c3n == u3_Host.ops_u.tem ) { - // Start raw input. - // - if ( c3n == uty_u->sta_f(uty_u) ) { - c3_assert(!"init-tcsetattr"); - } - - // initialize spinner timeout - // - { - uv_timer_init(u3L, &uty_u->tat_u.sun_u.tim_u); - uty_u->tat_u.sun_u.tim_u.data = uty_u; - } - } -} - -/* u3_term_log_exit(): clean up terminal. -*/ -void -u3_term_log_exit(void) -{ - if ( c3n == u3_Host.ops_u.tem ) { - u3_utty* uty_u; - - for ( uty_u = u3_Host.uty_u; uty_u; uty_u = uty_u->nex_u ) { - if ( uty_u->fid_i == -1 ) { continue; } - if ( c3n == uty_u->sto_f(uty_u) ) { - c3_assert(!"exit-tcsetattr"); - } - u3_write_fd(uty_u->fid_i, "\r\n", 2); - } - } - - if ( u3_Host.uty_u ) { - uv_close((uv_handle_t*)&u3_Host.uty_u->pin_u, 0); - uv_close((uv_handle_t*)&u3_Host.uty_u->pop_u, 0); - } -} - -/* _term_it_write_cb(): general write callback. -*/ -static void -_term_it_write_cb(uv_write_t* wri_u, c3_i sas_i) -{ - // write failure is logged, but otherwise ignored. - // - if ( 0 != sas_i ) { - u3l_log("term: write: %s", uv_strerror(sas_i)); - } - - c3_free(wri_u->data); - c3_free(wri_u); -} - -/* _term_it_write(): write libuv buffer, freeing pointer. -*/ -static void -_term_it_write(u3_utty* uty_u, - uv_buf_t* buf_u, - void* ptr_v) -{ - // work off a local copy of the buffer, in case we need - // to manipulate the length/pointer - // - uv_buf_t fub_u = { .base = buf_u->base, .len = buf_u->len }; - uv_stream_t* han_u = (uv_stream_t*)&(uty_u->pop_u); - c3_i ret_i; - - // try to write synchronously - // - while ( 1 ) { - ret_i = uv_try_write(han_u, &fub_u, 1); - - if ( (ret_i > 0) && (ret_i < fub_u.len) ) { - fub_u.len -= ret_i; - fub_u.base += ret_i; - continue; - } - else { - break; - } - } - - // cue an async write if necessary - // - if ( UV_EAGAIN == ret_i ) { - uv_write_t* wri_u = c3_malloc(sizeof(*wri_u)); - wri_u->data = ptr_v; - - // invoke callback manually on error - // - if ( (ret_i = uv_write(wri_u, han_u, &fub_u, 1, _term_it_write_cb)) ) { - _term_it_write_cb(wri_u, ret_i); - } - } - else { - // synchronous write failure is logged, but otherwise ignored - // - if ( ret_i < 0 ) { - u3l_log("term: write: %s", uv_strerror(ret_i)); - } - - c3_free(ptr_v); - } -} - -/* _term_it_dump_buf(): write static buffer. -*/ -static void -_term_it_dump_buf(u3_utty* uty_u, - uv_buf_t* buf_u) -{ - if ( buf_u->len ) { - _term_it_write(uty_u, buf_u, 0); - } -} - -/* _term_it_dump(): write static vector. -*/ -static void -_term_it_dump(u3_utty* uty_u, - c3_w len_w, - const c3_y* hun_y) -{ - uv_buf_t buf_u = uv_buf_init((c3_c*)hun_y, len_w); - _term_it_dump_buf(uty_u, &buf_u); -} - -/* _term_it_send(): write dynamic vector, freeing pointer. -*/ -static void -_term_it_send(u3_utty* uty_u, - c3_w len_w, - c3_y* hun_y) -{ - if ( len_w ) { - uv_buf_t buf_u = uv_buf_init((c3_c*)hun_y, len_w); - _term_it_write(uty_u, &buf_u, (void*)hun_y); - } - else { - c3_free(hun_y); - } -} - -/* _term_it_send_csi(): send csi escape sequence -*/ -static void -_term_it_send_csi(u3_utty *uty_u, c3_c cmd_c, c3_w num_w, ...) -{ - va_list ap; - va_start(ap, num_w); - - // allocate for escape sequence (2), command char (1), - // argument digits (5 per arg) and separators (1 per arg, minus 1). - // freed via _term_it_write. - // - c3_c* pas_c = c3_malloc( 2 + num_w * 6 ); - c3_y len_y = 0; - - pas_c[len_y++] = '\033'; - pas_c[len_y++] = '['; - - while ( num_w-- ) { - c3_w par_w = va_arg(ap, c3_w); - len_y += sprintf(pas_c+len_y, "%d", par_w); - - if ( num_w ) { - pas_c[len_y++] = ';'; - } - } - - pas_c[len_y++] = cmd_c; - - _term_it_send(uty_u, len_y, (c3_y*)pas_c); - - va_end(ap); -} - -/* _term_it_free_line(): wipe line stored by _term_it_save_stub -*/ -static void -_term_it_free_line(u3_utty* uty_u) -{ - u3z(uty_u->tat_u.mir.lin); - uty_u->tat_u.mir.lin = u3_nul; -} - -/* _term_it_clear_line(): clear line of cursor -*/ -static void -_term_it_clear_line(u3_utty* uty_u) -{ - _term_it_dump(uty_u, TERM_LIT("\r")); - _term_it_dump_buf(uty_u, &uty_u->ufo_u.cel_u); - _term_it_dump_buf(uty_u, &uty_u->ufo_u.ruc_u); - - // if we're clearing the bottom line, clear our mirror of it too - // - if ( uty_u->tat_u.siz.row_l - 1 == uty_u->tat_u.mir.rus_w ) { - _term_it_free_line(uty_u); - } -} - -/* _term_it_show_blank(): blank the screen. -*/ -static void -_term_it_show_blank(u3_utty* uty_u) -{ - _term_it_dump_buf(uty_u, &uty_u->ufo_u.clr_u); - _term_it_dump_buf(uty_u, &uty_u->ufo_u.ruc_u); -} - -/* _term_it_move_cursor(): move cursor to row & column - * - * row 0 is at the top, col 0 is to the left. - * if the given position exceeds the known window size, - * it is clipped to stay within the window. - */ -static void -_term_it_move_cursor(u3_utty* uty_u, c3_w col_w, c3_w row_w) -{ - c3_l row_l = uty_u->tat_u.siz.row_l; - c3_l col_l = uty_u->tat_u.siz.col_l; - if ( row_w >= row_l ) { row_w = row_l - 1; } - if ( col_w >= col_l ) { col_w = col_l - 1; } - - _term_it_send_csi(uty_u, 'H', 2, row_w + 1, col_w + 1); - _term_it_dump_buf(uty_u, &uty_u->ufo_u.suc_u); - - uty_u->tat_u.mir.rus_w = row_w; - uty_u->tat_u.mir.cus_w = col_w; -} - -/* _term_it_show_line(): print at cursor -*/ -static void -_term_it_show_line(u3_utty* uty_u, c3_w* lin_w, c3_w wor_w) -{ - u3_utat* tat_u = &uty_u->tat_u; - c3_y* hun_y = (c3_y*)lin_w; - c3_w byt_w = 0; - - // convert lin_w in-place from utf-32 to utf-8 - // - // (this is just a hand-translation of +tuft) - // XX refactor for use here and in a jet - // - { - c3_w car_w, i_w; - - for ( i_w = 0; i_w < wor_w; i_w++ ) { - car_w = lin_w[i_w]; - - if ( 0x7f >= car_w ) { - hun_y[byt_w++] = car_w; - } - else if ( 0x7ff >= car_w ) { - hun_y[byt_w++] = 0xc0 ^ ((car_w >> 6) & 0x1f); - hun_y[byt_w++] = 0x80 ^ (car_w & 0x3f); - } - else if ( 0xffff >= car_w ) { - hun_y[byt_w++] = 0xe0 ^ ((car_w >> 12) & 0xf); - hun_y[byt_w++] = 0x80 ^ ((car_w >> 6) & 0x3f); - hun_y[byt_w++] = 0x80 ^ (car_w & 0x3f); - } - else { - hun_y[byt_w++] = 0xf0 ^ ((car_w >> 18) & 0x7); - hun_y[byt_w++] = 0x80 ^ ((car_w >> 12) & 0x3f); - hun_y[byt_w++] = 0x80 ^ ((car_w >> 6) & 0x3f); - hun_y[byt_w++] = 0x80 ^ (car_w & 0x3f); - } - } - } - - //NOTE lin_w freed through hun_y by _send - _term_it_send(uty_u, byt_w, hun_y); - _term_it_dump_buf(uty_u, &uty_u->ufo_u.ruc_u); -} - -/* _term_it_restore_line(): re-render original line at bottom of screen -*/ -static void -_term_it_restore_line(u3_utty* uty_u) -{ - u3_utat* tat_u = &uty_u->tat_u; - - _term_it_send_csi(uty_u, 'H', 2, tat_u->siz.row_l, 1); - _term_it_dump_buf(uty_u, &uty_u->ufo_u.cel_u); - _term_it_send_stub(uty_u, u3k(tat_u->mir.lin)); - //NOTE send_stub restores cursor position -} - -/* _term_it_save_stub(): store line if relevant to internal logic - */ -static void -_term_it_save_stub(u3_utty* uty_u, u3_noun tub) -{ - u3_utat* tat_u = &uty_u->tat_u; - u3_noun lin = tat_u->mir.lin; - - // keep track of changes to bottom-most line, to aid spinner drawing logic. - // -t mode doesn't need this logic, because it doesn't render the spinner. - // - if ( ( tat_u->siz.row_l - 1 == tat_u->mir.rus_w ) && - ( c3n == u3_Host.ops_u.tem ) ) { - lin = u3dq("wail:klr:format", lin, tat_u->mir.cus_w, u3k(tub), ' '); - lin = u3do("pact:klr:format", lin); - } - - tat_u->mir.lin = lin; - u3z(tub); -} - -/* _term_it_show_nel(): render newline, moving cursor down -*/ -static void -_term_it_show_nel(u3_utty* uty_u) -{ - if ( c3y == u3_Host.ops_u.tem ) { - _term_it_dump(uty_u, TERM_LIT("\n")); - } - else { - _term_it_dump(uty_u, TERM_LIT("\r\n")); - _term_it_dump_buf(uty_u, &uty_u->ufo_u.suc_u); - } - - uty_u->tat_u.mir.cus_w = 0; - if ( uty_u->tat_u.mir.rus_w < uty_u->tat_u.siz.row_l - 1 ) { - uty_u->tat_u.mir.rus_w++; - } - else { - // newline at bottom of screen, so bottom line is now empty - // - _term_it_free_line(uty_u); - } -} - -/* _term_it_path(): path for console file. -*/ -static c3_c* -_term_it_path(u3_noun pax) -{ - c3_w len_w = 0; - c3_c *pas_c; - - // measure - // - { - u3_noun wiz = pax; - - while ( u3_nul != wiz ) { - len_w += (1 + u3r_met(3, u3h(wiz))); - wiz = u3t(wiz); - } - } - - // cut - // - pas_c = c3_malloc(len_w + 1); - pas_c[len_w] = '\0'; - { - u3_noun wiz = pax; - c3_c* waq_c = pas_c; - - while ( u3_nul != wiz ) { - c3_w tis_w = u3r_met(3, u3h(wiz)); - - if ( (u3_nul == u3t(wiz)) ) { - *waq_c++ = '.'; - } else *waq_c++ = '/'; - - u3r_bytes(0, tis_w, (c3_y*)waq_c, u3h(wiz)); - waq_c += tis_w; - - wiz = u3t(wiz); - } - *waq_c = 0; - } - u3z(pax); - return pas_c; -} - -/* _term_it_save(): save file by path. -*/ -static void -_term_it_save(u3_noun pax, u3_noun pad) -{ - c3_c* pax_c = _term_it_path(pax); - - u3_unix_save(pax_c, pad); - c3_free(pax_c); -} - -/* _term_ovum_plan(): plan term ovums, configuring spinner. -*/ -static u3_ovum* -_term_ovum_plan(u3_auto* car_u, u3_noun wir, u3_noun cad) -{ - u3_ovum* egg_u = u3_auto_plan(car_u, u3_ovum_init(0, c3__d, wir, cad)); - - // term events have no spinner label - // - u3z(egg_u->pin_u.lab); - egg_u->pin_u.lab = u3_blip; - - return egg_u; -} - -/* _term_io_belt(): send belt. -*/ -static void -_term_io_belt(u3_utty* uty_u, u3_noun blb) -{ - // XX s/b u3dc("scot", c3__ud, uty_u->tid_l) - // - u3_noun wir = u3nt(c3__term, '1', u3_nul); - u3_noun cad = u3nc(c3__belt, blb); - - c3_assert( 1 == uty_u->tid_l ); - c3_assert( uty_u->car_u ); - - { - u3_ovum* egg_u = _term_ovum_plan(uty_u->car_u, wir, cad); - - // no spinner delay on %ret - // - if ( c3__ret == u3h(blb) ) { - egg_u->pin_u.del_o = c3n; - } - } -} - -/* _term_io_spit(): input the buffer (if any), then input the belt (if any) -*/ -static void -_term_io_spit(u3_utty* uty_u, u3_noun bet) { - u3_utat* tat_u = &uty_u->tat_u; - if (u3_nul != tat_u->fut.imp) { - _term_io_belt(uty_u, u3nc(c3__txt, u3kb_flop(tat_u->fut.imp))); - tat_u->fut.imp = u3_nul; - } - if (u3_none != bet) { - _term_io_belt(uty_u, bet); - } -} - -/* _term_io_suck_char(): process a single character. - * - * Note that this accumulates simple inputs in a buffer, and is not - * guaranteed to flush it fully. After a call (or sequence of calls) - * to this function, please call _term_io_spit(uty_u, u3_none) to - * flush any remainder. - */ -static void -_term_io_suck_char(u3_utty* uty_u, c3_y cay_y) -{ - u3_utat* tat_u = &uty_u->tat_u; - - // escape sequences - // - if ( c3y == tat_u->esc.ape ) { - if ( c3y == tat_u->esc.bra ) { - // vt sequence - // - if ( cay_y == '~' ) { - switch ( tat_u->esc.seq_y ) { - default: { - _term_it_dump_buf(uty_u, &uty_u->ufo_u.bel_u); - break; - } - case '3': _term_io_spit(uty_u, u3nc(c3__del, u3_nul)); break; - } - tat_u->esc.ape = tat_u->esc.bra = c3n; - tat_u->esc.seq_y = 0; - } - else if ( cay_y <= '9' ) { - tat_u->esc.seq_y = cay_y; - } - // xterm sequence - // - else { - switch ( cay_y ) { - default: { - _term_it_dump_buf(uty_u, &uty_u->ufo_u.bel_u); - break; - } - case 'A': _term_io_spit(uty_u, u3nc(c3__aro, 'u')); break; - case 'B': _term_io_spit(uty_u, u3nc(c3__aro, 'd')); break; - case 'C': _term_io_spit(uty_u, u3nc(c3__aro, 'r')); break; - case 'D': _term_io_spit(uty_u, u3nc(c3__aro, 'l')); break; - // - case 'M': tat_u->esc.mou = c3y; break; - } - tat_u->esc.ape = tat_u->esc.bra = c3n; - } - } - else { - if ( (cay_y >= 'a') && (cay_y <= 'z') ) { - tat_u->esc.ape = c3n; - // XX for backwards compatibility, check kelvin version - // and fallback to [%met @c] - // - _term_io_spit(uty_u, u3nt(c3__mod, c3__met, cay_y)); - } - else if ( 8 == cay_y || 127 == cay_y ) { - tat_u->esc.ape = c3n; - // XX backwards compatibility [%met @c] - // - _term_io_spit(uty_u, u3nq(c3__mod, c3__met, c3__bac, u3_nul)); - } - else if ( ('[' == cay_y) || ('O' == cay_y) ) { - tat_u->esc.bra = c3y; - } - else { - tat_u->esc.ape = c3n; - - _term_it_dump_buf(uty_u, &uty_u->ufo_u.bel_u); - } - } - } - // mouse input - // - else if ( c3y == tat_u->esc.mou ) { - if ( 0 == tat_u->esc.ton_y ) { - tat_u->esc.ton_y = cay_y - 31; - } - else if ( 0 == tat_u->esc.col_y ) { - tat_u->esc.col_y = cay_y - 32; - } - else { - c3_y row_y = cay_y - 32; - // only acknowledge button 1 presses within our known window - if ( 1 != tat_u->esc.ton_y && row_y <= tat_u->siz.row_l ) { - _term_io_spit(uty_u, u3nt(c3__hit, tat_u->esc.col_y - 1, row_y - 1)); - } - tat_u->esc.mou = c3n; - tat_u->esc.ton_y = tat_u->esc.col_y = 0; - } - } - // unicode inputs - // - else if ( 0 != tat_u->fut.wid_w ) { - tat_u->fut.syb_y[tat_u->fut.len_w++] = cay_y; - - if ( tat_u->fut.len_w == tat_u->fut.wid_w ) { - u3_noun huv = u3i_bytes(tat_u->fut.wid_w, tat_u->fut.syb_y); - u3_noun wug; - - // XX implement directly here and jet - // - wug = u3do("taft", huv); - - tat_u->fut.len_w = tat_u->fut.wid_w = 0; - tat_u->fut.imp = u3nc(wug, tat_u->fut.imp); - } - } - // individual characters - // - else { - if ( (cay_y >= 32) && (cay_y < 127) ) { // visual ascii - tat_u->fut.imp = u3nc(cay_y, tat_u->fut.imp); - } - else if ( 0 == cay_y ) { // null - _term_it_dump_buf(uty_u, &uty_u->ufo_u.bel_u); - } - else if ( 8 == cay_y || 127 == cay_y ) { // backspace & delete - _term_io_spit(uty_u, u3nc(c3__bac, u3_nul)); - } - else if ( 10 == cay_y || 13 == cay_y ) { // newline & carriage return - _term_io_spit(uty_u, u3nc(c3__ret, u3_nul)); - } - else if ( cay_y <= 26 ) { - // XX backwards compatibility [%ctl @c] - // - _term_io_spit(uty_u, u3nt(c3__mod, c3__ctl, ('a' + (cay_y - 1)))); - } - else if ( 27 == cay_y ) { - tat_u->esc.ape = c3y; - } - else if ( cay_y >= 128 ) { - tat_u->fut.len_w = 1; - tat_u->fut.syb_y[0] = cay_y; - - if ( cay_y < 224 ) { - tat_u->fut.wid_w = 2; - } else if ( cay_y < 240 ) { - tat_u->fut.wid_w = 3; - } else tat_u->fut.wid_w = 4; - } - } -} - -/* _term_suck(): process a chunk of input -*/ - -/* - * `nread` (siz_w) is > 0 if there is data available, 0 if libuv is done reading for - * now, or < 0 on error. - * - * The callee is responsible for closing the stream when an error happens - * by calling uv_close(). Trying to read from the stream again is undefined. - * - * The callee is responsible for freeing the buffer, libuv does not reuse it. - * The buffer may be a null buffer (where buf->base=NULL and buf->len=0) on - * error. - */ - -static inline void -_term_suck(u3_utty* uty_u, const c3_y* buf, ssize_t siz_i) -{ - { - if ( siz_i == UV_EOF ) { - // We hear EOF (on the third read callback) if - // 2x the _term_alloc() buffer size is pasted. - // The process hangs if we do nothing (and ctrl-z - // then corrupts the event log), so we force shutdown. - // - u3l_log("term: hangup (EOF)"); - - // XX revise - // - u3_pier_bail(u3_king_stub()); - } - else if ( siz_i < 0 ) { - u3l_log("term %d: read: %s", uty_u->tid_l, uv_strerror(siz_i)); - } - else { - c3_i i; - - for ( i=0; i < siz_i; i++ ) { - _term_io_suck_char(uty_u, buf[i]); - } - _term_io_spit(uty_u, u3_none); - } - } -} - -/* _term_read_cb(): server read callback. -*/ -static void -_term_read_cb(uv_stream_t* tcp_u, - ssize_t siz_i, - const uv_buf_t * buf_u) -{ - u3_utty* uty_u = (u3_utty*)(void*)tcp_u; - _term_suck(uty_u, (const c3_y*)buf_u->base, siz_i); - c3_free(buf_u->base); -} - -/* _term_spin_step(): advance spinner state and (re-)render. -*/ -static void -_term_spin_step(u3_utty* uty_u) -{ - u3_utat* tat_u = &uty_u->tat_u; - c3_w bac_w; - - // calculate backoff from end of line, or bail out - // - { - c3_w cus_w = tat_u->mir.cus_w; - c3_l col_l = tat_u->siz.col_l; - - if ( cus_w >= col_l ) { // shenanigans! - return; - } - - bac_w = col_l - 1 - cus_w; - } - - c3_d lag_d = tat_u->sun_u.eve_d++; - const c3_c daz_c[] = "|/-\\"; - // | + « + why + » + \0 - c3_c buf_c[1 + 2 + 4 + 2 + 1]; - c3_c* cur_c = buf_c; - c3_w sol_w = 1; // spinner length (utf-32) - - // set spinner char - // - *cur_c++ = daz_c[lag_d % (sizeof(daz_c) - 1)]; - - // if we have a spinner, add it between brackets - // - if ( tat_u->sun_u.why_c[0] ) { - *cur_c++ = '\xc2'; - *cur_c++ = '\xab'; - sol_w++; - - { - c3_c* why_c = tat_u->sun_u.why_c; - *cur_c++ = *why_c++; - *cur_c++ = *why_c++; - *cur_c++ = *why_c++; - *cur_c++ = *why_c; - // XX assumes one glyph per char - // - sol_w += 4; - } - - *cur_c++ = '\xc2'; - *cur_c++ = '\xbb'; - sol_w++; - } - - *cur_c = '\0'; - - // write spinner, adjusting cursor as needed - // - // NB: we simply bail out if anything goes wrong - // - { - uv_buf_t lef_u = uty_u->ufo_u.cub_u; - c3_i fid_i = uty_u->fid_i; - - // One-time cursor backoff. - // - if ( c3n == tat_u->sun_u.diz_o ) { - // if we know where the bottom line is, and the cursor is not on it, - // move it to the bottom left - // - if ( tat_u->siz.row_l && tat_u->mir.rus_w < tat_u->siz.row_l - 1 ) { - _term_it_send_csi(uty_u, 'H', 2, tat_u->siz.row_l, 1); - } - - c3_w i_w; - for ( i_w = bac_w; i_w < sol_w; i_w++ ) { - if ( lef_u.len != write(fid_i, lef_u.base, lef_u.len) ) { - return; - } - } - - tat_u->sun_u.diz_o = c3y; - } - - { - c3_w len_w = cur_c - buf_c; - if ( len_w != write(fid_i, buf_c, len_w) ) { - return; - } - } - - // Cursor stays on spinner. - // - while ( sol_w-- ) { - if ( lef_u.len != write(fid_i, lef_u.base, lef_u.len) ) { - return; - } - } - } -} - -/* _term_spin_timer_cb(): render spinner -*/ -static void -_term_spin_timer_cb(uv_timer_t* tim_u) -{ - u3_utty* uty_u = tim_u->data; - _term_spin_step(uty_u); -} - -#define _SPIN_FAST_US 100UL // spinner activation delay when expected -#define _SPIN_COOL_US 500UL // spinner activation delay when cool -#define _SPIN_WARM_US 50UL // spinner activation delay when warm -#define _SPIN_RATE_US 250UL // spinner rate (ms/frame) -#define _SPIN_IDLE_US 500UL // spinner cools down if stopped this long - -/* u3_term_start_spinner(): prepare spinner state. RETAIN. -*/ -void -u3_term_start_spinner(u3_atom say, c3_o del_o) -{ - if ( c3n == u3_Host.ops_u.tem ) { - u3_utty* uty_u = _term_main(); - u3_utat* tat_u = &uty_u->tat_u; - - tat_u->sun_u.why_c[4] = 0; - u3r_bytes(0, 4, (c3_y*)tat_u->sun_u.why_c, say); - - tat_u->sun_u.eve_d = 0; - // XX must be c3n for cursor backoff from EOL? - tat_u->sun_u.diz_o = c3n; - - { - c3_d now_d = _term_msc_out_host(); - c3_d end_d = tat_u->sun_u.end_d; - c3_d wen_d = (c3n == del_o) ? _SPIN_FAST_US : - (now_d - end_d < _SPIN_IDLE_US) ? - _SPIN_WARM_US : _SPIN_COOL_US; - - uv_timer_start(&tat_u->sun_u.tim_u, - _term_spin_timer_cb, - wen_d, _SPIN_RATE_US); - } - } -} - -/* u3_term_stop_spinner(): reset spinner state and restore input line. -*/ -void -u3_term_stop_spinner(void) -{ - if ( c3n == u3_Host.ops_u.tem ) { - u3_utty* uty_u = _term_main(); - u3_utat* tat_u = &uty_u->tat_u; - - memset(tat_u->sun_u.why_c, 0, 5); - - uv_timer_stop(&tat_u->sun_u.tim_u); - - if ( c3y == tat_u->sun_u.diz_o ) { - _term_it_restore_line(uty_u); - tat_u->sun_u.end_d = _term_msc_out_host(); - tat_u->sun_u.diz_o = c3n; - } - else { - tat_u->sun_u.end_d = 0; - } - } -} - -/* _term_main(): return main or console terminal. -*/ -static u3_utty* -_term_main() -{ - u3_utty* uty_u; - - for ( uty_u = u3_Host.uty_u; uty_u; uty_u = uty_u->nex_u ) { - if ( (uty_u->fid_i != -1) && (uty_u->fid_i <= 2) ) { - return uty_u; - } - } - return u3_Host.uty_u; -} - -/* _term_ef_get(): terminal by id. -*/ -static u3_utty* -_term_ef_get(c3_l tid_l) -{ - if ( 0 != tid_l ) { - u3_utty* uty_u; - - for ( uty_u = u3_Host.uty_u; uty_u; uty_u = uty_u->nex_u ) { - if ( tid_l == uty_u->tid_l ) { - return uty_u; - } - } - } - return _term_main(); -} - -/* u3_term_get_blew(): return window size [columns rows]. -*/ -u3_noun -u3_term_get_blew(c3_l tid_l) -{ - u3_utty* uty_u = _term_ef_get(tid_l); - c3_l col_l, row_l; - - if ( (c3y == u3_Host.ops_u.tem) || !uty_u || - (c3y != uty_u->wsz_f(uty_u, &col_l, &row_l)) ) - { - col_l = 80; - row_l = 24; - } - - if ( uty_u ) { - uty_u->tat_u.siz.col_l = col_l; - uty_u->tat_u.siz.row_l = row_l; - } - - return u3nc(col_l, row_l); -} - -/* u3_term_ef_winc(): window change. Just console right now. -*/ -void -u3_term_ef_winc(void) -{ - // XX groace, this should be a global handler sent to each pier - // - if ( u3_Host.uty_u->car_u ) { - u3_noun wir = u3nt(c3__term, '1', u3_nul); - u3_noun cad = u3nc(c3__blew, u3_term_get_blew(1)); - - c3_assert( 1 == u3_Host.uty_u->tid_l ); - - _term_ovum_plan(u3_Host.uty_u->car_u, wir, cad); - } -} - -/* u3_term_ef_ctlc(): send ^C on console. -*/ -void -u3_term_ef_ctlc(void) -{ - u3_utty* uty_u = _term_main(); - - if ( uty_u->car_u ) { - u3_noun wir = u3nt(c3__term, '1', u3_nul); - u3_noun cad = u3nq(c3__belt, c3__mod, c3__ctl, 'c'); - - c3_assert( 1 == uty_u->tid_l ); - _term_ovum_plan(uty_u->car_u, wir, cad); - } -} - -/* _term_it_put_value(): put numeric color value on lin_w. -*/ -static c3_w -_term_it_put_value(c3_w* lin_w, - u3_atom val) -{ - c3_c str_c[4]; - c3_w len = snprintf(str_c, 4, "%d", val % 256); - for ( c3_w i_w = 0; i_w < len; i_w++ ) { - lin_w[i_w] = str_c[i_w]; - } - u3z(val); - return len; -} - -/* _term_it_put_tint(): put ansi color id on lin_w. RETAINS col. -*/ -static c3_w -_term_it_put_tint(c3_w* lin_w, - u3_noun col) -{ - u3_noun red, gre, blu; - c3_o tru = u3r_trel(col, &red, &gre, &blu); - - // 24-bit color - // - if ( c3y == tru ) { - c3_w n = 0; - - *lin_w++ = '8'; - *lin_w++ = ';'; - *lin_w++ = '2'; - *lin_w++ = ';'; - - c3_w m = _term_it_put_value(lin_w, red); - n += m; - lin_w += m; - - *lin_w++ = ';'; - - m = _term_it_put_value(lin_w, gre); - n += m; - lin_w += m; - - *lin_w++ = ';'; - - n += _term_it_put_value(lin_w, blu); - - return n + 6; - } - // standard color - // - else { - switch ( col ) { - default: - case u3_nul: *lin_w = '9'; break; - case 'k': *lin_w = '0'; break; - case 'r': *lin_w = '1'; break; - case 'g': *lin_w = '2'; break; - case 'y': *lin_w = '3'; break; - case 'b': *lin_w = '4'; break; - case 'm': *lin_w = '5'; break; - case 'c': *lin_w = '6'; break; - case 'w': *lin_w = '7'; break; - } - return 1; - } -} - -/* _term_it_put_deco(): put ansi sgr code on lin_w. RETAINS dec. -*/ -static void -_term_it_put_deco(c3_w* lin_w, - u3_noun dec) -{ - switch ( dec ) { - default: - case u3_nul: *lin_w = '0'; break; - case c3__br: *lin_w = '1'; break; - case c3__un: *lin_w = '4'; break; - case c3__bl: *lin_w = '5'; break; - } -} - -/* _term_it_send_stub(): send styled text, without saving -*/ -static void -_term_it_send_stub(u3_utty* uty_u, - u3_noun tub) -{ - c3_w tuc_w = u3qb_lent(tub); - - // count the amount of characters across all stubs - // - c3_w lec_w = 0; - { - u3_noun nub = tub; - while ( u3_nul != nub ) { - u3_noun nib = u3t(u3h(nub)); - lec_w = lec_w + u3qb_lent(nib); - nub = u3t(nub); - } - } - - // allocate enough memory for every display character, plus styles - // - //NOTE we use max 48 characters per styl for escape codes: - // 2 for opening, 7 for decorations, 2x16 for colors, 4 for closing, - // and 3 as separators between decorations and colors. - // - c3_w* lin_w = c3_malloc( sizeof(c3_w) * (lec_w + (48 * tuc_w)) ); - - // write the contents to the buffer, - // tracking total and escape characters written - // - c3_w i_w = 0; - { - u3_noun nub = tub; - while ( u3_nul != nub ) { - u3_noun tyl, nib, dec, bag, fog; - u3x_cell(u3h(nub), &tyl, &nib); - u3x_trel(tyl, &dec, &bag, &fog); - - c3_o tyl_o = c3n; - if ( ( c3n == u3_Host.ops_u.tem ) && - ( (u3_nul != dec) || (u3_nul != bag) || (u3_nul != fog) ) ) { - tyl_o = c3y; - } - - // write style escape sequences - // - if ( c3y == tyl_o ) { - c3_o mor_o = c3n; - lin_w[i_w++] = 27; - lin_w[i_w++] = '['; - - // text decorations - // - { - u3_noun dos = u3qdi_tap(dec); - u3_noun des = dos; - while ( u3_nul != des ) { - if ( c3y == mor_o ) { - lin_w[i_w++] = ';'; - } - _term_it_put_deco(&lin_w[i_w++], u3h(des)); - mor_o = c3y; - des = u3t(des); - } - u3z(dos); - } - - // background color - // - if ( u3_nul != bag ) { - if ( c3y == mor_o ) { - lin_w[i_w++] = ';'; - } - lin_w[i_w++] = '4'; - c3_w put_w = _term_it_put_tint(&lin_w[i_w], bag); - i_w += put_w; - mor_o = c3y; - } - - // foreground color - // - if ( u3_nul != fog ) { - if ( c3y == mor_o ) { - lin_w[i_w++] = ';'; - } - lin_w[i_w++] = '3'; - c3_w put_w = _term_it_put_tint(&lin_w[i_w], fog); - i_w += put_w; - mor_o = c3y; - } - - lin_w[i_w++] = 'm'; - } - - // write the text itself - // - for ( i_w = i_w; u3_nul != nib; i_w++, nib = u3t(nib) ) { - lin_w[i_w] = u3r_word(0, u3h(nib)); - } - - // if we applied any styles, toggle them off - // - if ( c3y == tyl_o ) { - lin_w[i_w++] = 27; - lin_w[i_w++] = '['; - lin_w[i_w++] = '0'; - lin_w[i_w++] = 'm'; - } - - nub = u3t(nub); - } - } - - _term_it_show_line(uty_u, lin_w, i_w); - - u3z(tub); -} - -/* _term_it_send_stub(): send styled text to terminal as ansi escape sequences -*/ -static void -_term_it_show_stub(u3_utty* uty_u, - u3_noun tub) -{ - _term_it_send_stub(uty_u, u3k(tub)); - _term_it_save_stub(uty_u, tub); -} - -/* _term_it_show_tour(): send utf32 to terminal. -*/ -static void -_term_it_show_tour(u3_utty* uty_u, - u3_noun lin) -{ - c3_w len_w = u3qb_lent(lin); - c3_w* lin_w = c3_malloc( sizeof(c3_w) * len_w ); - - { - c3_w i_w; - - for ( i_w = 0; u3_nul != lin; i_w++, lin = u3t(lin) ) { - lin_w[i_w] = u3r_word(0, u3h(lin)); - } - } - - _term_it_show_line(uty_u, lin_w, len_w); - - { - u3_noun tub = u3i_list(u3nc(u3nt(u3_nul, u3_nul, u3_nul), lin), u3_none); - _term_it_save_stub(uty_u, tub); - } - - //NOTE lin transferred to tub above -} - -/* _term_ef_blit(): send blit to terminal. -*/ -static void -_term_ef_blit(u3_utty* uty_u, - u3_noun blt) -{ - switch ( u3h(blt) ) { - default: break; - - case c3__bel: { - _term_it_dump_buf(uty_u, &uty_u->ufo_u.bel_u); - } break; - - case c3__clr: { - _term_it_show_blank(uty_u); - } break; - - case c3__hop: { - u3_noun pos = u3t(blt); - if ( c3y == u3r_ud(pos) ) { - _term_it_move_cursor(uty_u, pos, uty_u->tat_u.siz.row_l - 1); - } - else { - _term_it_move_cursor(uty_u, u3h(pos), u3t(pos)); - } - } break; - - case c3__klr: { - _term_it_show_stub(uty_u, u3k(u3t(blt))); - } break; - - case c3__lin: { //TMP backwards compatibility - _term_it_move_cursor(uty_u, 0, uty_u->tat_u.siz.row_l - 1); - _term_it_clear_line(uty_u); - } // - case c3__put: { - _term_it_show_tour(uty_u, u3k(u3t(blt))); - } break; - - case c3__mor: { - if (u3_nul != u3t(blt)) { - u3_noun bis = u3t(blt); - while (u3_nul != bis) { - _term_ef_blit(uty_u, u3k(u3h(bis))); - bis = u3t(bis); - } - break; - } - //TMP fall through to nel for backwards compatibility - } - case c3__nel: { - _term_it_show_nel(uty_u); - } break; - - case c3__sav: { - u3_noun pax, dat; - u3x_cell(u3t(blt), &pax, &dat); - - _term_it_save(u3k(pax), u3k(dat)); - } break; - - case c3__sag: { - u3_noun pax, dat; - u3x_cell(u3t(blt), &pax, &dat); - - _term_it_save(u3k(pax), u3qe_jam(dat)); - } break; - - case c3__url: { - // platform-agnostically opening the default web browser from within a - // c program is an unsolved problem. - } break; - - case c3__wyp: { - _term_it_clear_line(uty_u); - } break; - } - - u3z(blt); -} - -/* _term_ef_blit_lame(): simplified output handling for -t -*/ -static void -_term_ef_blit_lame(u3_utty* uty_u, - u3_noun blt) -{ - switch ( u3h(blt) ) { - default: break; - - case c3__klr: { - _term_it_show_stub(uty_u, u3k(u3t(blt))); - _term_it_show_nel(uty_u); - } break; - - case c3__lin: //TMP backwards compatibility - case c3__put: { - _term_it_show_tour(uty_u, u3k(u3t(blt))); - _term_it_show_nel(uty_u); - } break; - - case c3__sav: { - u3_noun pax, dat; - u3x_cell(u3t(blt), &pax, &dat); - - _term_it_save(u3k(pax), u3k(dat)); - } break; - - case c3__sag: { - u3_noun pax, dat; - u3x_cell(u3t(blt), &pax, &dat); - - _term_it_save(u3k(pax), u3qe_jam(dat)); - } break; - } - - u3z(blt); -} - -/* u3_term_io_hija(): hijack console for fprintf, returning FILE*. -*/ -FILE* -u3_term_io_hija(void) -{ - u3_utty* uty_u = _term_main(); - - if ( uty_u && uty_u->tat_u.siz.row_l ) { - if ( uty_u->fid_i > 2 ) { - // We *should* in fact, produce some kind of fake FILE* for - // non-console terminals. If we use this interface enough... - // - c3_assert(0); - } - else { - if ( c3n == u3_Host.ops_u.tem ) { - if ( c3y != uty_u->hij_f(uty_u) ) { - c3_assert(!"hija-tcsetattr"); - } - - // set scroll region to exclude the prompt, - // scroll up one line to make space, - // and move the cursor onto that space. - // - _term_it_send_csi(uty_u, 'r', 2, 1, uty_u->tat_u.siz.row_l - 1); - _term_it_send_csi(uty_u, 'S', 1, 1); - _term_it_send_csi(uty_u, 'H', 2, uty_u->tat_u.siz.row_l - 1, 1); - } - } - } - return stdout; -} - -/* u3_term_io_loja(): release console from fprintf. -*/ -void -u3_term_io_loja(int x, FILE* f) -{ - u3_utty* uty_u = _term_main(); - - if ( uty_u && uty_u->tat_u.siz.row_l ) { - if ( uty_u->fid_i > 2 ) { - // We *should* in fact, produce some kind of fake FILE* for - // non-console terminals. If we use this interface enough... - // - c3_assert(0); - } - else { - if ( c3y == u3_Host.ops_u.tem ) { - fprintf(f, "\n"); - fflush(f); - } - else { - if ( c3y != uty_u->loj_f(uty_u) ) { - c3_assert(!"loja-tcsetattr"); - } - - // clear the scrolling region we set previously, - // and restore cursor to its original position. - // - _term_it_dump_buf(uty_u, &uty_u->ufo_u.reg_u); - _term_it_dump_buf(uty_u, &uty_u->ufo_u.ruc_u); - } - } - } - else { - fprintf(f, "\r\n"); - } -} - -/* u3_term_it_log(): writes a log message -*/ -void -u3_term_io_log(c3_c* line) -{ - FILE* stream = u3_term_io_hija(); - int x = fprintf(stream, "%s", line); - fflush(stream); - u3_term_io_loja(x, stream); //TODO remove arg? unused... -} - -/* u3_term_tape_to(): dump a tape to a file. -*/ -void -u3_term_tape_to(FILE *fil_f, u3_noun tep) -{ - u3_noun tap = tep; - - while ( u3_nul != tap ) { - c3_c car_c; - - if ( u3h(tap) >= 127 ) { - car_c = '?'; - } else car_c = u3h(tap); - - putc(car_c, fil_f); - tap = u3t(tap); - } - u3z(tep); -} - -/* u3_term_tape(): dump a tape to stdout. -*/ -void -u3_term_tape(u3_noun tep) -{ - FILE* fil_f = u3_term_io_hija(); - - u3_term_tape_to(fil_f, tep); - - u3_term_io_loja(0, fil_f); -} - -/* u3_term_wall(): dump a wall to stdout. -*/ -void -u3_term_wall(u3_noun wol) -{ - FILE* fil_f = u3_term_io_hija(); - u3_noun wal = wol; - - while ( u3_nul != wal ) { - u3_term_tape_to(fil_f, u3k(u3h(wal))); - - putc(13, fil_f); - putc(10, fil_f); - - wal = u3t(wal); - } - u3_term_io_loja(0, fil_f); - - u3z(wol); -} - -/* _term_io_talk(): -*/ -static void -_term_io_talk(u3_auto* car_u) -{ - if ( c3n == u3_Host.ops_u.tem ) { - u3_utty* uty_u = _term_main(); - - // start mouse handling - // - _term_it_dump_buf(uty_u, &uty_u->ufo_u.mon_u); - - uv_read_start((uv_stream_t*)&(uty_u->pin_u), - _term_alloc, - _term_read_cb); - } - - //TODO reevaluate wrt dill sessions - // - u3_noun wir = u3nt(c3__term, '1', u3_nul); - u3_noun cad; - - // send terminal dimensions - // - { - cad = u3nc(c3__blew, u3_term_get_blew(1)); - _term_ovum_plan(car_u, u3k(wir), cad); - } - - // refresh terminal state - // - { - cad = u3nc(c3__hail, u3_nul); - _term_ovum_plan(car_u, wir, cad); - } -} - -/* _reck_orchid(): parses only a number as text - * - * Parses a text string which contains a decimal number. In practice, this - * number is always '1'. - */ -static u3_noun -_reck_orchid(u3_noun fot, u3_noun txt, c3_l* tid_l) -{ - c3_c* str = u3r_string(txt); - c3_d ato_d = strtol(str, NULL, 10); - c3_free(str); - - if ( ato_d >= 0x80000000ULL ) { - return c3n; - } else { - *tid_l = (c3_l) ato_d; - - return c3y; - } -} - -/* _term_io_kick(): apply effects. -*/ -static c3_o -_term_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) -{ - u3_noun tag, dat, i_wir, t_wir; - c3_o ret_o; - - if ( (c3n == u3r_cell(wir, &i_wir, &t_wir)) - || (c3n == u3r_cell(cad, &tag, &dat)) - || (c3__term != i_wir) ) - { - ret_o = c3n; - } - else { - u3_noun pud = t_wir; - u3_noun p_pud, q_pud; - c3_l tid_l; - - if ( (c3n == u3r_cell(pud, &p_pud, &q_pud)) - || (u3_nul != q_pud) - || (c3n == _reck_orchid(c3__ud, u3k(p_pud), &tid_l)) ) - { - u3l_log("term: bad tire"); - ret_o = c3n; - } - else { - switch ( tag ) { - default: { - ret_o = c3n; - } break; - - case c3__blit: { - ret_o = c3y; - - { - u3_utty* uty_u = _term_ef_get(tid_l); - if ( 0 == uty_u ) { - // u3l_log("no terminal %d", tid_l); - // u3l_log("uty_u %p", u3_Host.uty_u); - } - else { - u3_noun bis = dat; - - while ( c3y == u3du(bis) ) { - if (c3n == u3_Host.ops_u.tem) { - _term_ef_blit(uty_u, u3k(u3h(bis))); - } - else { - _term_ef_blit_lame(uty_u, u3k(u3h(bis))); - } - bis = u3t(bis); - } - } - } - } break; - - // XX obsolete %ames - // - // case c3__send: - - case c3__logo: { - ret_o = c3y; - u3_pier_exit(car_u->pir_u); - // XX validate? ignore? - // - u3_Host.xit_i = dat; - } break; - - case c3__mass: { - ret_o = c3y; - - // gc the daemon area - // - // XX disabled due to known leaks; uncomment for dev - // - // uv_timer_start(&u3K.tim_u, (uv_timer_cb)u3_king_grab, 0, 0); - } break; - - case c3__meld: { - ret_o = c3y; - u3_pier_meld(car_u->pir_u); - } break; - - case c3__pack: { - ret_o = c3y; - u3_pier_pack(car_u->pir_u); - } break; - } - } - } - - u3z(wir); u3z(cad); - return ret_o; -} - -static void -_term_io_exit_cb(uv_handle_t* han_u) -{ - u3_auto* car_u = han_u->data; - c3_free(car_u); -} - -/* _term_io_exit(): clean up terminal. -*/ -static void -_term_io_exit(u3_auto* car_u) -{ - u3_utty* uty_u = _term_main(); - - if ( c3n == u3_Host.ops_u.tem ) { - // stop mouse handling - // - _term_it_dump_buf(uty_u, &uty_u->ufo_u.mof_u); - - // move cursor to the end - // - _term_it_move_cursor(uty_u, 0, uty_u->tat_u.siz.row_l - 1); - - // NB, closed in u3_term_log_exit() - // - uv_read_stop((uv_stream_t*)&(uty_u->pin_u)); - - uv_timer_t* han_u = &(uty_u->tat_u.sun_u.tim_u); - han_u->data = car_u; - - uv_close((uv_handle_t*)han_u, _term_io_exit_cb); - } - else { - c3_free(car_u); - } -} - -/* u3_term_io_init(): initialize terminal -*/ -u3_auto* -u3_term_io_init(u3_pier* pir_u) -{ - u3_auto* car_u = c3_calloc(sizeof(*car_u)); - - c3_assert( u3_Host.uty_u ); - u3_Host.uty_u->car_u = car_u; - - car_u->nam_m = c3__term; - car_u->liv_o = c3y; - car_u->io.talk_f = _term_io_talk; - car_u->io.kick_f = _term_io_kick; - car_u->io.exit_f = _term_io_exit; - - return car_u; -} diff --git a/pkg/urbit/vere/io/unix.c b/pkg/urbit/vere/io/unix.c deleted file mode 100644 index 57df1f999..000000000 --- a/pkg/urbit/vere/io/unix.c +++ /dev/null @@ -1,1600 +0,0 @@ -/* vere/unix.c -** -** this file is responsible for maintaining a bidirectional -** mapping between the contents of a clay desk and a directory -** in a unix filesystem. -** -** TODO this driver is crufty and overdue for a rewrite. -** aspirationally, the rewrite should do sanity checking and -** transformations at the noun level to convert messages from -** arvo into sets of fs operations on trusted inputs, and -** inverse transformations and checks for fs contents to arvo -** messages. -** -** the two relevant transformations to apply are: -** -** 1. bidirectionally map file contents to atoms -** 2. bidirectionally map arvo $path <-> unix relative paths -** -** the first transform is trivial. the second poses some -** challenges: an arvo $path is a list of $knot, and the $knot -** space intersects with invalid unix paths in the three cases -** of: %$ (the empty knot), '.', and '..'. we escape these by -** prepending a '!' to the filename corresponding to the $knot, -** yielding unix files named '!', '!.', and '!..'. -** -** there is also the case of the empty path. we elide empty -** paths from this wrapper, which always uses the last path -** component as the file extension/mime-type. -** -** these transforms are implemented, but they ought to be -** implemented in one place, prior to any fs calls; as-is, they -** are sprinkled throughout the file updating code. -** -*/ -#include "all.h" -#include -#include "vere/vere.h" - -struct _u3_umon; -struct _u3_udir; -struct _u3_ufil; - -/* u3_unod: file or directory. -*/ - typedef struct _u3_unod { - c3_o dir; // c3y if dir, c3n if file - c3_o dry; // ie, unmodified - c3_c* pax_c; // absolute path - struct _u3_udir* par_u; // parent - struct _u3_unod* nex_u; // internal list - } u3_unod; - -/* u3_ufil: synchronized file. -*/ - typedef struct _u3_ufil { - c3_o dir; // c3y if dir, c3n if file - c3_o dry; // ie, unmodified - c3_c* pax_c; // absolute path - struct _u3_udir* par_u; // parent - struct _u3_unod* nex_u; // internal list - c3_w gum_w; // mug of last %ergo - } u3_ufil; - -/* u3_ufil: synchronized directory. -*/ - typedef struct _u3_udir { - c3_o dir; // c3y if dir, c3n if file - c3_o dry; // ie, unmodified - c3_c* pax_c; // absolute path - struct _u3_udir* par_u; // parent - struct _u3_unod* nex_u; // internal list - u3_unod* kid_u; // subnodes - } u3_udir; - -/* u3_ufil: synchronized mount point. -*/ - typedef struct _u3_umon { - u3_udir dir_u; // root directory, must be first - c3_c* nam_c; // mount point name - struct _u3_umon* nex_u; // internal list - } u3_umon; - -/* u3_unix: clay support system, also -*/ - typedef struct _u3_unix { - u3_auto car_u; - c3_l sev_l; // instance number - u3_umon* mon_u; // mount points - c3_c* pax_c; // pier directory - c3_o alm; // timer set - c3_o dyr; // ready to update - u3_noun sat; // (sane %ta) handle -#ifdef SYNCLOG - c3_w lot_w; // sync-slot - struct _u3_sylo { - c3_o unx; // from unix - c3_m wer_m; // mote saying where - c3_m wot_m; // mote saying what - c3_c* pax_c; // path - } sylo[1024]; -#endif - } u3_unix; - -void -u3_unix_ef_look(u3_unix* unx_u, u3_noun mon, u3_noun all); - -/* u3_unix_cane(): true iff (unix) path is canonical. -*/ -c3_t -u3_unix_cane(const c3_c* pax_c) -{ - if ( 0 == pax_c ) { - return 0; - } - // allow absolute paths. - // - if ( '/' == *pax_c ) { - pax_c++; - // allow root. - // - if ( 0 == *pax_c ) { - return 1; - } - } - do { - if ( 0 == *pax_c - || 0 == strcmp(".", pax_c) - || 0 == strcmp("..", pax_c) - || 0 == strncmp("/", pax_c, 1) - || 0 == strncmp("./", pax_c, 2) - || 0 == strncmp("../", pax_c, 3) ) - { - return 0; - } - pax_c = strchr(pax_c, '/'); - } while ( 0 != pax_c++ ); - return 1; -} - -/* _unix_sane_ta(): true iff pat is a valid @ta -** -** %ta is parsed by: -** (star ;~(pose nud low hep dot sig cab)) -*/ -static c3_t -_unix_sane_ta(u3_unix* unx_u, u3_atom pat) -{ - return _(u3n_slam_on(u3k(unx_u->sat), pat)); -} - -/* u3_readdir_r(): -*/ -c3_w -u3_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) -{ - errno = 0; - struct dirent * tmp_u = readdir(dirp); - - if (NULL == tmp_u){ - *result = NULL; - return (errno); // either success or error code - } else { - memcpy(entry, tmp_u, sizeof(struct dirent)); - *result = entry; - } - - return(0); -} - -/* _unix_string_to_knot(): convert c unix path component to $knot -*/ -static u3_atom -_unix_string_to_knot(c3_c* pax_c) -{ - c3_assert(pax_c); - // XX this can happen if we encounter a file without an extension. - // - // c3_assert(*pax_c); - c3_assert(!strchr(pax_c, '/')); - // XX horrible - // -# ifdef _WIN32 - c3_assert(!strchr(pax_c, '\\')); -# endif - if ( '!' == *pax_c ) { - pax_c++; - } - return u3i_string(pax_c); -} - -/* _unix_knot_to_string(): convert $knot to c unix path component. RETAIN. -*/ -static c3_c* -_unix_knot_to_string(u3_atom pon) -{ - c3_c* ret_c; - - if ( u3_nul != pon - && c3_s1('.') != pon - && c3_s2('.','.') != pon - && '!' != u3r_byte(0, pon) ) - { - ret_c = u3r_string(pon); - } - else { - c3_w met_w = u3r_met(3, pon); - - ret_c = c3_malloc(met_w + 2); - *ret_c = '!'; - u3r_bytes(0, met_w, (c3_y*)ret_c + 1, pon); - ret_c[met_w + 1] = 0; - } - c3_assert(!strchr(ret_c, '/')); -# ifdef _WIN32 - c3_assert(!strchr(ret_c, '\\')); -# endif - return ret_c; -} - -/* _unix_down(): descend path. -*/ -static c3_c* -_unix_down(c3_c* pax_c, c3_c* sub_c) -{ - c3_w pax_w = strlen(pax_c); - c3_w sub_w = strlen(sub_c); - c3_c* don_c = c3_malloc(pax_w + sub_w + 2); - - strcpy(don_c, pax_c); - don_c[pax_w] = '/'; - strcpy(don_c + pax_w + 1, sub_c); - don_c[pax_w + 1 + sub_w] = '\0'; - - return don_c; -} - -/* _unix_string_to_path(): convert c string to u3_noun $path -** -** c string must begin with the pier path plus mountpoint -*/ -static u3_noun -_unix_string_to_path_helper(c3_c* pax_c) -{ - u3_noun not; - - c3_assert(pax_c[-1] == '/'); - c3_c* end_c = strchr(pax_c, '/'); - if ( !end_c ) { - end_c = strrchr(pax_c, '.'); - if ( !end_c ) { - return u3nc(_unix_string_to_knot(pax_c), u3_nul); - } - else { - *end_c = 0; - not = _unix_string_to_knot(pax_c); - *end_c = '.'; - return u3nt(not, _unix_string_to_knot(end_c + 1), u3_nul); - } - } - else { - *end_c = 0; - not = _unix_string_to_knot(pax_c); - *end_c = '/'; - return u3nc(not, _unix_string_to_path_helper(end_c + 1)); - } -} -static u3_noun -_unix_string_to_path(u3_unix* unx_u, c3_c* pax_c) -{ - pax_c += strlen(unx_u->pax_c) + 1; - c3_c* pox_c = strchr(pax_c, '/'); - if ( !pox_c ) { - pox_c = strchr(pax_c, '.'); - if ( !pox_c ) { - return u3_nul; - } - else { - return u3nc(_unix_string_to_knot(pox_c + 1), u3_nul); - } - } - else { - return _unix_string_to_path_helper(pox_c + 1); - } -} - -/* _unix_mkdirp(): recursive mkdir of dirname of pax_c. -*/ -static void -_unix_mkdirp(c3_c* pax_c) -{ - c3_c* fas_c = strchr(pax_c + 1, '/'); - - while ( fas_c ) { - *fas_c = 0; - if ( 0 != mkdir(pax_c, 0777) && EEXIST != errno ) { - u3l_log("unix: mkdir %s: %s", pax_c, strerror(errno)); - u3m_bail(c3__fail); - } - *fas_c++ = '/'; - fas_c = strchr(fas_c, '/'); - } -} - -/* u3_unix_save(): save file under .../.urb/put or bail. -** -** XX this is quite bad, and doesn't share much in common with -** the rest of unix.c. a refactor would probably share common -** logic with _unix_sync_change, perhaps using openat, making -** unx_u optional, and/or having a flag to not track the file -** for future changes. -*/ -void -u3_unix_save(c3_c* pax_c, u3_atom pad) -{ - c3_i fid_i; - c3_w lod_w, len_w, fln_w, rit_w; - c3_y* pad_y; - c3_c* ful_c; - - if ( !u3_unix_cane(pax_c) ) { - u3l_log("%s: non-canonical path", pax_c); - u3z(pad); u3m_bail(c3__fail); - } - if ( '/' == *pax_c) { - pax_c++; - } - lod_w = strlen(u3_Host.dir_c); - len_w = lod_w + sizeof("/.urb/put/") + strlen(pax_c); - ful_c = c3_malloc(len_w); - rit_w = snprintf(ful_c, len_w, "%s/.urb/put/%s", u3_Host.dir_c, pax_c); - c3_assert(len_w == rit_w + 1); - - _unix_mkdirp(ful_c); - fid_i = c3_open(ful_c, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if ( fid_i < 0 ) { - u3l_log("%s: %s", ful_c, strerror(errno)); - c3_free(ful_c); - u3z(pad); u3m_bail(c3__fail); - } - - fln_w = u3r_met(3, pad); - pad_y = c3_malloc(fln_w); - u3r_bytes(0, fln_w, pad_y, pad); - u3z(pad); - rit_w = write(fid_i, pad_y, fln_w); - close(fid_i); - c3_free(pad_y); - - if ( rit_w != fln_w ) { - u3l_log("%s: %s", ful_c, strerror(errno)); - c3_free(ful_c); - u3m_bail(c3__fail); - } - c3_free(ful_c); -} - -/* _unix_rm_r_cb(): callback to delete individual files/directories -*/ -static c3_i -_unix_rm_r_cb(const c3_c* pax_c, - const struct stat* buf_u, - c3_i typeflag, - struct FTW* ftw_u) -{ - switch ( typeflag ) { - default: - u3l_log("bad file type in rm_r: %s", pax_c); - break; - case FTW_F: - if ( 0 != c3_unlink(pax_c) && ENOENT != errno ) { - u3l_log("error unlinking (in rm_r) %s: %s", - pax_c, strerror(errno)); - c3_assert(0); - } - break; - case FTW_D: - u3l_log("shouldn't have gotten pure directory: %s", pax_c); - break; - case FTW_DNR: - u3l_log("couldn't read directory: %s", pax_c); - break; - case FTW_NS: - u3l_log("couldn't stat path: %s", pax_c); - break; - case FTW_DP: - if ( 0 != c3_rmdir(pax_c) && ENOENT != errno ) { - u3l_log("error rmdiring %s: %s", pax_c, strerror(errno)); - c3_assert(0); - } - break; - case FTW_SL: - u3l_log("got symbolic link: %s", pax_c); - break; - case FTW_SLN: - u3l_log("got nonexistent symbolic link: %s", pax_c); - break; - } - - return 0; -} - -/* _unix_rm_r(): rm -r directory -*/ -static void -_unix_rm_r(c3_c* pax_c) -{ - if ( 0 > nftw(pax_c, _unix_rm_r_cb, 100, FTW_DEPTH | FTW_PHYS ) - && ENOENT != errno) { - u3l_log("rm_r error on %s: %s", pax_c, strerror(errno)); - } -} - -/* _unix_mkdir(): mkdir, asserting. -*/ -static void -_unix_mkdir(c3_c* pax_c) -{ - if ( 0 != c3_mkdir(pax_c, 0755) && EEXIST != errno) { - u3l_log("error mkdiring %s: %s", pax_c, strerror(errno)); - c3_assert(0); - } -} - -/* _unix_write_file_hard(): write to a file, overwriting what's there -*/ -static c3_w -_unix_write_file_hard(c3_c* pax_c, u3_noun mim) -{ - c3_i fid_i = c3_open(pax_c, O_WRONLY | O_CREAT | O_TRUNC, 0666); - c3_w len_w, rit_w, siz_w, mug_w = 0; - c3_y* dat_y; - - u3_noun dat = u3t(u3t(mim)); - - if ( fid_i < 0 ) { - u3l_log("error opening %s for writing: %s", - pax_c, strerror(errno)); - u3z(mim); - return 0; - } - - siz_w = u3h(u3t(mim)); - len_w = u3r_met(3, dat); - dat_y = c3_calloc(siz_w); - - u3r_bytes(0, len_w, dat_y, dat); - u3z(mim); - - rit_w = write(fid_i, dat_y, siz_w); - - if ( rit_w != siz_w ) { - u3l_log("error writing %s: %s", - pax_c, strerror(errno)); - mug_w = 0; - } - else { - mug_w = u3r_mug_bytes(dat_y, len_w); - } - - close(fid_i); - c3_free(dat_y); - - return mug_w; -} - -/* _unix_write_file_soft(): write to a file, not overwriting if it's changed -*/ -static void -_unix_write_file_soft(u3_ufil* fil_u, u3_noun mim) -{ - struct stat buf_u; - c3_i fid_i = c3_open(fil_u->pax_c, O_RDONLY, 0644); - c3_ws len_ws, red_ws; - c3_w old_w; - c3_y* old_y; - - if ( fid_i < 0 || fstat(fid_i, &buf_u) < 0 ) { - if ( ENOENT == errno ) { - goto _unix_write_file_soft_go; - } - else { - u3l_log("error opening file (soft) %s: %s", - fil_u->pax_c, strerror(errno)); - u3z(mim); - return; - } - } - - len_ws = buf_u.st_size; - old_y = c3_malloc(len_ws); - - red_ws = read(fid_i, old_y, len_ws); - - if ( close(fid_i) < 0 ) { - u3l_log("error closing file (soft) %s: %s", - fil_u->pax_c, strerror(errno)); - } - - if ( len_ws != red_ws ) { - if ( red_ws < 0 ) { - u3l_log("error reading file (soft) %s: %s", - fil_u->pax_c, strerror(errno)); - } - else { - u3l_log("wrong # of bytes read in file %s: %d %d", - fil_u->pax_c, len_ws, red_ws); - } - c3_free(old_y); - u3z(mim); - return; - } - - old_w = u3r_mug_bytes(old_y, len_ws); - - if ( old_w != fil_u->gum_w ) { - fil_u->gum_w = u3r_mug(u3t(u3t(mim))); // XXX this might fail with - c3_free(old_y); // trailing zeros - u3z(mim); - return; - } - - c3_free(old_y); - -_unix_write_file_soft_go: - fil_u->gum_w = _unix_write_file_hard(fil_u->pax_c, mim); -} - -static void -_unix_watch_dir(u3_udir* dir_u, u3_udir* par_u, c3_c* pax_c); -static void -_unix_watch_file(u3_unix* unx_u, u3_ufil* fil_u, u3_udir* par_u, c3_c* pax_c); - -/* _unix_get_mount_point(): retrieve or create mount point -*/ -static u3_umon* -_unix_get_mount_point(u3_unix* unx_u, u3_noun mon) -{ - if ( c3n == u3ud(mon) ) { - c3_assert(!"mount point must be an atom"); - u3z(mon); - return NULL; - } - - c3_c* nam_c = _unix_knot_to_string(mon); - u3_umon* mon_u; - - for ( mon_u = unx_u->mon_u; - mon_u && 0 != strcmp(nam_c, mon_u->nam_c); - mon_u = mon_u->nex_u ) - { - } - - if ( !mon_u ) { - mon_u = c3_malloc(sizeof(u3_umon)); - mon_u->nam_c = nam_c; - mon_u->dir_u.dir = c3y; - mon_u->dir_u.dry = c3n; - mon_u->dir_u.pax_c = strdup(unx_u->pax_c); - mon_u->dir_u.par_u = NULL; - mon_u->dir_u.nex_u = NULL; - mon_u->dir_u.kid_u = NULL; - mon_u->nex_u = unx_u->mon_u; - unx_u->mon_u = mon_u; - } - else { - c3_free(nam_c); - } - - u3z(mon); - - return mon_u; -} - -/* _unix_scan_mount_point(): scan unix for already-existing mount point -*/ -static void -_unix_scan_mount_point(u3_unix* unx_u, u3_umon* mon_u) -{ - DIR* rid_u = c3_opendir(mon_u->dir_u.pax_c); - if ( !rid_u ) { - u3l_log("error opening pier directory: %s: %s", - mon_u->dir_u.pax_c, strerror(errno)); - return; - } - - c3_w len_w = strlen(mon_u->nam_c); - - while ( 1 ) { - struct dirent ent_u; - struct dirent* out_u; - c3_w err_w; - - if ( 0 != (err_w = u3_readdir_r(rid_u, &ent_u, &out_u)) ) { - u3l_log("erroring loading pier directory %s: %s", - mon_u->dir_u.pax_c, strerror(errno)); - - c3_assert(0); - } - else if ( !out_u ) { - break; - } - else if ( '.' == out_u->d_name[0] ) { // unnecessary, but consistency - continue; - } - else if ( 0 != strncmp(mon_u->nam_c, out_u->d_name, len_w) ) { - continue; - } - else { - c3_c* pax_c = _unix_down(mon_u->dir_u.pax_c, out_u->d_name); - - struct stat buf_u; - - if ( 0 != stat(pax_c, &buf_u) ) { - u3l_log("can't stat pier directory %s: %s", - mon_u->dir_u.pax_c, strerror(errno)); - c3_free(pax_c); - continue; - } - if ( S_ISDIR(buf_u.st_mode) ) { - if ( out_u->d_name[len_w] != '\0' ) { - c3_free(pax_c); - continue; - } - else { - u3_udir* dir_u = c3_malloc(sizeof(u3_udir)); - _unix_watch_dir(dir_u, &mon_u->dir_u, pax_c); - } - } - else { - if ( '.' != out_u->d_name[len_w] - || '\0' == out_u->d_name[len_w + 1] - || '~' == out_u->d_name[strlen(out_u->d_name) - 1] - || !_unix_sane_ta(unx_u, _unix_string_to_knot(out_u->d_name)) ) - { - c3_free(pax_c); - continue; - } - else { - u3_ufil* fil_u = c3_malloc(sizeof(u3_ufil)); - _unix_watch_file(unx_u, fil_u, &mon_u->dir_u, pax_c); - } - } - - c3_free(pax_c); - } - } -} - -static u3_noun _unix_free_node(u3_unix* unx_u, u3_unod* nod_u); - -/* _unix_free_file(): free file, unlinking it -*/ -static void -_unix_free_file(u3_ufil *fil_u) -{ - if ( 0 != c3_unlink(fil_u->pax_c) && ENOENT != errno ) { - u3l_log("error unlinking %s: %s", fil_u->pax_c, strerror(errno)); - c3_assert(0); - } - - c3_free(fil_u->pax_c); - c3_free(fil_u); -} - -/* _unix_free_dir(): free directory, deleting everything within -*/ -static void -_unix_free_dir(u3_udir *dir_u) -{ - _unix_rm_r(dir_u->pax_c); - - if ( dir_u->kid_u ) { - fprintf(stderr, "don't kill me, i've got a family %s\r\n", dir_u->pax_c); - } - else { - // fprintf(stderr, "i'm a lone, lonely loner %s\r\n", dir_u->pax_c); - } - c3_free(dir_u->pax_c); - c3_free(dir_u); // XXX this might be too early, how do we - // know we've freed all the children? - // i suspect we should do this only if - // our kid list is empty -} - -/* _unix_free_node(): free node, deleting everything within -** -** also deletes from parent list if in it -*/ -static u3_noun -_unix_free_node(u3_unix* unx_u, u3_unod* nod_u) -{ - u3_noun can; - if ( nod_u->par_u ) { - u3_unod* don_u = nod_u->par_u->kid_u; - - if ( !don_u ) { - } - else if ( nod_u == don_u ) { - nod_u->par_u->kid_u = nod_u->par_u->kid_u->nex_u; - } - else { - for ( ; don_u->nex_u && nod_u != don_u->nex_u; don_u = don_u->nex_u ) { - } - if ( don_u->nex_u ) { - don_u->nex_u = don_u->nex_u->nex_u; - } - } - } - - if ( c3y == nod_u->dir ) { - can = u3_nul; - u3_unod* nud_u = ((u3_udir*) nod_u)->kid_u; - while ( nud_u ) { - u3_unod* nex_u = nud_u->nex_u; - can = u3kb_weld(_unix_free_node(unx_u, nud_u), can); - nud_u = nex_u; - } - _unix_free_dir((u3_udir *)nod_u); - } - else { - can = u3nc(u3nc(_unix_string_to_path(unx_u, nod_u->pax_c), u3_nul), - u3_nul); - _unix_free_file((u3_ufil *)nod_u); - } - - return can; -} - -/* _unix_free_mount_point(): free mount point -** -** this process needs to happen in a very careful order. in -** particular, we must recurse before we get to the callback, so -** that libuv does all the child directories before it does us. -** -** tread carefully -*/ -static void -_unix_free_mount_point(u3_unix* unx_u, u3_umon* mon_u) -{ - u3_unod* nod_u; - for ( nod_u = mon_u->dir_u.kid_u; nod_u; ) { - u3_unod* nex_u = nod_u->nex_u; - u3z(_unix_free_node(unx_u, nod_u)); - nod_u = nex_u; - } - - c3_free(mon_u->dir_u.pax_c); - c3_free(mon_u->nam_c); - c3_free(mon_u); -} - -/* _unix_delete_mount_point(): remove mount point from list and free -*/ -static void -_unix_delete_mount_point(u3_unix* unx_u, u3_noun mon) -{ - if ( c3n == u3ud(mon) ) { - c3_assert(!"mount point must be an atom"); - u3z(mon); - return; - } - - c3_c* nam_c = _unix_knot_to_string(mon); - u3_umon* mon_u; - u3_umon* tem_u; - - mon_u = unx_u->mon_u; - if ( !mon_u ) { - u3l_log("mount point already gone: %s", nam_c); - goto _delete_mount_point_out; - } - if ( 0 == strcmp(nam_c, mon_u->nam_c) ) { - unx_u->mon_u = mon_u->nex_u; - _unix_free_mount_point(unx_u, mon_u); - goto _delete_mount_point_out; - } - - for ( ; - mon_u->nex_u && 0 != strcmp(nam_c, mon_u->nex_u->nam_c); - mon_u = mon_u->nex_u ) - { - } - - if ( !mon_u->nex_u ) { - u3l_log("mount point already gone: %s", nam_c); - goto _delete_mount_point_out; - } - - tem_u = mon_u->nex_u; - mon_u->nex_u = mon_u->nex_u->nex_u; - _unix_free_mount_point(unx_u, tem_u); - -_delete_mount_point_out: - c3_free(nam_c); - u3z(mon); -} - -/* _unix_commit_mount_point: commit from mount point -*/ -static void -_unix_commit_mount_point(u3_unix* unx_u, u3_noun mon) -{ - unx_u->dyr = c3y; - u3_unix_ef_look(unx_u, mon, c3n); - return; -} - -/* _unix_watch_file(): initialize file -*/ -static void -_unix_watch_file(u3_unix* unx_u, u3_ufil* fil_u, u3_udir* par_u, c3_c* pax_c) -{ - // initialize fil_u - - fil_u->dir = c3n; - fil_u->dry = c3n; - fil_u->pax_c = c3_malloc(1 + strlen(pax_c)); - strcpy(fil_u->pax_c, pax_c); - fil_u->par_u = par_u; - fil_u->nex_u = NULL; - fil_u->gum_w = 0; - - if ( par_u ) { - fil_u->nex_u = par_u->kid_u; - par_u->kid_u = (u3_unod*) fil_u; - } -} - -/* _unix_watch_dir(): initialize directory -*/ -static void -_unix_watch_dir(u3_udir* dir_u, u3_udir* par_u, c3_c* pax_c) -{ - // initialize dir_u - - dir_u->dir = c3y; - dir_u->dry = c3n; - dir_u->pax_c = c3_malloc(1 + strlen(pax_c)); - strcpy(dir_u->pax_c, pax_c); - dir_u->par_u = par_u; - dir_u->nex_u = NULL; - dir_u->kid_u = NULL; - - if ( par_u ) { - dir_u->nex_u = par_u->kid_u; - par_u->kid_u = (u3_unod*) dir_u; - } -} - -/* _unix_create_dir(): create unix directory and watch it -*/ -static void -_unix_create_dir(u3_udir* dir_u, u3_udir* par_u, u3_noun nam) -{ - c3_c* nam_c = _unix_knot_to_string(nam); - c3_w nam_w = strlen(nam_c); - c3_w pax_w = strlen(par_u->pax_c); - c3_c* pax_c = c3_malloc(pax_w + 1 + nam_w + 1); - - strcpy(pax_c, par_u->pax_c); - pax_c[pax_w] = '/'; - strcpy(pax_c + pax_w + 1, nam_c); - pax_c[pax_w + 1 + nam_w] = '\0'; - - c3_free(nam_c); - u3z(nam); - - _unix_mkdir(pax_c); - _unix_watch_dir(dir_u, par_u, pax_c); -} - -static u3_noun _unix_update_node(u3_unix* unx_u, u3_unod* nod_u); - -/* _unix_update_file(): update file, producing list of changes -** -** when scanning through files, if dry, do nothing. otherwise, -** mark as dry, then check if file exists. if not, remove -** self from node list and add path plus sig to %into event. -** otherwise, read the file and get a mug checksum. if same as -** gum_w, move on. otherwise, overwrite add path plus data to -** %into event. -*/ -static u3_noun -_unix_update_file(u3_unix* unx_u, u3_ufil* fil_u) -{ - c3_assert( c3n == fil_u->dir ); - - if ( c3y == fil_u->dry ) { - return u3_nul; - } - - fil_u->dry = c3n; - - struct stat buf_u; - c3_i fid_i = c3_open(fil_u->pax_c, O_RDONLY, 0644); - c3_ws len_ws, red_ws; - c3_y* dat_y; - - if ( fid_i < 0 || fstat(fid_i, &buf_u) < 0 ) { - if ( ENOENT == errno ) { - return u3nc(u3nc(_unix_string_to_path(unx_u, fil_u->pax_c), u3_nul), u3_nul); - } - else { - u3l_log("error opening file %s: %s", - fil_u->pax_c, strerror(errno)); - return u3_nul; - } - } - - len_ws = buf_u.st_size; - dat_y = c3_malloc(len_ws); - - red_ws = read(fid_i, dat_y, len_ws); - - if ( close(fid_i) < 0 ) { - u3l_log("error closing file %s: %s", - fil_u->pax_c, strerror(errno)); - } - - if ( len_ws != red_ws ) { - if ( red_ws < 0 ) { - u3l_log("error reading file %s: %s", - fil_u->pax_c, strerror(errno)); - } - else { - u3l_log("wrong # of bytes read in file %s: %d %d", - fil_u->pax_c, len_ws, red_ws); - } - c3_free(dat_y); - return u3_nul; - } - else { - c3_w mug_w = u3r_mug_bytes(dat_y, len_ws); - if ( mug_w == fil_u->gum_w ) { - c3_free(dat_y); - return u3_nul; - } - else { - u3_noun pax = _unix_string_to_path(unx_u, fil_u->pax_c); - u3_noun mim = u3nt(c3__text, u3i_string("plain"), u3_nul); - u3_noun dat = u3nt(mim, len_ws, u3i_bytes(len_ws, dat_y)); - - c3_free(dat_y); - return u3nc(u3nt(pax, u3_nul, dat), u3_nul); - } - } -} - -/* _unix_update_dir(): update directory, producing list of changes -** -** when changing this, consider whether to also change -** _unix_initial_update_dir() -*/ -static u3_noun -_unix_update_dir(u3_unix* unx_u, u3_udir* dir_u) -{ - u3_noun can = u3_nul; - - c3_assert( c3y == dir_u->dir ); - - if ( c3y == dir_u->dry ) { - return u3_nul; - } - - dir_u->dry = c3n; - - // Check that old nodes are still there - - u3_unod* nod_u = dir_u->kid_u; - - if ( nod_u ) { - while ( nod_u ) { - if ( c3y == nod_u->dry ) { - nod_u = nod_u->nex_u; - } - else { - if ( c3y == nod_u->dir ) { - DIR* red_u = c3_opendir(nod_u->pax_c); - if ( 0 == red_u ) { - u3_unod* nex_u = nod_u->nex_u; - can = u3kb_weld(_unix_free_node(unx_u, nod_u), can); - nod_u = nex_u; - } - else { - closedir(red_u); - nod_u = nod_u->nex_u; - } - } - else { - struct stat buf_u; - c3_i fid_i = c3_open(nod_u->pax_c, O_RDONLY, 0644); - - if ( (fid_i < 0) || (fstat(fid_i, &buf_u) < 0) ) { - if ( ENOENT != errno ) { - u3l_log("_unix_update_dir: error opening file %s: %s", - nod_u->pax_c, strerror(errno)); - } - - u3_unod* nex_u = nod_u->nex_u; - can = u3kb_weld(_unix_free_node(unx_u, nod_u), can); - nod_u = nex_u; - } - else { - if ( close(fid_i) < 0 ) { - u3l_log("_unix_update_dir: error closing file %s: %s", - nod_u->pax_c, strerror(errno)); - } - - nod_u = nod_u->nex_u; - } - } - } - } - } - - // Check for new nodes - - DIR* rid_u = c3_opendir(dir_u->pax_c); - if ( !rid_u ) { - u3l_log("error opening directory %s: %s", - dir_u->pax_c, strerror(errno)); - c3_assert(0); - } - - while ( 1 ) { - struct dirent ent_u; - struct dirent* out_u; - c3_w err_w; - - - if ( (err_w = u3_readdir_r(rid_u, &ent_u, &out_u)) != 0 ) { - u3l_log("error loading directory %s: %s", - dir_u->pax_c, strerror(err_w)); - c3_assert(0); - } - else if ( !out_u ) { - break; - } - else if ( '.' == out_u->d_name[0] ) { - continue; - } - else { - c3_c* pax_c = _unix_down(dir_u->pax_c, out_u->d_name); - - struct stat buf_u; - - if ( 0 != stat(pax_c, &buf_u) ) { - u3l_log("can't stat %s: %s", pax_c, strerror(errno)); - c3_free(pax_c); - continue; - } - else { - u3_unod* nod_u; - for ( nod_u = dir_u->kid_u; nod_u; nod_u = nod_u->nex_u ) { - if ( 0 == strcmp(pax_c, nod_u->pax_c) ) { - if ( S_ISDIR(buf_u.st_mode) ) { - if ( c3n == nod_u->dir ) { - u3l_log("not a directory: %s", nod_u->pax_c); - c3_assert(0); - } - } - else { - if ( c3y == nod_u->dir ) { - u3l_log("not a file: %s", nod_u->pax_c); - c3_assert(0); - } - } - break; - } - } - - if ( !nod_u ) { - if ( !S_ISDIR(buf_u.st_mode) ) { - if ( !strchr(out_u->d_name,'.') - || '~' == out_u->d_name[strlen(out_u->d_name) - 1] - || !_unix_sane_ta(unx_u, _unix_string_to_knot(out_u->d_name)) ) - { - c3_free(pax_c); - continue; - } - - u3_ufil* fil_u = c3_malloc(sizeof(u3_ufil)); - _unix_watch_file(unx_u, fil_u, dir_u, pax_c); - } - else { - u3_udir* dis_u = c3_malloc(sizeof(u3_udir)); - _unix_watch_dir(dis_u, dir_u, pax_c); - can = u3kb_weld(_unix_update_dir(unx_u, dis_u), can); // XXX unnecessary? - } - } - } - - c3_free(pax_c); - } - } - - if ( closedir(rid_u) < 0 ) { - u3l_log("error closing directory %s: %s", - dir_u->pax_c, strerror(errno)); - } - - if ( !dir_u->kid_u ) { - return u3kb_weld(_unix_free_node(unx_u, (u3_unod*) dir_u), can); - } - - // get change list - - for ( nod_u = dir_u->kid_u; nod_u; nod_u = nod_u->nex_u ) { - can = u3kb_weld(_unix_update_node(unx_u, nod_u), can); - } - - return can; -} - -/* _unix_update_node(): update node, producing list of changes -*/ -static u3_noun -_unix_update_node(u3_unix* unx_u, u3_unod* nod_u) -{ - if ( c3y == nod_u->dir ) { - return _unix_update_dir(unx_u, (void*)nod_u); - } - else { - return _unix_update_file(unx_u, (void*)nod_u); - } -} - -/* _unix_update_mount(): update mount point -*/ -static void -_unix_update_mount(u3_unix* unx_u, u3_umon* mon_u, u3_noun all) -{ - if ( c3n == mon_u->dir_u.dry ) { - u3_noun can = u3_nul; - u3_unod* nod_u; - for ( nod_u = mon_u->dir_u.kid_u; nod_u; nod_u = nod_u->nex_u ) { - can = u3kb_weld(_unix_update_node(unx_u, nod_u), can); - } - - { - // XX remove u3A->sen - // - u3_noun wir = u3nt(c3__sync, - u3dc("scot", c3__uv, unx_u->sev_l), - u3_nul); - u3_noun cad = u3nq(c3__into, _unix_string_to_knot(mon_u->nam_c), all, - can); - - u3_auto_plan(&unx_u->car_u, u3_ovum_init(0, c3__c, wir, cad)); - } - } -} - -/* _unix_initial_update_file(): read file, but don't watch -** XX deduplicate with _unix_update_file() -*/ -static u3_noun -_unix_initial_update_file(c3_c* pax_c, c3_c* bas_c) -{ - struct stat buf_u; - c3_i fid_i = c3_open(pax_c, O_RDONLY, 0644); - c3_ws len_ws, red_ws; - c3_y* dat_y; - - if ( fid_i < 0 || fstat(fid_i, &buf_u) < 0 ) { - if ( ENOENT == errno ) { - return u3_nul; - } - else { - u3l_log("error opening initial file %s: %s", - pax_c, strerror(errno)); - return u3_nul; - } - } - - len_ws = buf_u.st_size; - dat_y = c3_malloc(len_ws); - - red_ws = read(fid_i, dat_y, len_ws); - - if ( close(fid_i) < 0 ) { - u3l_log("error closing initial file %s: %s", - pax_c, strerror(errno)); - } - - if ( len_ws != red_ws ) { - if ( red_ws < 0 ) { - u3l_log("error reading initial file %s: %s", - pax_c, strerror(errno)); - } - else { - u3l_log("wrong # of bytes read in initial file %s: %d %d", - pax_c, len_ws, red_ws); - } - c3_free(dat_y); - return u3_nul; - } - else { - u3_noun pax = _unix_string_to_path_helper(pax_c - + strlen(bas_c) - + 1); /* XX slightly less VERY BAD than before*/ - u3_noun mim = u3nt(c3__text, u3i_string("plain"), u3_nul); - u3_noun dat = u3nt(mim, len_ws, u3i_bytes(len_ws, dat_y)); - - c3_free(dat_y); - return u3nc(u3nt(pax, u3_nul, dat), u3_nul); - } -} - -/* _unix_initial_update_dir(): read directory, but don't watch -** XX deduplicate with _unix_update_dir() -*/ -static u3_noun -_unix_initial_update_dir(c3_c* pax_c, c3_c* bas_c) -{ - u3_noun can = u3_nul; - - DIR* rid_u = c3_opendir(pax_c); - if ( !rid_u ) { - u3l_log("error opening initial directory: %s: %s", - pax_c, strerror(errno)); - return u3_nul; - } - - while ( 1 ) { - struct dirent ent_u; - struct dirent* out_u; - c3_w err_w; - - if ( 0 != (err_w = u3_readdir_r(rid_u, &ent_u, &out_u)) ) { - u3l_log("error loading initial directory %s: %s", - pax_c, strerror(errno)); - - c3_assert(0); - } - else if ( !out_u ) { - break; - } - else if ( '.' == out_u->d_name[0] ) { - continue; - } - else { - c3_c* pox_c = _unix_down(pax_c, out_u->d_name); - - struct stat buf_u; - - if ( 0 != stat(pox_c, &buf_u) ) { - u3l_log("initial can't stat %s: %s", - pox_c, strerror(errno)); - c3_free(pox_c); - continue; - } - else { - if ( S_ISDIR(buf_u.st_mode) ) { - can = u3kb_weld(_unix_initial_update_dir(pox_c, bas_c), can); - } - else { - can = u3kb_weld(_unix_initial_update_file(pox_c, bas_c), can); - } - c3_free(pox_c); - } - } - } - - if ( closedir(rid_u) < 0 ) { - u3l_log("error closing initial directory %s: %s", - pax_c, strerror(errno)); - } - - return can; -} - -/* u3_unix_initial_into_card(): create initial filesystem sync card. -*/ -u3_noun -u3_unix_initial_into_card(c3_c* arv_c) -{ - u3_noun can = _unix_initial_update_dir(arv_c, arv_c); - - return u3nc(u3nt(c3__c, c3__sync, u3_nul), - u3nq(c3__into, u3_nul, c3y, can)); -} - -/* _unix_sync_file(): sync file to unix -*/ -static void -_unix_sync_file(u3_unix* unx_u, u3_udir* par_u, u3_noun nam, u3_noun ext, u3_noun mim) -{ - c3_assert( par_u ); - c3_assert( c3y == par_u->dir ); - - // form file path - - c3_c* nam_c = _unix_knot_to_string(nam); - c3_c* ext_c = _unix_knot_to_string(ext); - c3_w par_w = strlen(par_u->pax_c); - c3_w nam_w = strlen(nam_c); - c3_w ext_w = strlen(ext_c); - c3_c* pax_c = c3_malloc(par_w + 1 + nam_w + 1 + ext_w + 1); - - strcpy(pax_c, par_u->pax_c); - pax_c[par_w] = '/'; - strcpy(pax_c + par_w + 1, nam_c); - pax_c[par_w + 1 + nam_w] = '.'; - strcpy(pax_c + par_w + 1 + nam_w + 1, ext_c); - pax_c[par_w + 1 + nam_w + 1 + ext_w] = '\0'; - - c3_free(nam_c); c3_free(ext_c); - u3z(nam); u3z(ext); - - // check whether we already know about this file - - u3_unod* nod_u; - for ( nod_u = par_u->kid_u; - ( nod_u && - ( c3y == nod_u->dir || - 0 != strcmp(nod_u->pax_c, pax_c) ) ); - nod_u = nod_u->nex_u ) - { } - - // apply change - - if ( u3_nul == mim ) { - if ( nod_u ) { - u3z(_unix_free_node(unx_u, nod_u)); - } - } - else { - - if ( !nod_u ) { - c3_w gum_w = _unix_write_file_hard(pax_c, u3k(u3t(mim))); - u3_ufil* fil_u = c3_malloc(sizeof(u3_ufil)); - _unix_watch_file(unx_u, fil_u, par_u, pax_c); - fil_u->gum_w = gum_w; - goto _unix_sync_file_out; - } - else { - _unix_write_file_soft((u3_ufil*) nod_u, u3k(u3t(mim))); - } - } - - c3_free(pax_c); - -_unix_sync_file_out: - u3z(mim); -} - -/* _unix_sync_change(): sync single change to unix -*/ -static void -_unix_sync_change(u3_unix* unx_u, u3_udir* dir_u, u3_noun pax, u3_noun mim) -{ - c3_assert( c3y == dir_u->dir ); - - if ( c3n == u3du(pax) ) { - if ( u3_nul == pax ) { - u3l_log("can't sync out file as top-level, strange"); - } - else { - u3l_log("sync out: bad path"); - } - u3z(pax); u3z(mim); - return; - } - else if ( c3n == u3du(u3t(pax)) ) { - u3l_log("can't sync out file as top-level, strangely"); - u3z(pax); u3z(mim); - } - else { - u3_noun i_pax = u3h(pax); - u3_noun t_pax = u3t(pax); - u3_noun it_pax = u3h(t_pax); - u3_noun tt_pax = u3t(t_pax); - - if ( u3_nul == tt_pax ) { - _unix_sync_file(unx_u, dir_u, u3k(i_pax), u3k(it_pax), mim); - } - else { - c3_c* nam_c = _unix_knot_to_string(i_pax); - c3_w pax_w = strlen(dir_u->pax_c); - u3_unod* nod_u; - - for ( nod_u = dir_u->kid_u; - ( nod_u && - ( c3n == nod_u->dir || - 0 != strcmp(nod_u->pax_c + pax_w + 1, nam_c) ) ); - nod_u = nod_u->nex_u ) - { } - - if ( !nod_u ) { - nod_u = c3_malloc(sizeof(u3_udir)); - _unix_create_dir((u3_udir*) nod_u, dir_u, u3k(i_pax)); - } - - if ( c3n == nod_u->dir ) { - u3l_log("weird, we got a file when we weren't expecting to"); - c3_assert(0); - } - - _unix_sync_change(unx_u, (u3_udir*) nod_u, u3k(t_pax), mim); - } - } - u3z(pax); -} - -/* _unix_sync_ergo(): sync list of changes to unix -*/ -static void -_unix_sync_ergo(u3_unix* unx_u, u3_umon* mon_u, u3_noun can) -{ - u3_noun nac = can; - u3_noun nam = _unix_string_to_knot(mon_u->nam_c); - - while ( u3_nul != nac) { - _unix_sync_change(unx_u, &mon_u->dir_u, - u3nc(u3k(nam), u3k(u3h(u3h(nac)))), - u3k(u3t(u3h(nac)))); - nac = u3t(nac); - } - - u3z(nam); - u3z(can); -} - -/* u3_unix_ef_dirk(): commit mount point -*/ -void -u3_unix_ef_dirk(u3_unix* unx_u, u3_noun mon) -{ - _unix_commit_mount_point(unx_u, mon); -} - -/* u3_unix_ef_ergo(): update filesystem from urbit -*/ -void -u3_unix_ef_ergo(u3_unix* unx_u, u3_noun mon, u3_noun can) -{ - u3_umon* mon_u = _unix_get_mount_point(unx_u, mon); - - _unix_sync_ergo(unx_u, mon_u, can); -} - -/* u3_unix_ef_ogre(): delete mount point -*/ -void -u3_unix_ef_ogre(u3_unix* unx_u, u3_noun mon) -{ - _unix_delete_mount_point(unx_u, mon); -} - -/* u3_unix_ef_hill(): enumerate mount points -*/ -void -u3_unix_ef_hill(u3_unix* unx_u, u3_noun hil) -{ - u3_noun mon; - - for ( mon = hil; c3y == u3du(mon); mon = u3t(mon) ) { - u3_umon* mon_u = _unix_get_mount_point(unx_u, u3k(u3h(mon))); - _unix_scan_mount_point(unx_u, mon_u); - } - - unx_u->car_u.liv_o = c3y; - - u3z(hil); -} - -/* u3_unix_ef_look(): update the root of a specific mount point. -*/ -void -u3_unix_ef_look(u3_unix* unx_u, u3_noun mon, u3_noun all) -{ - if ( c3y == unx_u->dyr ) { - c3_c* nam_c = _unix_knot_to_string(mon); - - unx_u->dyr = c3n; - u3_umon* mon_u = unx_u->mon_u; - while ( mon_u && 0 != strcmp(nam_c, mon_u->nam_c) ) { - mon_u = mon_u->nex_u; - } - c3_free(nam_c); - if ( mon_u ) { - _unix_update_mount(unx_u, mon_u, all); - } - } - u3z(mon); -} - -/* _unix_io_talk(): start listening for fs events. -*/ -static void -_unix_io_talk(u3_auto* car_u) -{ - // XX review wire - // - u3_noun wir = u3nc(c3__boat, u3_nul); - u3_noun cad = u3nc(c3__boat, u3_nul); - - u3_auto_plan(car_u, u3_ovum_init(0, c3__c, wir, cad)); -} - -/* _unix_io_kick(): apply effects. -*/ -static c3_o -_unix_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) -{ - u3_unix* unx_u = (u3_unix*)car_u; - - u3_noun tag, dat, i_wir; - c3_o ret_o; - - if ( (c3n == u3r_cell(wir, &i_wir, 0)) - || (c3n == u3r_cell(cad, &tag, &dat)) - || ( (c3__clay != i_wir) - && (c3__boat != i_wir) - && (c3__sync != i_wir) ) ) - { - ret_o = c3n; - } - else { - switch ( tag ) { - default: { - ret_o = c3n; - } break; - - case c3__dirk: { - u3_unix_ef_dirk(unx_u, u3k(dat)); - ret_o = c3y; - } break; - - case c3__ergo: { - u3_noun mon = u3k(u3h(dat)); - u3_noun can = u3k(u3t(dat)); - u3_unix_ef_ergo(unx_u, mon, can); - - ret_o = c3y; - } break; - - case c3__ogre: { - u3_unix_ef_ogre(unx_u, u3k(dat)); - ret_o = c3y; - } break; - - case c3__hill: { - u3_unix_ef_hill(unx_u, u3k(dat)); - ret_o = c3y; - } break; - } - } - - u3z(wir); u3z(cad); - return ret_o; -} - -/* _unix_io_exit(): terminate unix I/O. -*/ -static void -_unix_io_exit(u3_auto* car_u) -{ - u3_unix* unx_u = (u3_unix*)car_u; - - u3z(unx_u->sat); - c3_free(unx_u->pax_c); - c3_free(unx_u); -} - -/* u3_unix_io_init(): initialize unix sync. -*/ -u3_auto* -u3_unix_io_init(u3_pier* pir_u) -{ - u3_unix* unx_u = c3_calloc(sizeof(*unx_u)); - unx_u->mon_u = 0; - unx_u->pax_c = strdup(pir_u->pax_c); - unx_u->alm = c3n; - unx_u->dyr = c3n; - unx_u->sat = u3do("sane", c3__ta); - - u3_auto* car_u = &unx_u->car_u; - car_u->nam_m = c3__unix; - car_u->liv_o = c3n; - car_u->io.talk_f = _unix_io_talk; - car_u->io.kick_f = _unix_io_kick; - car_u->io.exit_f = _unix_io_exit; - // XX wat do - // - // car_u->ev.bail_f = ...l; - - { - u3_noun now; - struct timeval tim_u; - gettimeofday(&tim_u, 0); - - now = u3_time_in_tv(&tim_u); - unx_u->sev_l = u3r_mug(now); - u3z(now); - } - - return car_u; -} diff --git a/pkg/urbit/vere/ivory.c b/pkg/urbit/vere/ivory.c deleted file mode 100644 index 370f8c4ab..000000000 --- a/pkg/urbit/vere/ivory.c +++ /dev/null @@ -1,3 +0,0 @@ -#include "vere/ivory.h" - -#include "ivory_impl.h" diff --git a/pkg/urbit/vere/king.c b/pkg/urbit/vere/king.c deleted file mode 100644 index 64896a697..000000000 --- a/pkg/urbit/vere/king.c +++ /dev/null @@ -1,1658 +0,0 @@ -/* vere/daemon.c -** -** the main loop of the daemon process -*/ -#include "all.h" -#include "ur/ur.h" -#include "vere/ivory.h" -#include "vere/vere.h" -#include -#include - -static const c3_c* ver_hos_c = "https://bootstrap.urbit.org/vere"; - -// stash config flags for worker -// -static c3_w sag_w; - -/* -:: skeleton client->king protocol -:: -|% -:: +doom: daemon command -:: -:: Should require auth to the daemon itself -:: -+$ doom - $% :: boot - :: - :: p: boot procedure - :: q: pill specifier - :: r: path to pier - :: - [%boot p=boot q=pill r=@t] - :: end the daemon - :: - :: XX not implemented - :: - [%exit ~] - :: acquire a pier - :: - :: XX used for restart, may not be right - :: - [%pier p=(unit @t)] - :: admin ship actions - :: - :: XX not implemented - :: - [%root p=ship q=wyrd] - == -:: +boot: boot procedures -:: -+$ boot - $% :: mine a comet - :: - :: p: optionally under a specific star - :: - [%come p=(unit ship)] - :: boot with real keys - :: - :: And perform pre-boot validation, retrieve snapshot, etc. - :: - [%dawn p=seed] - :: boot with fake keys - :: - :: p: identity - :: - [%fake p=ship] - == -:: +pill: boot-sequence ingredients -:: -:: p: jammed pill -:: q: optional %into ovum overriding that of .p -:: -+$ pill [p=@ q=(unit ovum)] --- -*/ - -void _king_doom(u3_noun doom); - void _king_boot(u3_noun boot); - void _king_come(u3_noun star, u3_noun pill, u3_noun path); - void _king_dawn(u3_noun seed, u3_noun pill, u3_noun path); - void _king_fake(u3_noun ship, u3_noun pill, u3_noun path); - void _king_pier(u3_noun pier); - -/* _king_defy_fate(): invalid fate -*/ -void -_king_defy_fate() -{ - exit(1); -} - -/* _king_doom(): doom parser -*/ -void -_king_doom(u3_noun doom) -{ - u3_noun load; - void (*next)(u3_noun); - - c3_assert(_(u3a_is_cell(doom))); - c3_assert(_(u3a_is_cat(u3h(doom)))); - - switch ( u3h(doom) ) { - case c3__boot: - next = _king_boot; - break; - case c3__pier: - next = _king_pier; - break; - default: - _king_defy_fate(); - } - - load = u3k(u3t(doom)); - u3z(doom); - next(load); -} - -/* _king_boot(): boot parser -*/ -void -_king_boot(u3_noun bul) -{ - u3_noun boot, pill, path; - void (*next)(u3_noun, u3_noun, u3_noun); - - c3_assert(_(u3a_is_cell(bul))); - u3x_trel(bul, &boot, &pill, &path); - c3_assert(_(u3a_is_cat(u3h(boot)))); - - switch ( u3h(boot) ) { - case c3__fake: { - next = _king_fake; - break; - } - case c3__come: { - next = _king_come; - break; - } - case c3__dawn: { - next = _king_dawn; - break; - } - default: - return _king_defy_fate(); - } - - next(u3k(u3t(boot)), u3k(pill), u3k(path)); - u3z(bul); -} - -/* _king_fake(): boot with fake keys -*/ -void -_king_fake(u3_noun ship, u3_noun pill, u3_noun path) -{ - // XX link properly - // - u3_noun vent = u3nc(c3__fake, u3k(ship)); - u3K.pir_u = u3_pier_boot(sag_w, ship, vent, pill, path, u3_none); -} - -/* _king_come(): mine a comet under star (unit) -** -** XX revise to exclude star argument -*/ -void -_king_come(u3_noun star, u3_noun pill, u3_noun path) -{ - _king_dawn(u3_dawn_come(), pill, path); -} - -static void -_king_slog(u3_noun hod) -{ - u3_pier_tank(0, 0, u3k(u3t(hod))); - u3z(hod); -} - -/* _king_dawn(): boot from keys, validating -*/ -void -_king_dawn(u3_noun feed, u3_noun pill, u3_noun path) -{ - // enable ivory slog printfs - // - u3C.slog_f = _king_slog; - - u3_noun ship = ( c3y == u3a_is_cell(u3h(feed)) ) - ? u3h(u3t(feed)) - : u3h(feed); - u3_noun vent = u3_dawn_vent(u3k(ship), u3k(feed)); - // XX link properly - // - u3K.pir_u = u3_pier_boot(sag_w, u3k(ship), vent, pill, path, feed); - - // disable ivory slog printfs - // - u3C.slog_f = 0; -} - -/* _king_pier(): pier parser -*/ -void -_king_pier(u3_noun pier) -{ - if ( (c3n == u3du(pier)) || - (c3n == u3ud(u3t(pier))) ) { - u3m_p("daemon: invalid pier", pier); - exit(1); - } - - u3K.pir_u = u3_pier_stay(sag_w, u3k(u3t(pier))); - u3z(pier); -} - -/* _king_curl_alloc(): allocate a response buffer for curl -** XX deduplicate with dawn.c -*/ -static size_t -_king_curl_alloc(void* dat_v, size_t uni_t, size_t mem_t, void* buf_v) -{ - uv_buf_t* buf_u = buf_v; - - size_t siz_t = uni_t * mem_t; - buf_u->base = c3_realloc(buf_u->base, 1 + siz_t + buf_u->len); - - memcpy(buf_u->base + buf_u->len, dat_v, siz_t); - buf_u->len += siz_t; - buf_u->base[buf_u->len] = 0; - - return siz_t; -} - -/* _king_curl_bytes(): HTTP GET url_c, produce response body bytes. -** XX deduplicate with dawn.c -*/ -static c3_i -_king_curl_bytes(c3_c* url_c, c3_w* len_w, c3_y** hun_y, c3_t veb_t) -{ - c3_i ret_i = 0; - CURL *cul_u; - CURLcode res_i; - long cod_i; - uv_buf_t buf_u = uv_buf_init(c3_malloc(1), 0); - - if ( !(cul_u = curl_easy_init()) ) { - u3l_log("failed to initialize libcurl"); - exit(1); - } - - u3K.ssl_curl_f(cul_u); - curl_easy_setopt(cul_u, CURLOPT_URL, url_c); - curl_easy_setopt(cul_u, CURLOPT_WRITEFUNCTION, _king_curl_alloc); - curl_easy_setopt(cul_u, CURLOPT_WRITEDATA, (void*)&buf_u); - - res_i = curl_easy_perform(cul_u); - curl_easy_getinfo(cul_u, CURLINFO_RESPONSE_CODE, &cod_i); - - // XX retry? - // - if ( CURLE_OK != res_i ) { - if ( veb_t ) { - u3l_log("curl: failed %s: %s", url_c, curl_easy_strerror(res_i)); - } - ret_i = -1; - } - if ( 300 <= cod_i ) { - if ( veb_t ) { - u3l_log("curl: error %s: HTTP %ld", url_c, cod_i); - } - ret_i = -2; - } - - curl_easy_cleanup(cul_u); - - *len_w = buf_u.len; - *hun_y = (c3_y*)buf_u.base; - - return ret_i; -} - -/* _king_get_atom(): HTTP GET url_c, produce response body as atom. -*/ -static u3_noun -_king_get_atom(c3_c* url_c) -{ - c3_w len_w; - c3_y* hun_y; - u3_noun pro; - - if ( _king_curl_bytes(url_c, &len_w, &hun_y, 1) ) { - u3_king_bail(); - exit(1); - } - - pro = u3i_bytes(len_w, hun_y); - c3_free(hun_y); - return pro; -} - -/* _king_get_pace(): get "pace" (release channel name). -*/ -static c3_c* -_king_get_pace(void) -{ - struct stat buf_u; - c3_c* pat_c; - c3_w red_w, len_w; - c3_i ret_i, fid_i; - - ret_i = asprintf(&pat_c, "%s/.bin/pace", u3_Host.dir_c); - c3_assert( ret_i > 0 ); - - fid_i = c3_open(pat_c, O_RDONLY, 0644); - - if ( (fid_i < 0) || (fstat(fid_i, &buf_u) < 0) ) { - c3_free(pat_c); - return strdup("live"); - } - - c3_free(pat_c); - - len_w = buf_u.st_size; - pat_c = c3_malloc(len_w + 1); - red_w = read(fid_i, pat_c, len_w); - close(fid_i); - - if ( len_w != red_w ) { - c3_free(pat_c); - u3l_log("unable to read pace file, " - "falling back to default (\"live\")\n"); - return strdup("live"); - } - - pat_c[len_w] = 0; - - while ( len_w-- && isspace(pat_c[len_w]) ) { - pat_c[len_w] = 0; - } - - return pat_c; -} - -/* u3_king_next(): get next vere version string, if it exists. -** return: 0 is success, -1 is no-op (same version), -2 is error -*/ -c3_i -u3_king_next(c3_c* pac_c, c3_c** out_c) -{ - c3_c* ver_c; - c3_c* url_c; - c3_w len_w; - c3_y* hun_y; - c3_i ret_i; - - ret_i = asprintf(&url_c, "%s/%s/%s/next", ver_hos_c, pac_c, URBIT_VERSION); - c3_assert( ret_i > 0 ); - - // skip printfs on failed requests (/next is usually not present) - // - if ( _king_curl_bytes(url_c, &len_w, &hun_y, 0) ) { - c3_free(url_c); - - ret_i = asprintf(&url_c, "%s/%s/last", ver_hos_c, pac_c); - c3_assert( ret_i > 0 ); - - // enable printfs on failed requests (/last must be present) - // XX support channel redirections - // - if ( _king_curl_bytes(url_c, &len_w, &hun_y, 1) ) - { - c3_free(url_c); - return -2; - } - } - - c3_free(url_c); - - // null-terminate - // - hun_y = c3_realloc(hun_y, 1 + len_w); - hun_y[len_w] = 0; - - ver_c = (c3_c*)hun_y; - - // XX trim ver_c ? - // - if ( 0 == strcmp(ver_c, URBIT_VERSION) ) { - c3_free(ver_c); - return -1; - } - - *out_c = ver_c; - return 0; -} - -/* _get_cmd_output(): Run a shell command and capture its output. - Exits with an error if the command fails or produces no output. - The 'out_c' parameter should be an array of sufficient length to hold - the command's output, up to a max of len_c characters. -*/ -static void -_get_cmd_output(c3_c *cmd_c, c3_c *out_c, c3_w len_c) -{ - FILE *fp = popen(cmd_c, "r"); - if ( NULL == fp ) { - u3l_log("'%s' failed", cmd_c); - exit(1); - } - - if ( NULL == fgets(out_c, len_c, fp) ) { - u3l_log("'%s' produced no output", cmd_c); - exit(1); - } - - pclose(fp); -} - -/* _arvo_hash(): get a shortened hash of the last git commit - that modified the sys/ directory in arvo. - hax_c must be an array with length >= 11. -*/ -static void -_arvo_hash(c3_c *out_c, c3_c *arv_c) -{ - c3_c cmd_c[2048]; - - sprintf(cmd_c, "git -C %s log -1 HEAD --format=%%H -- sys/", arv_c); - _get_cmd_output(cmd_c, out_c, 11); - - out_c[10] = 0; // end with null-byte -} - -/* _git_pill_url(): produce a URL from which to download a pill - based on the location of an arvo git repository. -*/ -static void -_git_pill_url(c3_c *out_c, c3_c *arv_c) -{ - c3_c hax_c[11]; - - assert(NULL != arv_c); - - if ( 0 != system("which git >> /dev/null") ) { - u3l_log("boot: could not find git executable"); - exit(1); - } - - _arvo_hash(hax_c, arv_c); - sprintf(out_c, "https://bootstrap.urbit.org/git-%s.pill", hax_c); -} - -/* _boothack_pill(): parse CLI pill arguments into +pill specifier -*/ -static u3_noun -_boothack_pill(void) -{ - u3_noun arv = u3_nul; - u3_noun pil; - - if ( 0 != u3_Host.ops_u.pil_c ) { - u3l_log("boot: loading pill %s", u3_Host.ops_u.pil_c); - pil = u3m_file(u3_Host.ops_u.pil_c); - } - else { - c3_c url_c[2048]; - - if ( (c3y == u3_Host.ops_u.git) && - (0 != u3_Host.ops_u.arv_c) ) - { - _git_pill_url(url_c, u3_Host.ops_u.arv_c); - } - else { - c3_assert( 0 != u3_Host.ops_u.url_c ); - strcpy(url_c, u3_Host.ops_u.url_c); - } - - u3l_log("boot: downloading pill %s", url_c); - pil = _king_get_atom(url_c); - } - - if ( 0 != u3_Host.ops_u.arv_c ) { - u3l_log("boot: preparing filesystem from %s", - u3_Host.ops_u.arv_c); - arv = u3nc(u3_nul, u3_unix_initial_into_card(u3_Host.ops_u.arv_c)); - } - - return u3nc(pil, arv); -} - -/* _boothack_key(): parse a private key file or value -*/ -static u3_noun -_boothack_key(u3_noun kef) -{ - u3_noun seed; - u3_weak ship = u3_none; - - { - u3_noun des = u3dc("slaw", c3__uw, u3k(kef)); - - if ( u3_nul == des ) { - c3_c* kef_c = u3r_string(kef); - u3l_log("dawn: invalid private keys: %s", kef_c); - c3_free(kef_c); - exit(1); - } - - // +feed:able:jael: keyfile - // - u3_noun pro = u3m_soft(0, u3ke_cue, u3k(u3t(des))); - if ( u3_blip != u3h(pro) ) { - u3l_log("dawn: unable to cue keyfile"); - exit(1); - } - seed = u3k(u3t(pro)); - u3z(pro); - - // if it's a single seed, we can trivially sanity-check early - // - if ( c3y == u3ud(u3h(seed)) ) { - // local reference, not counted - // - ship = u3h(seed); - } - - u3z(des); - u3z(kef); - } - - if ( 0 != u3_Host.ops_u.who_c ) { - u3_noun woh = u3i_string(u3_Host.ops_u.who_c); - u3_noun whu = u3dc("slaw", 'p', u3k(woh)); - - if ( u3_nul == whu ) { - u3l_log("dawn: invalid ship specified with -w %s", - u3_Host.ops_u.who_c); - exit(1); - } - - if ( (u3_none != ship) && - (c3n == u3r_sing(ship, u3t(whu))) ) - { - u3_noun how = u3dc("scot", 'p', u3k(ship)); - c3_c* how_c = u3r_string(u3k(how)); - u3l_log("dawn: mismatch between -w %s and -K %s", - u3_Host.ops_u.who_c, how_c); - - u3z(how); - c3_free(how_c); - exit(1); - } - - u3z(woh); - u3z(whu); - } - - return seed; -} - -/* _boothack_doom(): parse CLI arguments into $doom -*/ -static u3_noun -_boothack_doom(void) -{ - u3_noun pax = u3i_string(u3_Host.dir_c); - u3_noun bot; - - if ( c3n == u3_Host.ops_u.nuu ) { - return u3nt(c3__pier, u3_nul, pax); - } - else if ( 0 != u3_Host.ops_u.fak_c ) { - u3_noun fak = u3i_string(u3_Host.ops_u.fak_c); - u3_noun whu = u3dc("slaw", 'p', u3k(fak)); - - if ( u3_nul == whu ) { - u3l_log("boot: malformed -F ship %s", u3_Host.ops_u.fak_c); - u3_king_bail(); - } - - bot = u3nc(c3__fake, u3k(u3t(whu))); - - u3z(whu); - u3z(fak); - } - else if ( 0 != u3_Host.ops_u.who_c ) { - u3_noun kef; - - if ( 0 != u3_Host.ops_u.key_c ) { - kef = u3m_file(u3_Host.ops_u.key_c); - - // handle trailing newline - // - { - c3_c* key_c = u3r_string(kef); - c3_w len_w = strlen(key_c); - - if (len_w && (key_c[len_w - 1] == '\n')) { - key_c[len_w - 1] = '\0'; - u3z(kef); - kef = u3i_string(key_c); - } - - c3_free(key_c); - } - } - else if ( 0 != u3_Host.ops_u.gen_c ) { - kef = u3i_string(u3_Host.ops_u.gen_c); - } - else { - u3l_log("boot: must specify a key with -k or -G"); - exit(1); - } - - bot = u3nc(c3__dawn, _boothack_key(kef)); - } - else { - // XX allow parent star to be specified? - // - bot = u3nc(c3__come, u3_nul); - } - - return u3nq(c3__boot, bot, _boothack_pill(), pax); -} - -/* _king_sign_init(): initialize daemon signal handlers -*/ -static void -_king_sign_init(void) -{ - // gracefully shutdown on SIGTERM - // - { - u3_usig* sig_u; - - sig_u = c3_malloc(sizeof(u3_usig)); - uv_signal_init(u3L, &sig_u->sil_u); - - sig_u->num_i = SIGTERM; - sig_u->nex_u = u3_Host.sig_u; - u3_Host.sig_u = sig_u; - } - - // forward SIGINT to worker - // - { - u3_usig* sig_u; - - sig_u = c3_malloc(sizeof(u3_usig)); - uv_signal_init(u3L, &sig_u->sil_u); - - sig_u->num_i = SIGINT; - sig_u->nex_u = u3_Host.sig_u; - u3_Host.sig_u = sig_u; - } - - // inject new dimensions after terminal resize - // - { - u3_usig* sig_u; - - sig_u = c3_malloc(sizeof(u3_usig)); - uv_signal_init(u3L, &sig_u->sil_u); - - sig_u->num_i = SIGWINCH; - sig_u->nex_u = u3_Host.sig_u; - u3_Host.sig_u = sig_u; - } - - // handle SIGINFO (if available) - // -#ifdef SIGINFO - { - u3_usig* sig_u; - - sig_u = c3_malloc(sizeof(u3_usig)); - uv_signal_init(u3L, &sig_u->sil_u); - - sig_u->num_i = SIGINFO; - sig_u->nex_u = u3_Host.sig_u; - u3_Host.sig_u = sig_u; - } -#endif - - // handle SIGUSR1 (fallback for SIGINFO) - // - { - u3_usig* sig_u; - - sig_u = c3_malloc(sizeof(u3_usig)); - uv_signal_init(u3L, &sig_u->sil_u); - - sig_u->num_i = SIGUSR1; - sig_u->nex_u = u3_Host.sig_u; - u3_Host.sig_u = sig_u; - } -} - -/* _king_sign_cb: signal callback. -*/ -static void -_king_sign_cb(uv_signal_t* sil_u, c3_i num_i) -{ - switch ( num_i ) { - default: { - u3l_log("\r\nmysterious signal %d", num_i); - break; - } - - case SIGTERM: { - u3_king_exit(); - break; - } - - case SIGINT: { - u3l_log("\r\ninterrupt"); - u3_term_ef_ctlc(); - -#ifdef U3_OS_mingw - PulseEvent(u3_Host.cev_u); -#endif - break; - } - - case SIGWINCH: { - u3_term_ef_winc(); - break; - } - - // fallthru if defined - // -#ifdef SIGINFO - case SIGINFO: -#endif - case SIGUSR1: { - u3_king_slog(); - break; - } - } -} - -/* _king_sign_move(): enable daemon signal handlers -*/ -static void -_king_sign_move(void) -{ - u3_usig* sig_u; - - for ( sig_u = u3_Host.sig_u; sig_u; sig_u = sig_u->nex_u ) { - uv_signal_start(&sig_u->sil_u, _king_sign_cb, sig_u->num_i); - } -} - -/* _king_sign_hold(): disable daemon signal handlers -*/ -static void -_king_sign_hold(void) -{ - u3_usig* sig_u; - - for ( sig_u = u3_Host.sig_u; sig_u; sig_u = sig_u->nex_u ) { - uv_signal_stop(&sig_u->sil_u); - } -} - -/* _king_sign_close(): dispose daemon signal handlers -*/ -static void -_king_sign_close(void) -{ - u3_usig* sig_u; - - for ( sig_u = u3_Host.sig_u; sig_u; sig_u = sig_u->nex_u ) { - uv_close((uv_handle_t*)&sig_u->sil_u, (uv_close_cb)free); - } -} -/* _boothack_cb(): setup pier via message as if from client. -*/ -void -_boothack_cb(uv_timer_t* tim_u) -{ - _king_doom(_boothack_doom()); -} - -/* _king_loop_init(): stuff that comes before the event loop -*/ -void -_king_loop_init() -{ - // initialize terminal/logging - // - u3_term_log_init(); - - // start signal handlers - // - _king_sign_init(); - _king_sign_move(); - - // async "boothack" - // / - uv_timer_start(&u3K.tim_u, _boothack_cb, 0, 0); -} - -/* _king_loop_exit(): cleanup after event loop -*/ -void -_king_loop_exit() -{ -} - -static void -_king_boot_ivory(void) -{ - c3_d len_d; - c3_y* byt_y; - - if ( u3_Host.ops_u.lit_c ) { - if ( c3n == u3u_mmap_read("lite", u3_Host.ops_u.lit_c, &len_d, &byt_y) ) { - u3l_log("lite: unable to load ivory pill at %s", - u3_Host.ops_u.lit_c); - exit(1); - } - } - else { - len_d = u3_Ivory_pill_len; - byt_y = u3_Ivory_pill; - } - - { - u3_cue_xeno* sil_u = u3s_cue_xeno_init_with(ur_fib27, ur_fib28); - u3_weak pil; - - if ( u3_none == (pil = u3s_cue_xeno_with(sil_u, len_d, byt_y)) ) { - u3l_log("lite: unable to cue ivory pill"); - exit(1); - } - - u3s_cue_xeno_done(sil_u); - - if ( c3n == u3v_boot_lite(pil)) { - u3l_log("lite: boot failed"); - exit(1); - } - } - - if ( u3_Host.ops_u.lit_c ) { - if ( c3n == u3u_munmap(len_d, byt_y) ) { - u3l_log("lite: unable to unmap ivory pill at %s", - u3_Host.ops_u.lit_c); - exit(1); - } - } -} - -/* u3_king_commence(): start the daemon -*/ -void -u3_king_commence() -{ - u3_Host.lup_u = uv_default_loop(); - - // initialize top-level timer - // - uv_timer_init(u3L, &u3K.tim_u); - - // start up a "fast-compile" arvo for internal use only - // (with hashboard and sample-profiling always disabled) - // - sag_w = u3C.wag_w; - u3C.wag_w |= u3o_hashless; - u3C.wag_w &= ~u3o_debug_cpu; - - // wire up signal controls - // - u3C.sign_hold_f = _king_sign_hold; - u3C.sign_move_f = _king_sign_move; - - // Ignore SIGPIPE signals. - #ifndef U3_OS_mingw - { - struct sigaction sig_s = {{0}}; - sigemptyset(&(sig_s.sa_mask)); - sig_s.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &sig_s, 0); - } - #endif - - // boot the ivory pill - // - _king_boot_ivory(); - - // disable core dumps (due to lmdb size) - // - #ifndef U3_OS_mingw - { - struct rlimit rlm; - - getrlimit(RLIMIT_CORE, &rlm); - rlm.rlim_cur = 0; - - if ( 0 != setrlimit(RLIMIT_CORE, &rlm) ) { - u3l_log("king: unable to disable core dumps: %s", strerror(errno)); - exit(1); - } - } - #endif - - // run the loop - // - _king_loop_init(); - uv_run(u3L, UV_RUN_DEFAULT); - _king_loop_exit(); - u3m_stop(); -} - -/* u3_king_stub(): get the One Pier for unreconstructed code. -*/ -u3_pier* -u3_king_stub(void) -{ - if ( !u3K.pir_u ) { - c3_assert(!"king: no pier"); - } - else { - return u3K.pir_u; - } -} - -/* _king_forall(): run on all piers -*/ -static void -_king_forall(void (*pir_f)(u3_pier*)) -{ - u3_pier* pir_u = u3K.pir_u; - - while ( pir_u ) { - pir_f(pir_u); - pir_u = pir_u->nex_u; - } -} - -/* u3_king_slog(): print status info. -*/ -void -u3_king_slog(void) -{ - _king_forall(u3_pier_slog); -} - -/* _king_forall_unlink(): run on all piers, unlinking from king. -*/ -static void -_king_forall_unlink(void (*pir_f)(u3_pier*)) -{ - u3_pier* pir_u = u3K.pir_u; - - while ( u3K.pir_u ) { - u3_pier* pir_u = u3K.pir_u; - u3K.pir_u = pir_u->nex_u; - pir_f(pir_u); - } -} - -/* _king_curl_file(): HTTP GET [url_c], write response body to [fil_u]. -*/ -static c3_i -_king_save_file(c3_c* url_c, FILE* fil_u) -{ - c3_i ret_i = 0; - CURL *cul_u; - CURLcode res_i; - long cod_i; - - if ( !(cul_u = curl_easy_init()) ) { - u3l_log("failed to initialize libcurl"); - exit(1); - } - - u3K.ssl_curl_f(cul_u); - curl_easy_setopt(cul_u, CURLOPT_URL, url_c); - curl_easy_setopt(cul_u, CURLOPT_WRITEDATA, (void*)fil_u); - - res_i = curl_easy_perform(cul_u); - curl_easy_getinfo(cul_u, CURLINFO_RESPONSE_CODE, &cod_i); - - // XX retry? - // - if ( CURLE_OK != res_i ) { - u3l_log("curl: failed %s: %s", url_c, curl_easy_strerror(res_i)); - ret_i = -1; - } - if ( 300 <= cod_i ) { - u3l_log("curl: error %s: HTTP %ld", url_c, cod_i); - ret_i = -2; - } - - curl_easy_cleanup(cul_u); - return ret_i; -} - -/* _king_make_pace(): mkdir -p $pier/.bin/[pace] -*/ -static c3_i -_king_make_pace(c3_c* pac_c) -{ - c3_c* bin_c; - c3_i ret_i; - - ret_i = asprintf(&bin_c, "%s/.bin", u3_Host.dir_c); - c3_assert( ret_i > 0 ); - - ret_i = c3_mkdir(bin_c, 0700); - - if ( ret_i && (EEXIST != errno) ) { - fprintf(stderr, "vere: mkdir %s failed: %s\n", bin_c, strerror(errno)); - c3_free(bin_c); - return -1; - } - - c3_free(bin_c); - - ret_i = asprintf(&bin_c, "%s/.bin/%s/", u3_Host.dir_c, pac_c); - c3_assert( ret_i > 0 ); - - // XX asserting wrapper conflicts here (and is bypassed for .urb) - // - ret_i = mkdir(bin_c, 0700); - - if ( ret_i && (EEXIST != errno) ) { - fprintf(stderr, "vere: mkdir %s failed: %s\n", bin_c, strerror(errno)); - c3_free(bin_c); - return -1; - } - - c3_free(bin_c); - return 0; -} - -static c3_i -_king_write_raw(c3_i fid_i, c3_y* buf_y, size_t len_i); - -/* _king_init_pace(): save pace file if not present -*/ -static c3_i -_king_init_pace(c3_c* pac_c) -{ - c3_c* bin_c; - c3_i fid_i, ret_i = asprintf(&bin_c, "%s/.bin/pace", u3_Host.dir_c); - c3_assert( ret_i > 0 ); - - if ( (-1 == (fid_i = open(bin_c, O_WRONLY | O_CREAT | O_EXCL, 0644))) ) { - if ( EEXIST == errno ) { - c3_free(bin_c); - // XX print something here? - // - return 0; - } - else { - u3l_log("dock: init pace (%s): open %s", pac_c, strerror(errno)); - c3_free(bin_c); - return -1; - } - } - - if ( _king_write_raw(fid_i, (c3_y*)pac_c, strlen(pac_c)) ) { - u3l_log("dock: init pace (%s): write %s", pac_c, strerror(errno)); - close(fid_i); - c3_free(bin_c); - return -1; - } - // XX sync first? - // - else if ( close(fid_i) ) { - u3l_log("dock: init pace (%s): close %s", pac_c, strerror(errno)); - c3_free(bin_c); - return 1; - } - - u3l_log("dock: pace (%s): configured at %s/.bin/pace", - pac_c, u3_Host.dir_c); - - return 0; -} - -/* _king_link_run(): ln [bin_c] $pier/.run -*/ -static c3_i -_king_link_run(c3_c* bin_c) -{ - c3_c* lin_c; - c3_i ret_i; - - ret_i = asprintf(&lin_c, "%s/%s", u3_Host.dir_c, U3_BIN_ALIAS); - c3_assert( ret_i > 0 ); - - ret_i = unlink(lin_c); - - if ( ret_i && (ENOENT != errno) ) { - fprintf(stderr, "vere: unlink %s failed: %s\n", lin_c, strerror(errno)); - c3_free(lin_c); - return -1; - } - - ret_i = link(bin_c, lin_c); - - if ( ret_i ) { - fprintf(stderr, "vere: link %s -> %s failed: %s\n", - lin_c, bin_c, strerror(errno)); - c3_free(lin_c); - return -1; - } - - c3_free(lin_c); - return 0; -} - -/* u3_king_vere(): download binary as specified. -*/ -c3_i -u3_king_vere(c3_c* pac_c, // pace - c3_c* ver_c, // version - c3_c* arc_c, // architecture - c3_c* dir_c, // output directory - c3_t lin_t) // link to $pier/.run -{ - c3_c* bin_c; - c3_c* url_c; - FILE* fil_u; - c3_i fid_i, ret_i; - - ret_i = asprintf(&bin_c, "%s/vere-v%s-%s" U3_BIN_SUFFIX, - dir_c, ver_c, arc_c); - c3_assert( ret_i > 0 ); - - if ( (-1 == (fid_i = open(bin_c, O_WRONLY | O_CREAT | O_EXCL, 0755))) - || !(fil_u = fdopen(fid_i, "wb")) ) - { - if ( EEXIST == errno ) { - u3l_log("already installed"); - c3_free(bin_c); - return 0; - } - else { - u3l_log("unable to open %s: %s", bin_c, strerror(errno)); - c3_free(bin_c); - return -1; - } - } - - ret_i = asprintf(&url_c, "%s/%s/%s/vere-v%s-%s", - ver_hos_c, pac_c, ver_c, ver_c, arc_c); - c3_assert( ret_i > 0 ); - - if ( (ret_i = _king_save_file(url_c, fil_u)) ) { - u3l_log("unable to save %s to %s: %d", url_c, bin_c, ret_i); - c3_free(url_c); - fclose(fil_u); - unlink(bin_c); - c3_free(bin_c); - return -1; // XX - } - - // XX sync unnecessary here? - // - if ( fflush(fil_u) || c3_sync(fid_i) ) { - fprintf(stderr, "vere: sync %s failed: %s\n", bin_c, strerror(errno)); - c3_free(url_c); - fclose(fil_u); - unlink(bin_c); - c3_free(bin_c); - return -1; - } - - fclose(fil_u); - - // XX if link fails wat do? - // XX set via cli option - // - if ( lin_t ) { - if ( _king_link_run(bin_c) ) { - fprintf(stderr, "vere: link %s/%s failed\n", u3_Host.dir_c, U3_BIN_ALIAS); - c3_free(url_c); - c3_free(bin_c); - return -1; - } - } - - u3l_log("vere: saved to %s", bin_c); - - c3_free(url_c); - c3_free(bin_c); - - return 0; -} - -/* _king_do_upgrade(): get arch-appropriate binary at [ver_c]. -*/ -static void -_king_do_upgrade(c3_c* pac_c, c3_c* ver_c) -{ - c3_c* dir_c; - c3_c* arc_c; - -#ifdef U3_OS_ARCH - arc_c = U3_OS_ARCH; -#else - if ( u3_Host.arc_c ) { - arc_c = u3_Host.arc_c; - } - else { - u3l_log("vere: --arch required"); - return; - } -#endif - - if ( _king_make_pace(pac_c) ) { - u3l_log("vere: unable to make pace (%s) directory in pier", pac_c); - u3_king_bail(); - exit(1); - } - - { - c3_i ret_i = asprintf(&dir_c, "%s/.bin/%s", u3_Host.dir_c, pac_c); - c3_assert( ret_i > 0 ); - } - - // XX get link option - // - if ( u3_king_vere(pac_c, ver_c, arc_c, dir_c, 1) ) { - u3l_log("vere: upgrade failed"); - u3_king_bail(); - exit(1); - } - - c3_free(dir_c); - u3l_log("vere: upgrade succeeded"); - // XX print restart instructions -} - -/* _king_read_raw: read (up to) [len_i] from [fid_i] to [buf_y] -*/ -static ssize_t -_king_read_raw(c3_i fid_i, c3_y* buf_y, size_t len_i) -{ - ssize_t ret_i; - - do { - ret_i = read(fid_i, buf_y, len_i); - } - while ( (ret_i < 0) && (errno == EINTR) ); - - return ret_i; -} - -/* _king_read_raw: write [len_i] from [buf_y] to [fid_i]. -*/ -static c3_i -_king_write_raw(c3_i fid_i, c3_y* buf_y, size_t len_i) -{ - ssize_t ret_i; - - while ( len_i ) { - - do { - ret_i = write(fid_i, buf_y, len_i); - } - while ( (ret_i < 0) && (errno == EINTR) ); - - if ( ret_i < 0 ) { - return -1; - } - else { - len_i -= ret_i; - buf_y += ret_i; - } - } - - return 0; -} - -static c3_i -_king_copy_raw(c3_i src_i, c3_i dst_i, c3_y* buf_y, size_t pag_i) -{ - ssize_t red_i; - - do { - if ( 0 > (red_i = _king_read_raw(src_i, buf_y, pag_i)) ) { - return -1; - } - - if ( _king_write_raw(dst_i, buf_y, (size_t)red_i) ) { - return -1; - } - } - while ( red_i ); - - return 0; -} - -#if defined(U3_OS_mingw) -int err_win_to_posix(DWORD winerr); -#endif - -static c3_i -_king_copy_file(c3_c* src_c, c3_c* dst_c) -{ -#if defined(U3_OS_mingw) - // XX try FSCTL_DUPLICATE_EXTENTS_TO_FILE - // - if ( CopyFileA(src_c, dst_c, TRUE) ) { - return 0; - } - - // XX fallback on any? - // - errno = err_win_to_posix(GetLastError()); - return -1; -#elif defined(U3_OS_osx) - if ( !clonefile(src_c, dst_c, 0) ) { - return 0; - } - // fallthru to copying bytes on some errors - // - else if ( (ENOTSUP != errno) && (EXDEV != errno) ) { - return -1; - } -#endif - - { - c3_i src_i, dst_i, ret_i = 0, err_i = 0; - - if ( -1 == (src_i = open(src_c, O_RDONLY, 0644)) ) { - err_i = errno; - ret_i = -1; - goto done1; - } - - if ( -1 == (dst_i = open(dst_c, O_RDWR | O_CREAT, 0755)) ) { - err_i = errno; - ret_i = -1; - goto done2; - } - - // XX try clone_file_range ? - // -#if defined(U3_OS_linux) - #if defined(FICLONE) - if ( !ioctl(dst_i, FICLONE, src_i) ) { - ret_i = 0; - goto done3; - } - // fallthru to copying bytes on some errors - // - else if ( (EOPNOTSUPP != errno) && (EXDEV != errno) ) { - err_i = errno; - ret_i = -1; - goto done3; - } - #endif - - { - off_t off_i = 0; - ssize_t sen_i; - size_t len_i; - { - struct stat sat_u; - if ( -1 == fstat(src_i, &sat_u) ) { - err_i = errno; - ret_i = -1; - goto done3; - } - len_i = sat_u.st_size; - } - - do { - // XX fallback on any errors? - // - if ( 0 > (sen_i = sendfile64(dst_i, src_i, &off_i, len_i)) ) { - err_i = errno; - ret_i = -1; - goto done3; - } - - len_i -= off_i; - } - while ( len_i ); - - ret_i = 0; - goto done3; - } -#elif defined(U3_OS_osx) - if ( !fcopyfile(src_i, dst_i, NULL, COPYFILE_ALL) ) { - ret_i = 0; - goto done3; - } - - // XX fallback on any errors? - // -#endif - - { - size_t pag_i = 1 << 14;; - c3_y* buf_y = c3_malloc(pag_i); - ret_i = _king_copy_raw(src_i, dst_i, buf_y, pag_i); - err_i = errno; - c3_free(buf_y); - } - -done3: - close(dst_i); -done2: - close(src_i); -done1: - errno = err_i; - return ret_i; - } -} - -/* _king_copy_vere(): copy current binary into $pier/.bin (COW if possible) -*/ -static c3_i -_king_copy_vere(c3_c* pac_c, c3_c* ver_c, c3_c* arc_c, c3_t lin_t) -{ - c3_c* bin_c; - c3_i ret_i; - - if ( _king_make_pace(pac_c) ) { - return -1; // XX - } - - ret_i = asprintf(&bin_c, "%s/.bin/%s/vere-v%s-%s" U3_BIN_SUFFIX, - u3_Host.dir_c, pac_c, ver_c, arc_c); - c3_assert( ret_i > 0 ); - - ret_i = _king_copy_file(u3_Host.dem_c, bin_c); - - if ( ret_i ) { - fprintf(stderr, "vere: copy %s -> %s failed: %s\r\n", - bin_c, u3_Host.dem_c, strerror(errno)); - c3_free(bin_c); - return -1; - } - - // XX option - // - if ( lin_t ) { - if ( _king_link_run(bin_c) ) { - fprintf(stderr, "vere: link %s/%s failed\n", u3_Host.dir_c, U3_BIN_ALIAS); - c3_free(bin_c); - return -1; - } - } - - c3_free(bin_c); - return 0; -} - -/* u3_king_dock(): copy binary into pier on boot. -*/ -void -u3_king_dock(c3_c* pac_c) -{ - c3_c* arc_c = "unknown"; - -#ifdef U3_OS_ARCH - arc_c = U3_OS_ARCH; -#endif - - // XX get link option - // - if ( _king_copy_vere(pac_c, URBIT_VERSION, arc_c, 1) ) { - u3l_log("vere: binary copy failed"); - u3_king_bail(); - exit(1); - } - else { - // NB: failure ignored - // - _king_init_pace(pac_c); - u3l_log("vere: binary copy succeeded"); - // XX print restart instructions - } -} - -/* _king_done_cb(): -*/ -static void -_king_done_cb(uv_handle_t* han_u) -{ - if( UV_EBUSY == uv_loop_close(u3L) ) { - // XX uncomment to debug - // - // fprintf(stderr, "\r\nking: open libuv handles\r\n"); - // uv_print_all_handles(u3L, stderr); - // fprintf(stderr, "\r\nking: force shutdown\r\n"); - - uv_stop(u3L); - } -} - -/* u3_king_done(): all piers closed. s/b callback -*/ -void -u3_king_done(void) -{ - uv_handle_t* han_u = (uv_handle_t*)&u3K.tim_u; - - if ( u3_Host.xit_i ) { - if ( c3y == u3_Host.nex_o ) { - u3l_log("vere: upgrade failed"); - } - else if ( c3y == u3_Host.pep_o ) { - u3l_log("vere: prep for upgrade failed"); - } - } - else { - // get next binary - // - if ( c3y == u3_Host.nex_o ) { - c3_c* pac_c; - c3_c* ver_c; - - // hack to ensure we only try once - // - u3_Host.nex_o = c3n; - - pac_c = _king_get_pace(); - - switch ( u3_king_next(pac_c, &ver_c) ) { - case -2: { - u3l_log("vere: unable to check for next version"); - } break; - - case -1: { - u3l_log("vere: up to date"); - } break; - - case 0: { - u3l_log("vere: next (%%%s): %s", pac_c, ver_c); - _king_do_upgrade(pac_c, ver_c); - c3_free(ver_c); - } break; - - default: c3_assert(0); - } - - c3_free(pac_c); - } - else if ( c3y == u3_Host.pep_o ) { - u3l_log("vere: ready for upgrade"); - } - - // copy binary into pier on boot - // - if ( (c3y == u3_Host.ops_u.nuu) - && (c3y == u3_Host.ops_u.doc) ) - { - // hack to ensure we only try once - // - u3_Host.ops_u.nuu = c3n; - u3_king_dock(U3_VERE_PACE); - } - } - - // XX hack, if pier's are still linked, we're not actually done - // - if ( !u3K.pir_u && !uv_is_closing(han_u) ) { - uv_close((uv_handle_t*)&u3K.tim_u, _king_done_cb); - _king_sign_close(); - - u3_term_log_exit(); - fflush(stdout); - } - - // XX remove move - // - exit(u3_Host.xit_i); -} - -/* u3_king_exit(): shutdown gracefully -*/ -void -u3_king_exit(void) -{ - _king_forall(u3_pier_exit); -} - -/* u3_king_bail(): immediately shutdown. -*/ -void -u3_king_bail(void) -{ - u3_Host.xit_i = 1; - _king_forall_unlink(u3_pier_bail); - _king_loop_exit(); - u3_king_done(); - exit(u3_Host.xit_i); -} - -/* u3_king_grab(): gc the daemon -*/ -void -u3_king_grab(void* vod_p) -{ - c3_w tot_w = 0; - FILE* fil_u; - - c3_assert( u3R == &(u3H->rod_u) ); - -#ifdef U3_MEMORY_LOG - { - // XX date will not match up with that of the worker - // - u3_noun wen = u3dc("scot", c3__da, u3k(u3A->now)); - c3_c* wen_c = u3r_string(wen); - - c3_c nam_c[2048]; - snprintf(nam_c, 2048, "%s/.urb/put/mass", u3_king_stub()->pax_c); - - struct stat st; - if ( -1 == stat(nam_c, &st) ) { - c3_mkdir(nam_c, 0700); - } - - c3_c man_c[2048]; - snprintf(man_c, 2048, "%s/%s-daemon.txt", nam_c, wen_c); - - fil_u = c3_fopen(man_c, "w"); - fprintf(fil_u, "%s\r\n", wen_c); - - c3_free(wen_c); - u3z(wen); - } -#else - { - fil_u = u3_term_io_hija(); - fprintf(fil_u, "measuring daemon:\r\n"); - } -#endif - - tot_w += u3m_mark(fil_u); - tot_w += u3_pier_mark(fil_u); - - u3a_print_memory(fil_u, "total marked", tot_w); - u3a_print_memory(fil_u, "sweep", u3a_sweep()); - -#ifdef U3_MEMORY_LOG - { - fclose(fil_u); - } -#else - { - u3_term_io_loja(0, fil_u); - } -#endif -} diff --git a/pkg/urbit/vere/lord.c b/pkg/urbit/vere/lord.c deleted file mode 100644 index b7b356e57..000000000 --- a/pkg/urbit/vere/lord.c +++ /dev/null @@ -1,1261 +0,0 @@ -/* vere/lord.c -*/ -#include "all.h" -#include "vere/vere.h" -#include "ur/hashcons.h" - -#undef LORD_TRACE_JAM -#undef LORD_TRACE_CUE - -/* -|% -:: +writ: from king to serf -:: -+$ writ - $% $: %live - $% [%cram eve=@] - [%exit cod=@] - [%save eve=@] - [%meld ~] - [%pack ~] - == == - [%peek mil=@ sam=*] :: gang (each path $%([%once @tas @tas path] [%beam @tas beam])) - [%play eve=@ lit=(list ?((pair @da ovum) *))] - [%work mil=@ job=(pair @da ovum)] - == -:: +plea: from serf to king -:: -+$ plea - $% [%live ~] - [%ripe [pro=%1 hon=@ nok=@] eve=@ mug=@] - [%slog pri=@ tank] - [%flog cord] - $: %peek - $% [%done dat=(unit (cask))] - [%bail dud=goof] - == == - $: %play - $% [%done mug=@] - [%bail eve=@ mug=@ dud=goof] - == == - $: %work - $% [%done eve=@ mug=@ fec=(list ovum)] - [%swap eve=@ mug=@ job=(pair @da ovum) fec=(list ovum)] - [%bail lud=(list goof)] - == == - == --- -*/ - -/* _lord_stop_cb(): finally all done. -*/ -static void -_lord_stop_cb(void* ptr_v, - ssize_t err_i, - const c3_c* err_c) -{ - u3_lord* god_u = ptr_v; - - void (*exit_f)(void*) = god_u->cb_u.exit_f; - void* exit_v = god_u->cb_u.ptr_v; - - u3s_cue_xeno_done(god_u->sil_u); - c3_free(god_u); - - if ( exit_f ) { - exit_f(exit_v); - } -} - -/* _lord_writ_free(): dispose of pending writ. -*/ -static void -_lord_writ_free(u3_writ* wit_u) -{ - switch ( wit_u->typ_e ) { - default: c3_assert(0); - - case u3_writ_work: { - // XX confirm - // - u3_ovum* egg_u = wit_u->wok_u.egg_u; - u3_auto_drop(egg_u->car_u, egg_u); - u3z(wit_u->wok_u.job); - } break; - - case u3_writ_peek: { - u3z(wit_u->pek_u->sam); - } break; - - case u3_writ_play: { - u3_fact* tac_u = wit_u->fon_u.ext_u; - u3_fact* nex_u; - - while ( tac_u ) { - nex_u = tac_u->nex_u; - u3_fact_free(tac_u); - tac_u = nex_u; - } - } break; - - case u3_writ_save: - case u3_writ_cram: - case u3_writ_meld: - case u3_writ_pack: - case u3_writ_exit: { - } break; - } - - c3_free(wit_u); -} - -/* _lord_bail_noop(): ignore subprocess error on shutdown -*/ -static void -_lord_bail_noop(void* ptr_v, - ssize_t err_i, - const c3_c* err_c) -{ -} - -/* _lord_stop(): close and dispose all resources. -*/ -static void -_lord_stop(u3_lord* god_u) -{ - // dispose outstanding writs - // - { - u3_writ* wit_u = god_u->ext_u; - u3_writ* nex_u; - - while ( wit_u ) { - nex_u = wit_u->nex_u; - _lord_writ_free(wit_u); - wit_u = nex_u; - } - - god_u->ent_u = god_u->ext_u = 0; - } - - u3_newt_moat_stop(&god_u->out_u, _lord_stop_cb); - u3_newt_mojo_stop(&god_u->inn_u, _lord_bail_noop); - - uv_read_stop((uv_stream_t*)&(god_u->err_u)); - - uv_close((uv_handle_t*)&god_u->cub_u, 0); - -#if defined(LORD_TRACE_JAM) || defined(LORD_TRACE_CUE) - u3t_trace_close(); -#endif -} - -/* _lord_bail(): serf/lord error. -*/ -static void -_lord_bail(u3_lord* god_u) -{ - void (*bail_f)(void*) = god_u->cb_u.bail_f; - void* bail_v = god_u->cb_u.ptr_v; - - u3_lord_halt(god_u); - bail_f(bail_v); -} - -/* _lord_writ_pop(): pop the writ stack. -*/ -static u3_writ* -_lord_writ_pop(u3_lord* god_u) -{ - u3_writ* wit_u = god_u->ext_u; - - c3_assert( wit_u ); - - if ( !wit_u->nex_u ) { - god_u->ent_u = god_u->ext_u = 0; - } - else { - god_u->ext_u = wit_u->nex_u; - wit_u->nex_u = 0; - } - - god_u->dep_w--; - - return wit_u; -} - -/* _lord_writ_str(): writ labels for printing. -*/ -static inline const c3_c* -_lord_writ_str(u3_writ_type typ_e) -{ - switch ( typ_e ) { - default: c3_assert(0); - - case u3_writ_work: return "work"; - case u3_writ_peek: return "peek"; - case u3_writ_play: return "play"; - case u3_writ_save: return "save"; - case u3_writ_cram: return "cram"; - case u3_writ_meld: return "meld"; - case u3_writ_pack: return "pack"; - case u3_writ_exit: return "exit"; - } -} - -/* _lord_writ_need(): require writ type. -*/ -static u3_writ* -_lord_writ_need(u3_lord* god_u, u3_writ_type typ_e) -{ - u3_writ* wit_u = _lord_writ_pop(god_u); - - if ( typ_e != wit_u->typ_e ) { - fprintf(stderr, "lord: unexpected %%%s, expected %%%s\r\n", - _lord_writ_str(typ_e), - _lord_writ_str(wit_u->typ_e)); - _lord_bail(god_u); - return 0; - } - - return wit_u; -} - -/* _lord_plea_foul(): -*/ -static void -_lord_plea_foul(u3_lord* god_u, c3_m mot_m, u3_noun dat) -{ - if ( u3_blip == mot_m ) { - fprintf(stderr, "lord: received invalid $plea\r\n"); - } - else { - fprintf(stderr, "lord: received invalid %%%.4s $plea\r\n", (c3_c*)&mot_m); - } - - // XX can't unconditionally print - // - // u3m_p("plea", dat); - - _lord_bail(god_u); -} - -/* _lord_plea_live(): hear serf %live ack -*/ -static void -_lord_plea_live(u3_lord* god_u, u3_noun dat) -{ - u3_writ* wit_u = _lord_writ_pop(god_u); - - if( u3_nul != dat ) { - return _lord_plea_foul(god_u, c3__live, dat); - } - - switch ( wit_u->typ_e ) { - default: { - return _lord_plea_foul(god_u, c3__live, dat); - } break; - - case u3_writ_save: { - god_u->cb_u.save_f(god_u->cb_u.ptr_v); - } break; - - case u3_writ_cram: { - god_u->cb_u.cram_f(god_u->cb_u.ptr_v); - } break; - - case u3_writ_meld: { - // XX wire into cb - // - u3l_log("pier: meld complete"); - } break; - - case u3_writ_pack: { - // XX wire into cb - // - u3l_log("pier: pack complete"); - } break; - } - - c3_free(wit_u); -} - -/* _lord_plea_ripe(): hear serf startup state -*/ -static void -_lord_plea_ripe(u3_lord* god_u, u3_noun dat) -{ - if ( c3y == god_u->liv_o ) { - fprintf(stderr, "lord: received unexpected %%ripe\n"); - _lord_bail(god_u); - return; - } - - { - u3_noun ver, pro, hon, noc, eve, mug; - c3_y pro_y, hon_y, noc_y; - c3_d eve_d; - c3_l mug_l; - - if ( (c3n == u3r_trel(dat, &ver, &eve, &mug)) - || (c3n == u3r_trel(ver, &pro, &hon, &noc)) - || (c3n == u3r_safe_byte(pro, &pro_y)) - || (c3n == u3r_safe_byte(hon, &hon_y)) - || (c3n == u3r_safe_byte(noc, &noc_y)) - || (c3n == u3r_safe_chub(eve, &eve_d)) - || (c3n == u3r_safe_word(mug, &mug_l)) ) - { - return _lord_plea_foul(god_u, c3__ripe, dat); - } - - if ( 1 != pro_y ) { - fprintf(stderr, "pier: unsupported ipc protocol version %u\r\n", pro_y); - _lord_bail(god_u); - return; - } - - god_u->eve_d = eve_d; - god_u->mug_l = mug_l; - god_u->hon_y = hon_y; - god_u->noc_y = noc_y; - } - - god_u->liv_o = c3y; - god_u->cb_u.live_f(god_u->cb_u.ptr_v); - - u3z(dat); -} - -/* _lord_plea_slog(): hear serf debug output -*/ -static void -_lord_plea_slog(u3_lord* god_u, u3_noun dat) -{ - u3_noun pri, tan; - c3_w pri_w; - - if ( (c3n == u3r_cell(dat, &pri, &tan)) - || (c3n == u3r_safe_word(pri, &pri_w)) ) - { - return _lord_plea_foul(god_u, c3__slog, dat); - } - - // XX per-writ slog_f? - // - - god_u->cb_u.slog_f(god_u->cb_u.ptr_v, pri_w, u3k(tan)); - u3z(dat); -} - -/* _lord_plea_flog(): hear serf debug output -*/ -static void -_lord_plea_flog(u3_lord* god_u, u3_noun dat) -{ - u3_pier* pir_u = god_u->cb_u.ptr_v; - - if ( c3n == u3a_is_atom(dat) ) { - return _lord_plea_foul(god_u, c3__flog, dat); - } - - c3_c* tan_c = u3r_string(dat); - u3C.stderr_log_f(tan_c); - c3_free(tan_c); - - if ( 0 != pir_u->sog_f ) { - pir_u->sog_f(pir_u->sop_p, 0, u3k(dat)); - } - u3z(dat); -} - -/* _lord_plea_peek_bail(): hear serf %peek %bail -*/ -static void -_lord_plea_peek_bail(u3_lord* god_u, u3_peek* pek_u, u3_noun dud) -{ - u3_pier_punt_goof("peek", dud); - - pek_u->fun_f(pek_u->ptr_v, u3_nul); - - u3z(pek_u->sam); - c3_free(pek_u); -} - -/* _lord_plea_peek_done(): hear serf %peek %done -*/ -static void -_lord_plea_peek_done(u3_lord* god_u, u3_peek* pek_u, u3_noun rep) -{ - // XX review - // - if ( (u3_pico_once == pek_u->typ_e) - && (u3_nul != rep) ) - { - u3_noun dat; - - if ( c3y == u3r_pq(u3t(rep), c3__omen, 0, &dat) ) { - u3k(dat); - u3z(rep); - rep = u3nc(u3_nul, dat); - } - } - - // XX cache [dat] (unless last) - // - pek_u->fun_f(pek_u->ptr_v, rep); - - u3z(pek_u->sam); - c3_free(pek_u); -} - -/* _lord_plea_peek(): hear serf %peek response -*/ -static void -_lord_plea_peek(u3_lord* god_u, u3_noun dat) -{ - u3_peek* pek_u; - { - u3_writ* wit_u = _lord_writ_need(god_u, u3_writ_peek); - pek_u = wit_u->pek_u; - c3_free(wit_u); - } - - if ( c3n == u3a_is_cell(dat) ) { - return _lord_plea_foul(god_u, c3__peek, dat); - } - - switch ( u3h(dat) ) { - default: { - return _lord_plea_foul(god_u, c3__peek, dat); - } - - case c3__done: { - _lord_plea_peek_done(god_u, pek_u, u3k(u3t(dat))); - } break; - - case c3__bail: { - _lord_plea_peek_bail(god_u, pek_u, u3k(u3t(dat))); - } break; - } - - u3z(dat); -} - -/* _lord_plea_play_bail(): hear serf %play %bail -*/ -static void -_lord_plea_play_bail(u3_lord* god_u, u3_info fon_u, u3_noun dat) -{ - u3_noun eve, mug, dud; - c3_d eve_d; - c3_l mug_l; - - if ( (c3n == u3r_trel(dat, &eve, &mug, &dud)) - || (c3n == u3r_safe_chub(eve, &eve_d)) - || (c3n == u3r_safe_word(mug, &mug_l)) - || (c3n == u3a_is_cell(dud)) ) - { - fprintf(stderr, "lord: invalid %%play\r\n"); - return _lord_plea_foul(god_u, c3__bail, dat); - } - - god_u->eve_d = (eve_d - 1ULL); - god_u->mug_l = mug_l; - - god_u->cb_u.play_bail_f(god_u->cb_u.ptr_v, - fon_u, mug_l, eve_d, u3k(dud)); - - u3z(dat); -} -/* _lord_plea_play_done(): hear serf %play %done -*/ -static void -_lord_plea_play_done(u3_lord* god_u, u3_info fon_u, u3_noun dat) -{ - c3_l mug_l; - - if ( c3n == u3r_safe_word(dat, &mug_l) ) { - fprintf(stderr, "lord: invalid %%play\r\n"); - return _lord_plea_foul(god_u, c3__done, dat); - } - - god_u->eve_d = fon_u.ent_u->eve_d; - god_u->mug_l = mug_l; - - god_u->cb_u.play_done_f(god_u->cb_u.ptr_v, fon_u, mug_l); - - u3z(dat); -} - -/* _lord_plea_play(): hear serf %play response -*/ -static void -_lord_plea_play(u3_lord* god_u, u3_noun dat) -{ - u3_info fon_u; - { - u3_writ* wit_u = _lord_writ_need(god_u, u3_writ_play); - fon_u = wit_u->fon_u; - c3_free(wit_u); - } - - if ( c3n == u3a_is_cell(dat) ) { - return _lord_plea_foul(god_u, c3__play, dat); - } - - switch ( u3h(dat) ) { - default: { - return _lord_plea_foul(god_u, c3__play, dat); - } - - case c3__done: { - _lord_plea_play_done(god_u, fon_u, u3k(u3t(dat))); - } break; - - case c3__bail: { - _lord_plea_play_bail(god_u, fon_u, u3k(u3t(dat))); - } break; - } - - u3z(dat); -} - -/* _lord_work_spin(): update spinner if more work is in progress. - */ - static void -_lord_work_spin(u3_lord* god_u) -{ - u3_writ* wit_u = god_u->ext_u; - - // complete spinner - // - c3_assert( c3y == god_u->pin_o ); - god_u->cb_u.spun_f(god_u->cb_u.ptr_v); - god_u->pin_o = c3n; - - // restart spinner if more work - // - while ( wit_u ) { - if ( u3_writ_work != wit_u->typ_e ) { - wit_u = wit_u->nex_u; - } - else { - u3_ovum* egg_u = wit_u->wok_u.egg_u; - - god_u->cb_u.spin_f(god_u->cb_u.ptr_v, - egg_u->pin_u.lab, - egg_u->pin_u.del_o); - god_u->pin_o = c3y; - break; - } - } -} - -/* _lord_work_done(): -*/ -static void -_lord_work_done(u3_lord* god_u, - u3_ovum* egg_u, - c3_d eve_d, - c3_l mug_l, - u3_noun job, - u3_noun act) -{ - u3_fact* tac_u = u3_fact_init(eve_d, mug_l, job); - god_u->mug_l = mug_l; - god_u->eve_d = eve_d; - - u3_gift* gif_u = u3_gift_init(eve_d, act); - - _lord_work_spin(god_u); - - god_u->cb_u.work_done_f(god_u->cb_u.ptr_v, egg_u, tac_u, gif_u); -} - - -/* _lord_plea_work_bail(): hear serf %work %bail -*/ -static void -_lord_plea_work_bail(u3_lord* god_u, u3_ovum* egg_u, u3_noun lud) -{ - _lord_work_spin(god_u); - - god_u->cb_u.work_bail_f(god_u->cb_u.ptr_v, egg_u, lud); -} - -/* _lord_plea_work_swap(): hear serf %work %swap -*/ -static void -_lord_plea_work_swap(u3_lord* god_u, u3_ovum* egg_u, u3_noun dat) -{ - u3_noun eve, mug, job, act; - c3_d eve_d; - c3_l mug_l; - - if ( (c3n == u3r_qual(dat, &eve, &mug, &job, &act)) - || (c3n == u3r_safe_chub(eve, &eve_d)) - || (c3n == u3r_safe_word(mug, &mug_l)) - || (c3n == u3a_is_cell(job)) ) - { - u3z(job); - u3_ovum_free(egg_u); - fprintf(stderr, "lord: invalid %%work\r\n"); - return _lord_plea_foul(god_u, c3__swap, dat); - } - else { - u3k(job); u3k(act); - u3z(dat); - _lord_work_done(god_u, egg_u, eve_d, mug_l, job, act); - } -} - -/* _lord_plea_work_done(): hear serf %work %done -*/ -static void -_lord_plea_work_done(u3_lord* god_u, - u3_ovum* egg_u, - u3_noun job, - u3_noun dat) -{ - u3_noun eve, mug, act; - c3_d eve_d; - c3_l mug_l; - - if ( (c3n == u3r_trel(dat, &eve, &mug, &act)) - || (c3n == u3r_safe_chub(eve, &eve_d)) - || (c3n == u3r_safe_word(mug, &mug_l)) ) - { - u3z(job); - u3_ovum_free(egg_u); - fprintf(stderr, "lord: invalid %%work\r\n"); - return _lord_plea_foul(god_u, c3__done, dat); - } - else { - u3k(act); - u3z(dat); - _lord_work_done(god_u, egg_u, eve_d, mug_l, job, act); - } -} - -/* _lord_plea_work(): hear serf %work response -*/ -static void -_lord_plea_work(u3_lord* god_u, u3_noun dat) -{ - u3_ovum* egg_u; - u3_noun job; - - { - u3_writ* wit_u = _lord_writ_need(god_u, u3_writ_work); - egg_u = wit_u->wok_u.egg_u; - job = wit_u->wok_u.job; - c3_free(wit_u); - } - - if ( c3n == u3a_is_cell(dat) ) { - u3z(job); - u3_ovum_free(egg_u); - return _lord_plea_foul(god_u, c3__work, dat); - } - - switch ( u3h(dat) ) { - default: { - u3z(job); - u3_ovum_free(egg_u); - return _lord_plea_foul(god_u, c3__work, dat); - } break; - - case c3__done: { - _lord_plea_work_done(god_u, egg_u, job, u3k(u3t(dat))); - } break; - - case c3__swap: { - u3z(job); - _lord_plea_work_swap(god_u, egg_u, u3k(u3t(dat))); - } break; - - case c3__bail: { - u3z(job); - _lord_plea_work_bail(god_u, egg_u, u3k(u3t(dat))); - } break; - } - - u3z(dat); -} - -/* _lord_on_plea(): handle plea from serf. -*/ -static void -_lord_on_plea(void* ptr_v, c3_d len_d, c3_y* byt_y) -{ - u3_lord* god_u = ptr_v; - u3_noun tag, dat; - u3_weak jar; - -#ifdef LORD_TRACE_CUE - u3t_event_trace("king ipc cue", 'B'); -#endif - - jar = u3s_cue_xeno_with(god_u->sil_u, len_d, byt_y); - -#ifdef LORD_TRACE_CUE - u3t_event_trace("king ipc cue", 'E'); -#endif - - if ( u3_none == jar ) { - return _lord_plea_foul(god_u, 0, u3_blip); - } - else if ( c3n == u3r_cell(jar, &tag, &dat) ) { - return _lord_plea_foul(god_u, 0, jar); - } - - switch ( tag ) { - default: { - return _lord_plea_foul(god_u, 0, jar); - } - - case c3__work: { - _lord_plea_work(god_u, u3k(dat)); - } break; - - case c3__peek: { - _lord_plea_peek(god_u, u3k(dat)); - } break; - - case c3__slog: { - _lord_plea_slog(god_u, u3k(dat)); - } break; - - case c3__flog: { - _lord_plea_flog(god_u, u3k(dat)); - } break; - - case c3__play: { - _lord_plea_play(god_u, u3k(dat)); - } break; - - case c3__live: { - _lord_plea_live(god_u, u3k(dat)); - } break; - - case c3__ripe: { - _lord_plea_ripe(god_u, u3k(dat)); - } break; - } - - u3z(jar); -} - -/* _lord_writ_new(): allocate a new writ. -*/ -static u3_writ* -_lord_writ_new(u3_lord* god_u) -{ - u3_writ* wit_u = c3_calloc(sizeof(*wit_u)); - return wit_u; -} - -/* _lord_writ_make(): cons writ. -*/ -static u3_noun -_lord_writ_make(u3_lord* god_u, u3_writ* wit_u) -{ - u3_noun msg; - - switch ( wit_u->typ_e ) { - default: c3_assert(0); - - case u3_writ_work: { - u3_noun mil = u3i_words(1, &wit_u->wok_u.egg_u->mil_w); - msg = u3nt(c3__work, mil, u3k(wit_u->wok_u.job)); - } break; - - case u3_writ_peek: { - // XX support timeouts, - // - msg = u3nc(c3__peek, u3nc(0, u3k(wit_u->pek_u->sam))); - } break; - - case u3_writ_play: { - u3_fact* tac_u = wit_u->fon_u.ext_u; - c3_d eve_d = tac_u->eve_d; - u3_noun lit = u3_nul; - - while ( tac_u ) { - lit = u3nc(u3k(tac_u->job), lit); - tac_u = tac_u->nex_u; - } - - msg = u3nt(c3__play, u3i_chubs(1, &eve_d), u3kb_flop(lit)); - - } break; - - case u3_writ_save: { - msg = u3nt(c3__live, c3__save, u3i_chubs(1, &god_u->eve_d)); - } break; - - case u3_writ_cram: { - msg = u3nt(c3__live, c3__cram, u3i_chubs(1, &god_u->eve_d)); - } break; - - case u3_writ_meld: { - msg = u3nt(c3__live, c3__meld, u3_nul); - } break; - - case u3_writ_pack: { - msg = u3nt(c3__live, c3__pack, u3_nul); - } break; - - case u3_writ_exit: { - // requested exit code is always 0 - // - msg = u3nt(c3__live, c3__exit, 0); - } break; - } - - return msg; -} - -/* _lord_writ_send(): send writ to serf. -*/ -static void -_lord_writ_send(u3_lord* god_u, u3_writ* wit_u) -{ - // exit expected - // - if ( u3_writ_exit == wit_u->typ_e ) { - god_u->out_u.bal_f = _lord_bail_noop; - god_u->inn_u.bal_f = _lord_bail_noop; - } - - { - u3_noun jar = _lord_writ_make(god_u, wit_u); - c3_d len_d; - c3_y* byt_y; - -#ifdef LORD_TRACE_JAM - u3t_event_trace("king ipc jam", 'B'); -#endif - - u3s_jam_xeno(jar, &len_d, &byt_y); - -#ifdef LORD_TRACE_JAM - u3t_event_trace("king ipc jam", 'E'); -#endif - - u3_newt_send(&god_u->inn_u, len_d, byt_y); - u3z(jar); - } -} - -/* _lord_writ_plan(): enqueue a writ and send. -*/ -static void -_lord_writ_plan(u3_lord* god_u, u3_writ* wit_u) -{ - if ( !god_u->ent_u ) { - c3_assert( !god_u->ext_u ); - c3_assert( !god_u->dep_w ); - god_u->dep_w = 1; - god_u->ent_u = god_u->ext_u = wit_u; - } - else { - god_u->dep_w++; - god_u->ent_u->nex_u = wit_u; - god_u->ent_u = wit_u; - } - - _lord_writ_send(god_u, wit_u); -} - -/* u3_lord_peek(): read namespace, injecting what's missing. -*/ -void -u3_lord_peek(u3_lord* god_u, u3_pico* pic_u) -{ - u3_writ* wit_u = _lord_writ_new(god_u); - wit_u->typ_e = u3_writ_peek; - wit_u->pek_u = c3_calloc(sizeof(*wit_u->pek_u)); - wit_u->pek_u->ptr_v = pic_u->ptr_v; - wit_u->pek_u->fun_f = pic_u->fun_f; - wit_u->pek_u->typ_e = pic_u->typ_e; - - // construct the full scry path - // - { - u3_noun sam; - switch ( pic_u->typ_e ) { - default: c3_assert(0); - - case u3_pico_full: { - sam = u3k(pic_u->ful); - } break; - - case u3_pico_once: { - sam = u3nc(c3n, u3nq(c3__once, - pic_u->las_u.car_m, - u3k(pic_u->las_u.des), - u3k(pic_u->las_u.pax))); - } break; - } - - wit_u->pek_u->sam = u3nc(u3k(pic_u->gan), sam); - } - - // XX cache check, unless last - // - _lord_writ_plan(god_u, wit_u); -} - -/* u3_lord_play(): recompute batch. -*/ -void -u3_lord_play(u3_lord* god_u, u3_info fon_u) -{ - u3_writ* wit_u = _lord_writ_new(god_u); - wit_u->typ_e = u3_writ_play; - wit_u->fon_u = fon_u; - - // XX wat do? - // - // c3_assert( !pay_u.ent_u->nex_u ); - - _lord_writ_plan(god_u, wit_u); -} - -/* u3_lord_work(): attempt work. -*/ -void -u3_lord_work(u3_lord* god_u, u3_ovum* egg_u, u3_noun job) -{ - u3_writ* wit_u = _lord_writ_new(god_u); - wit_u->typ_e = u3_writ_work; - wit_u->wok_u.egg_u = egg_u; - wit_u->wok_u.job = job; - - // if not spinning, start - // - if ( c3n == god_u->pin_o ) { - god_u->cb_u.spin_f(god_u->cb_u.ptr_v, - egg_u->pin_u.lab, - egg_u->pin_u.del_o); - god_u->pin_o = c3y; - } - - _lord_writ_plan(god_u, wit_u); -} - -/* u3_lord_save(): save a snapshot. -*/ -c3_o -u3_lord_save(u3_lord* god_u) -{ - if ( god_u->dep_w ) { - return c3n; - } - else { - u3_writ* wit_u = _lord_writ_new(god_u); - wit_u->typ_e = u3_writ_save; - _lord_writ_plan(god_u, wit_u); - return c3y; - } -} - -/* u3_lord_cram(): save portable state. -*/ -c3_o -u3_lord_cram(u3_lord* god_u) -{ - if ( god_u->dep_w ) { - return c3n; - } - else { - u3_writ* wit_u = _lord_writ_new(god_u); - wit_u->typ_e = u3_writ_cram; - _lord_writ_plan(god_u, wit_u); - return c3y; - } -} - -/* u3_lord_meld(): globally deduplicate persistent state. -*/ -void -u3_lord_meld(u3_lord* god_u) -{ - u3_writ* wit_u = _lord_writ_new(god_u); - wit_u->typ_e = u3_writ_meld; - _lord_writ_plan(god_u, wit_u); -} - -/* u3_lord_pack(): defragment persistent state. -*/ -void -u3_lord_pack(u3_lord* god_u) -{ - u3_writ* wit_u = _lord_writ_new(god_u); - wit_u->typ_e = u3_writ_pack; - _lord_writ_plan(god_u, wit_u); -} - -/* u3_lord_exit(): shutdown gracefully. -*/ -void -u3_lord_exit(u3_lord* god_u) -{ - u3_writ* wit_u = _lord_writ_new(god_u); - wit_u->typ_e = u3_writ_exit; - _lord_writ_plan(god_u, wit_u); - - // XX set timer, then halt -} - -/* u3_lord_stall(): send SIGINT -*/ -void -u3_lord_stall(u3_lord* god_u) -{ - uv_process_kill(&god_u->cub_u, SIGINT); -} - -/* u3_lord_halt(): shutdown immediately -*/ -void -u3_lord_halt(u3_lord* god_u) -{ - // no exit callback on halt - // - god_u->cb_u.exit_f = 0; - - uv_process_kill(&god_u->cub_u, SIGKILL); - _lord_stop(god_u); -} - -/* _lord_serf_err_alloc(): libuv buffer allocator. -*/ -static void -_lord_serf_err_alloc(uv_handle_t* had_u, size_t len_i, uv_buf_t* buf) -{ - // error/info messages as a rule don't exceed one line - // - *buf = uv_buf_init(c3_malloc(80), 80); -} - -/* _lord_on_serf_err_cb(): subprocess stderr callback. -*/ -static void -_lord_on_serf_err_cb(uv_stream_t* pyp_u, - ssize_t siz_i, - const uv_buf_t* buf_u) -{ - if ( siz_i >= 0 ) { - // serf used to write to 2 directly - // this can't be any worse than that - // - u3_write_fd(2, buf_u->base, siz_i); - } else { - uv_read_stop(pyp_u); - - if ( siz_i != UV_EOF ) { - u3l_log("lord: serf stderr: %s", uv_strerror(siz_i)); - } - } - - if ( buf_u->base != NULL ) { - c3_free(buf_u->base); - } -} - - -/* _lord_on_serf_exit(): handle subprocess exit. -*/ -static void -_lord_on_serf_exit(uv_process_t* req_u, - c3_ds sas_i, - c3_i sig_i) -{ - - u3_lord* god_u = (void*)req_u; - - if ( !god_u->ext_u - || !(u3_writ_exit == god_u->ext_u->typ_e) ) - { - fprintf(stderr, "pier: work exit: status %" PRId64 ", signal %d\r\n", - sas_i, sig_i); - _lord_bail(god_u); - } - else { - _lord_stop(god_u); - } -} - -/* _lord_on_serf_bail(): handle subprocess error. -*/ -static void -_lord_on_serf_bail(void* ptr_v, - ssize_t err_i, - const c3_c* err_c) -{ - u3_lord* god_u = ptr_v; - - if ( UV_EOF == err_i ) { - u3l_log("pier: serf unexpectedly shut down"); - } - else { - u3l_log("pier: serf error: %s", err_c); - } - - _lord_bail(god_u); -} - -/* u3_lord_info(): status info as $mass. -*/ -u3_noun -u3_lord_info(u3_lord* god_u) -{ - return u3_pier_mass( - c3__lord, - u3i_list( - u3_pier_mase("live", god_u->liv_o), - u3_pier_mase("event", u3i_chub(god_u->eve_d)), - u3_pier_mase("mug", god_u->mug_l), - u3_pier_mase("queue", u3i_word(god_u->dep_w)), - u3_newt_moat_info(&god_u->out_u), - u3_none)); -} - -/* u3_lord_slog(): print status info. -*/ -void -u3_lord_slog(u3_lord* god_u) -{ - u3l_log(" lord: live=%s, event=%" PRIu64 ", mug=%x, queue=%u", - ( c3y == god_u->liv_o ) ? "&" : "|", - god_u->eve_d, - god_u->mug_l, - god_u->dep_w); - u3_newt_moat_slog(&god_u->out_u); -} - -/* u3_lord_init(): instantiate child process. -*/ -u3_lord* -u3_lord_init(c3_c* pax_c, c3_w wag_w, c3_d key_d[4], u3_lord_cb cb_u) -{ - u3_lord* god_u = c3_calloc(sizeof *god_u); - god_u->liv_o = c3n; - god_u->pin_o = c3n; - god_u->wag_w = wag_w; - god_u->bin_c = u3_Host.wrk_c; // XX strcopy - god_u->pax_c = pax_c; // XX strcopy - god_u->cb_u = cb_u; - - god_u->key_d[0] = key_d[0]; - god_u->key_d[1] = key_d[1]; - god_u->key_d[2] = key_d[2]; - god_u->key_d[3] = key_d[3]; - - // spawn new process and connect to it - // - { - c3_c* arg_c[10]; - c3_c key_c[256]; - c3_c wag_c[11]; - c3_c hap_c[11]; - c3_c cev_c[11]; - c3_c lom_c[11]; - c3_i err_i; - - sprintf(key_c, "%" PRIx64 ":%" PRIx64 ":%" PRIx64 ":%" PRIx64, - god_u->key_d[0], - god_u->key_d[1], - god_u->key_d[2], - god_u->key_d[3]); - - sprintf(wag_c, "%u", god_u->wag_w); - - sprintf(hap_c, "%u", u3_Host.ops_u.hap_w); - - sprintf(lom_c, "%u", u3_Host.ops_u.lom_y); - - arg_c[0] = god_u->bin_c; // executable - arg_c[1] = "serf"; // protocol - arg_c[2] = god_u->pax_c; // path to checkpoint directory - arg_c[3] = key_c; // disk key - arg_c[4] = wag_c; // runtime config - arg_c[5] = hap_c; // hash table size - arg_c[6] = lom_c; // loom bex - - if ( u3_Host.ops_u.roc_c ) { - // XX validate - // - arg_c[7] = u3_Host.ops_u.roc_c; - } - else { - arg_c[7] = "0"; - } - -#ifdef U3_OS_mingw - sprintf(cev_c, "%" PRIu64, u3_Host.cev_u); - arg_c[8] = cev_c; -#else - arg_c[8] = 0; -#endif - - arg_c[9] = 0; - - uv_pipe_init(u3L, &god_u->inn_u.pyp_u, 0); - uv_timer_init(u3L, &god_u->out_u.tim_u); - uv_pipe_init(u3L, &god_u->out_u.pyp_u, 0); - uv_pipe_init(u3L, &god_u->err_u, 0); - - god_u->cod_u[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; - god_u->cod_u[0].data.stream = (uv_stream_t *)&god_u->inn_u; - - god_u->cod_u[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; - god_u->cod_u[1].data.stream = (uv_stream_t *)&god_u->out_u; - - god_u->cod_u[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; - god_u->cod_u[2].data.stream = (uv_stream_t *)&god_u->err_u; - - god_u->ops_u.stdio = god_u->cod_u; - god_u->ops_u.stdio_count = 3; - - // if any fds are inherited, libuv ignores UV_PROCESS_WINDOWS_HIDE* - god_u->ops_u.flags = UV_PROCESS_WINDOWS_HIDE; - god_u->ops_u.exit_cb = _lord_on_serf_exit; - god_u->ops_u.file = arg_c[0]; - god_u->ops_u.args = arg_c; - - if ( (err_i = uv_spawn(u3L, &god_u->cub_u, &god_u->ops_u)) ) { - fprintf(stderr, "spawn: %s: %s\r\n", arg_c[0], uv_strerror(err_i)); - - return 0; - } - - uv_read_start((uv_stream_t *)&god_u->err_u, _lord_serf_err_alloc, _lord_on_serf_err_cb); - } - -#if defined(LORD_TRACE_JAM) || defined(LORD_TRACE_CUE) - u3t_trace_open(god_u->pax_c); -#endif - - { - god_u->sil_u = u3s_cue_xeno_init(); - } - - // start reading from proc - // - { - god_u->out_u.ptr_v = god_u; - god_u->out_u.pok_f = _lord_on_plea; - god_u->out_u.bal_f = _lord_on_serf_bail; - - // XX distinguish from out_u.bal_f ? - // - god_u->inn_u.ptr_v = god_u; - god_u->inn_u.bal_f = _lord_on_serf_bail; - - u3_newt_read(&god_u->out_u); - } - return god_u; -} diff --git a/pkg/urbit/vere/newt.c b/pkg/urbit/vere/newt.c deleted file mode 100644 index 583edf5e3..000000000 --- a/pkg/urbit/vere/newt.c +++ /dev/null @@ -1,480 +0,0 @@ -/* vere/newt.c -** -** implements noun blob messages with trivial framing. -** -** framing is 5 bytes long. first byte is a version tag; a -** character that should never otherwise appear in a message -** intended for urbit. right now we use 0x0. next 32 bits are -** little-endian byte count. after that is the indicated number -** of bytes, which are the +jam of a noun. -** -** the implementation is relatively inefficient and could -** lose a few copies, mallocs, etc. -*/ -#include "all.h" -#include "vere/vere.h" - -/* _newt_mess_head(): await next msg header. -*/ -static void -_newt_mess_head(u3_mess* mes_u) -{ - mes_u->sat_e = u3_mess_head; - mes_u->hed_u.has_y = 0; -} - -/* _newt_mess_tail(): await msg body. -*/ -static void -_newt_mess_tail(u3_mess* mes_u, c3_d len_d) -{ - u3_meat* met_u = c3_malloc(len_d + sizeof(*met_u)); - met_u->nex_u = 0; - met_u->len_d = len_d; - - mes_u->sat_e = u3_mess_tail; - mes_u->tal_u.has_d = 0; - mes_u->tal_u.met_u = met_u; -} - -/* _newt_meat_plan(): enqueue complete msg. -*/ -static void -_newt_meat_plan(u3_moat* mot_u, u3_meat* met_u) -{ - if ( mot_u->ent_u ) { - mot_u->ent_u->nex_u = met_u; - mot_u->ent_u = met_u; - } - else { - mot_u->ent_u = mot_u->ext_u = met_u; - } -} - -/* _newt_meat_poke(): deliver completed msg. -*/ -static void -_newt_meat_poke(u3_moat* mot_u, u3_meat* met_u) -{ - mot_u->pok_f(mot_u->ptr_v, met_u->len_d, met_u->hun_y); - c3_free(met_u); -} - -/* _newt_meat_next_sync(): deliver completed msgs, synchronously. -*/ -static void -_newt_meat_next_sync(u3_moat* mot_u) -{ - u3_meat* met_u = mot_u->ext_u; - - while ( met_u ) { - u3_meat* nex_u = met_u->nex_u; - _newt_meat_poke(mot_u, met_u); - met_u = nex_u; - } - - mot_u->ent_u = mot_u->ext_u = 0; -} - -static void -_newt_meat_next_cb(uv_timer_t* tim_u); - -/* _newt_meat_next(): deliver completed msgs, asynchronously. -*/ -static void -_newt_meat_next(u3_moat* mot_u) -{ - u3_meat* met_u = mot_u->ext_u; - - if ( met_u ) { - mot_u->ext_u = met_u->nex_u; - - if ( mot_u->ext_u ) { - uv_timer_start(&mot_u->tim_u, _newt_meat_next_cb, 0, 0); - } - else { - mot_u->ent_u = 0; - } - - _newt_meat_poke(mot_u, met_u); - } -} - -/* _newt_meat_next_cb(): handle next msg after timer. -*/ -static void -_newt_meat_next_cb(uv_timer_t* tim_u) -{ - u3_moat* mot_u = tim_u->data; - _newt_meat_next(mot_u); -} - -/* u3_newt_decode(): decode a (partial) length-prefixed byte buffer -*/ -c3_o -u3_newt_decode(u3_moat* mot_u, c3_y* buf_y, c3_d len_d) -{ - u3_mess* mes_u = &mot_u->mes_u; - - while ( len_d ) { - switch( mes_u->sat_e ) { - - // read up to 5 bytes as needed - // - case u3_mess_head: { - c3_y* hed_y = mes_u->hed_u.hed_y; - c3_y has_y = mes_u->hed_u.has_y; - c3_y ned_y = sizeof(mes_u->hed_u.hed_y) - has_y; - c3_y cop_y = c3_min(ned_y, len_d); - - memcpy(hed_y + has_y, buf_y, cop_y); - buf_y += cop_y; - len_d -= cop_y; - ned_y -= cop_y; - - // moar bytes needed, yield - // - if ( ned_y ) { - mes_u->hed_u.has_y = (has_y + cop_y); - } - // length known, allocate message - // - else { - c3_d met_d = (((c3_d)hed_y[1]) << 0) - | (((c3_d)hed_y[2]) << 8) - | (((c3_d)hed_y[3]) << 16) - | (((c3_d)hed_y[4]) << 24); - - // check for version tag and nonzero length - // - if ( 0x0 != hed_y[0] || !met_d ) { - return c3n; - } - - // await body - // - _newt_mess_tail(mes_u, met_d); - } - } break; - - case u3_mess_tail: { - u3_meat* met_u = mes_u->tal_u.met_u; - c3_d has_d = mes_u->tal_u.has_d; - c3_d ned_d = met_u->len_d - has_d; - c3_d cop_d = c3_min(ned_d, len_d); - - memcpy(met_u->hun_y + has_d, buf_y, cop_d); - buf_y += cop_d; - len_d -= cop_d; - ned_d -= cop_d; - - // moar bytes needed, yield - // - if ( ned_d ) { - mes_u->tal_u.has_d = (has_d + cop_d); - } - // message completed, enqueue and await next header - // - else { - _newt_meat_plan(mot_u, met_u); - _newt_mess_head(mes_u); - } - } break; - } - } - return c3y; -} - -/* _newt_read(): handle async read result. -*/ -static c3_o -_newt_read(u3_moat* mot_u, - ssize_t len_i, - const uv_buf_t* buf_u) -{ - if ( 0 > len_i ) { - c3_free(buf_u->base); - uv_read_stop((uv_stream_t*)&mot_u->pyp_u); - - if ( UV_EOF != len_i ) { - fprintf(stderr, "newt: read failed %s\r\n", uv_strerror(len_i)); - } - - mot_u->bal_f(mot_u->ptr_v, len_i, uv_strerror(len_i)); - return c3n; - } - // EAGAIN/EWOULDBLOCK - // - else if ( 0 == len_i ) { - c3_free(buf_u->base); - return c3n; - } - else { - if ( c3n == u3_newt_decode(mot_u, (c3_y*)buf_u->base, (c3_d)len_i) ) { - mot_u->bal_f(mot_u->ptr_v, -1, "newt-decode"); - c3_free(buf_u->base); - return c3n; - } - c3_free(buf_u->base); - return c3y; - } -} - -/* _newt_read_sync_cb(): async read callback, sync msg delivery. -*/ -static void -_newt_read_sync_cb(uv_stream_t* str_u, - ssize_t len_i, - const uv_buf_t* buf_u) -{ - u3_moat* mot_u = (void *)str_u; - - if ( c3y == _newt_read(mot_u, len_i, buf_u) ) { - _newt_meat_next_sync(mot_u); - } -} - -/* _newt_read_cb(): async read callback, async msg delivery. -*/ -static void -_newt_read_cb(uv_stream_t* str_u, - ssize_t len_i, - const uv_buf_t* buf_u) -{ - u3_moat* mot_u = (void *)str_u; - - if ( c3y == _newt_read(mot_u, len_i, buf_u) ) { - _newt_meat_next(mot_u); - } -} - -/* _newt_alloc(): libuv-style allocator. -*/ -static void -_newt_alloc(uv_handle_t* had_u, - size_t len_i, - uv_buf_t* buf_u) -{ - // XX pick an appropriate size - // - void* ptr_v = c3_malloc(len_i); - - *buf_u = uv_buf_init(ptr_v, len_i); -} - -static void -_newt_read_init(u3_moat* mot_u, uv_read_cb read_cb_f) -{ - // zero-initialize completed msg queue - // - mot_u->ent_u = mot_u->ext_u = 0; - - // store pointer for libuv handle callback - // - mot_u->pyp_u.data = mot_u; - mot_u->tim_u.data = mot_u; - - // await next msg header - // - _newt_mess_head(&mot_u->mes_u); - - { - c3_i sas_i; - - if ( 0 != (sas_i = uv_read_start((uv_stream_t*)&mot_u->pyp_u, - _newt_alloc, - read_cb_f)) ) - { - fprintf(stderr, "newt: read failed %s\r\n", uv_strerror(sas_i)); - mot_u->bal_f(mot_u->ptr_v, sas_i, uv_strerror(sas_i)); - } - } -} - -/* _moat_stop_cb(): finalize stop/close input stream.. -*/ -static void -_moat_stop_cb(uv_handle_t* han_u) -{ - u3_moat* mot_u = han_u->data; - mot_u->bal_f(mot_u->ptr_v, -1, ""); -} - -/* u3_newt_moat_stop(); newt stop/close input stream. -*/ -void -u3_newt_moat_stop(u3_moat* mot_u, u3_moor_bail bal_f) -{ - mot_u->pyp_u.data = mot_u; - - if ( bal_f ) { - mot_u->bal_f = bal_f; - } - - uv_close((uv_handle_t*)&mot_u->pyp_u, _moat_stop_cb); - uv_close((uv_handle_t*)&mot_u->tim_u, 0); - - // dispose in-process message - // - if ( u3_mess_tail == mot_u->mes_u.sat_e ) { - c3_free(mot_u->mes_u.tal_u.met_u); - _newt_mess_head(&mot_u->mes_u); - } - - // dispose pending messages - { - u3_meat* met_u = mot_u->ext_u; - u3_meat* nex_u; - - while ( met_u ) { - nex_u = met_u->nex_u; - c3_free(met_u); - met_u = nex_u; - } - - mot_u->ent_u = mot_u->ext_u = 0; - } -} - -/* u3_newt_read_sync(): start reading; multiple msgs synchronous. -*/ -void -u3_newt_read_sync(u3_moat* mot_u) -{ - _newt_read_init(mot_u, _newt_read_sync_cb); -} - -/* u3_newt_read(): start reading; each msg asynchronous. -*/ -void -u3_newt_read(u3_moat* mot_u) -{ - _newt_read_init(mot_u, _newt_read_cb); -} - -/* u3_newt_moat_info(): status info as $mass. -*/ -u3_noun -u3_newt_moat_info(u3_moat* mot_u) -{ - u3_meat* met_u = mot_u->ext_u; - c3_w len_w = 0; - - while ( met_u ) { - len_w++; - met_u = met_u->nex_u; - } - return u3_pier_mass( - c3__moat, - u3i_list(u3_pier_mase("pending-inbound", u3i_word(len_w)), - u3_none)); -} - -/* u3_newt_moat_slog(); print status info. -*/ -void -u3_newt_moat_slog(u3_moat* mot_u) -{ - u3_meat* met_u = mot_u->ext_u; - c3_w len_w = 0; - - while ( met_u ) { - len_w++; - met_u = met_u->nex_u; - } - - if ( len_w ) { - u3l_log(" newt: %u inbound ipc messages pending", len_w); - } -} - -/* n_req: write request for newt -*/ -typedef struct _n_req { - uv_write_t wri_u; - u3_mojo* moj_u; - c3_y* buf_y; - c3_y hed_y[5]; -} n_req; - -/* _newt_write_cb(): generic write callback. -*/ -static void -_newt_write_cb(uv_write_t* wri_u, c3_i sas_i) -{ - n_req* req_u = (n_req*)wri_u; - u3_mojo* moj_u = req_u->moj_u; - - c3_free(req_u->buf_y); - c3_free(req_u); - - if ( 0 != sas_i ) { - if ( UV_ECANCELED == sas_i ) { - fprintf(stderr, "newt: write canceled\r\n"); - } - else { - fprintf(stderr, "newt: write failed %s\r\n", uv_strerror(sas_i)); - moj_u->bal_f(moj_u->ptr_v, sas_i, uv_strerror(sas_i)); - } - } -} - -/* _mojo_stop_cb(): finalize stop/close output stream.. -*/ -static void -_mojo_stop_cb(uv_handle_t* han_u) -{ - u3_mojo* moj_u = han_u->data; - moj_u->bal_f(moj_u->ptr_v, -1, ""); -} - -/* u3_newt_mojo_stop(); newt stop/close output stream. -*/ -void -u3_newt_mojo_stop(u3_mojo* moj_u, u3_moor_bail bal_f) -{ - moj_u->pyp_u.data = moj_u; - - if ( bal_f ) { - moj_u->bal_f = bal_f; - } - - uv_close((uv_handle_t*)&moj_u->pyp_u, _mojo_stop_cb); -} - -/* u3_newt_send(): write buffer to stream. -*/ -void -u3_newt_send(u3_mojo* moj_u, c3_d len_d, c3_y* byt_y) -{ - n_req* req_u = c3_malloc(sizeof(*req_u)); - req_u->moj_u = moj_u; - req_u->buf_y = byt_y; - - // write header - // - req_u->hed_y[0] = 0x0; - req_u->hed_y[1] = ( len_d & 0xff); - req_u->hed_y[2] = ((len_d >> 8) & 0xff); - req_u->hed_y[3] = ((len_d >> 16) & 0xff); - req_u->hed_y[4] = ((len_d >> 24) & 0xff); - - { - uv_buf_t buf_u[2] = { - uv_buf_init((c3_c*)req_u->hed_y, sizeof(req_u->hed_y)), - uv_buf_init((c3_c*)req_u->buf_y, len_d) - }; - - c3_i sas_i; - - if ( 0 != (sas_i = uv_write(&req_u->wri_u, - (uv_stream_t*)&moj_u->pyp_u, - buf_u, 2, - _newt_write_cb)) ) - { - c3_free(req_u); - fprintf(stderr, "newt: write failed %s\r\n", uv_strerror(sas_i)); - moj_u->bal_f(moj_u->ptr_v, sas_i, uv_strerror(sas_i)); - } - } -} diff --git a/pkg/urbit/vere/pier.c b/pkg/urbit/vere/pier.c deleted file mode 100644 index a0870ff60..000000000 --- a/pkg/urbit/vere/pier.c +++ /dev/null @@ -1,2459 +0,0 @@ -/* vere/pier.c -*/ -#include "all.h" -#include "vere/vere.h" -#include "vere/db/lmdb.h" -#include - -#define PIER_READ_BATCH 1000ULL -#define PIER_PLAY_BATCH 500ULL -#define PIER_WORK_BATCH 10ULL - -#undef VERBOSE_PIER - -/* _pier_peek_plan(): add a u3_pico to the peek queue -*/ -static void -_pier_peek_plan(u3_pier* pir_u, u3_pico* pic_u) -{ - if (!pir_u->pec_u.ent_u) { - c3_assert( !pir_u->pec_u.ext_u ); - pir_u->pec_u.ent_u = pir_u->pec_u.ext_u = pic_u; - } - else { - pir_u->pec_u.ent_u->nex_u = pic_u; - pir_u->pec_u.ent_u = pic_u; - } - - u3_pier_spin(pir_u); -} - -/* _pier_peek_next(): pop u3_pico off of peek queue -*/ -static u3_pico* -_pier_peek_next(u3_pier* pir_u) -{ - u3_pico* pic_u = pir_u->pec_u.ext_u; - - if (pic_u) { - pir_u->pec_u.ext_u = pic_u->nex_u; - if (!pir_u->pec_u.ext_u) { - pir_u->pec_u.ent_u = 0; - } - - pic_u->nex_u = 0; - } - - return pic_u; -} - -/* _pier_work_send(): send new events for processing -*/ -static void -_pier_work_send(u3_work* wok_u) -{ - u3_auto* car_u = wok_u->car_u; - u3_pier* pir_u = wok_u->pir_u; - u3_lord* god_u = pir_u->god_u; - c3_w len_w = 0; - - // calculate work batch size - { - u3_wall* wal_u = wok_u->wal_u; - - if ( !wal_u ) { - // XX work depth, or full lord send-stack depth? - // - if ( PIER_WORK_BATCH > god_u->dep_w ) { - len_w = PIER_WORK_BATCH - god_u->dep_w; - } - } - else { - c3_d sen_d = god_u->eve_d + god_u->dep_w; - if ( wal_u->eve_d > sen_d ) { - len_w = wal_u->eve_d - sen_d; - } - } - } - - // send batch - // - { - u3_ovum* egg_u; - u3_pico* pic_u; - u3_noun ovo, now, bit = u3qc_bex(48); - - { - struct timeval tim_tv; - gettimeofday(&tim_tv, 0); - now = u3_time_in_tv(&tim_tv); - } - - while ( len_w && car_u && (egg_u = u3_auto_next(car_u, &ovo)) ) { - len_w--; - u3_lord_work(god_u, egg_u, u3nc(u3k(now), ovo)); - now = u3ka_add(now, u3k(bit)); - - // queue events depth first - // - car_u = egg_u->car_u; - - // interleave scry requests - // - if ( len_w && (pic_u = _pier_peek_next(pir_u)) ) - { - len_w--; - u3_lord_peek(god_u, pic_u); - u3_pico_free(pic_u); - } - } - - // if there's room left in the batch, fill it up with remaining scries - // - while ( len_w-- && (pic_u = _pier_peek_next(pir_u)) ) - { - u3_lord_peek(god_u, pic_u); - u3_pico_free(pic_u); - } - - u3z(now); u3z(bit); - } -} - -/* _pier_gift_plan(): enqueue effects. -*/ -static void -_pier_gift_plan(u3_work* wok_u, u3_gift* gif_u) -{ - c3_assert( gif_u->eve_d > wok_u->fec_u.rel_d ); - -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: (%" PRIu64 "): compute: complete\r\n", gif_u->eve_d); -#endif - - gif_u->nex_u = 0; - - if ( !wok_u->fec_u.ent_u ) { - c3_assert( !wok_u->fec_u.ext_u ); - wok_u->fec_u.ent_u = wok_u->fec_u.ext_u = gif_u; - } - else { - wok_u->fec_u.ent_u->nex_u = gif_u; - wok_u->fec_u.ent_u = gif_u; - } -} - -/* _pier_gift_next(): dequeue effect. -*/ -static u3_gift* -_pier_gift_next(u3_work* wok_u) -{ - u3_pier* pir_u = wok_u->pir_u; - u3_disk* log_u = pir_u->log_u; - u3_gift* gif_u = wok_u->fec_u.ext_u; - - if ( !gif_u || (gif_u->eve_d > log_u->dun_d) ) { - return 0; - } - else { - wok_u->fec_u.ext_u = gif_u->nex_u; - - if ( !wok_u->fec_u.ext_u ) { - wok_u->fec_u.ent_u = 0; - } - - c3_assert( (1ULL + wok_u->fec_u.rel_d) == gif_u->eve_d ); - wok_u->fec_u.rel_d = gif_u->eve_d; - - return gif_u; - } -} - -/* _pier_gift_kick(): apply effects. -*/ -static void -_pier_gift_kick(u3_work* wok_u) -{ - u3_gift* gif_u; - - while ( (gif_u = _pier_gift_next(wok_u)) ) { -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: (%" PRIu64 "): compute: release\r\n", gif_u->eve_d); -#endif - - u3_auto_kick(wok_u->car_u, gif_u->act); - u3_gift_free(gif_u); - } -} - -/* _pier_wall_plan(): enqueue a barrier. -*/ -static void -_pier_wall_plan(u3_pier* pir_u, c3_d eve_d, - void* ptr_v, void (*wal_f)(void*, c3_d)) -{ - c3_assert( u3_psat_work == pir_u->sat_e ); - - u3_wall* wal_u = c3_malloc(sizeof(*wal_u)); - wal_u->ptr_v = ptr_v; - wal_u->eve_d = eve_d; - wal_u->wal_f = wal_f; - - // insert into [pir_u->wal_u], preserving stable sort by [eve_d] - // - { - u3_wall** las_u = &pir_u->wok_u->wal_u; - - while ( *las_u && (eve_d <= (*las_u)->eve_d) ) { - las_u = &(*las_u)->nex_u; - } - - wal_u->nex_u = *las_u; - *las_u = wal_u; - } -} - -/* _pier_wall(): process a barrier if possible. -*/ -static void -_pier_wall(u3_work* wok_u) -{ - u3_lord* god_u = wok_u->pir_u->god_u; - u3_disk* log_u = wok_u->pir_u->log_u; - - if ( god_u->eve_d == log_u->dun_d ) { - u3_wall* wal_u; - - while ( (wal_u = wok_u->wal_u) - && !god_u->dep_w - && (wal_u->eve_d <= god_u->eve_d) ) - { - wok_u->wal_u = wal_u->nex_u; - wal_u->wal_f(wal_u->ptr_v, god_u->eve_d); - c3_free(wal_u); - } - } -} - -/* _pier_work(): advance event processing. -*/ -static void -_pier_work(u3_work* wok_u) -{ - u3_pier* pir_u = wok_u->pir_u; - - if ( c3n == pir_u->liv_o ) { - pir_u->liv_o = u3_auto_live(wok_u->car_u); - - // all i/o drivers are fully initialized - // - if ( c3y == pir_u->liv_o ) { - // XX this is when "boot" is actually complete - // XX even better would be after neighboring with our sponsor - // - u3l_log("pier (%" PRIu64 "): live", pir_u->god_u->eve_d); - - // XX move callbacking to king - // - if ( u3_Host.bot_f ) { - u3_Host.bot_f(); - } - } - } - - _pier_gift_kick(wok_u); - _pier_wall(wok_u); - - if ( u3_psat_work == pir_u->sat_e ) { - _pier_work_send(wok_u); - } - else { - c3_assert( u3_psat_done == pir_u->sat_e ); - } -} - -/* _pier_on_lord_work_spin(): start spinner -*/ -static void -_pier_on_lord_work_spin(void* ptr_v, u3_atom pin, c3_o del_o) -{ - u3_pier* pir_u = ptr_v; - - c3_assert( (u3_psat_wyrd == pir_u->sat_e) - || (u3_psat_work == pir_u->sat_e) - || (u3_psat_done == pir_u->sat_e) ); - - u3_term_start_spinner(pin, del_o); -} - -/* _pier_on_lord_work_spun(): stop spinner -*/ -static void -_pier_on_lord_work_spun(void* ptr_v) -{ - u3_pier* pir_u = ptr_v; - - c3_assert( (u3_psat_wyrd == pir_u->sat_e) - || (u3_psat_work == pir_u->sat_e) - || (u3_psat_done == pir_u->sat_e) ); - - u3_term_stop_spinner(); -} - -/* _pier_on_lord_work_done(): event completion from worker. -*/ -static void -_pier_on_lord_work_done(void* ptr_v, - u3_ovum* egg_u, - u3_fact* tac_u, - u3_gift* gif_u) -{ - u3_pier* pir_u = ptr_v; - - c3_assert( (u3_psat_work == pir_u->sat_e) - || (u3_psat_done == pir_u->sat_e) ); - -#ifdef VERBOSE_PIER - fprintf(stderr, "pier (%" PRIu64 "): work: done\r\n", tac_u->eve_d); -#endif - - // XX this is a departure from the general organization of this file - // - u3_disk_plan(pir_u->log_u, tac_u); - - u3_auto_done(egg_u); - - _pier_gift_plan(pir_u->wok_u, gif_u); - _pier_work(pir_u->wok_u); -} - -/* _pier_on_lord_work_bail(): event failure from worker. -*/ -static void -_pier_on_lord_work_bail(void* ptr_v, u3_ovum* egg_u, u3_noun lud) -{ - u3_pier* pir_u = ptr_v; - -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: work: bail\r\n"); -#endif - - c3_assert( (u3_psat_work == pir_u->sat_e) - || (u3_psat_done == pir_u->sat_e) ); - - u3_auto_bail(egg_u, lud); - - // XX groace - // - if ( pir_u->wok_u ) { - _pier_work(pir_u->wok_u); - } -} - -/* _pier_work_time(): set time. -*/ -static void -_pier_work_time(u3_pier* pir_u) -{ - struct timeval tim_tv; - gettimeofday(&tim_tv, 0); - - // XX save to pier - // - u3v_time(u3_time_in_tv(&tim_tv)); -} - -/* _pier_work_fore_cb(): run on every loop iteration before i/o polling. -*/ -static void -_pier_work_fore_cb(uv_prepare_t* pep_u) -{ - u3_work* wok_u = pep_u->data; - _pier_work_time(wok_u->pir_u); -} - -/* _pier_work_afte_cb(): run on every loop iteration after i/o polling. -*/ -static void -_pier_work_afte_cb(uv_check_t* cek_u) -{ - u3_work* wok_u = cek_u->data; - _pier_work(wok_u); -} - -/* _pier_work_idle_cb(): run on next loop iteration. -*/ -static void -_pier_work_idle_cb(uv_idle_t* idl_u) -{ - u3_work* wok_u = idl_u->data; - _pier_work(wok_u); - uv_idle_stop(idl_u); -} - -/* u3_pier_spin(): (re-)activate idle handler -*/ -void -u3_pier_spin(u3_pier* pir_u) -{ - // XX return c3n instead? - // - if ( u3_psat_work == pir_u->sat_e - || u3_psat_done == pir_u->sat_e ) - { - u3_work* wok_u = pir_u->wok_u; - - if ( !uv_is_active((uv_handle_t*)&wok_u->idl_u) ) { - uv_idle_start(&wok_u->idl_u, _pier_work_idle_cb); - } - } -} - -/* u3_pier_peek(): read namespace. -*/ -void -u3_pier_peek(u3_pier* pir_u, - u3_noun gan, - u3_noun ful, - void* ptr_v, - u3_peek_cb fun_f) -{ - u3_pico* pic_u = u3_pico_init(); - - pic_u->ptr_v = ptr_v; - pic_u->fun_f = fun_f; - pic_u->gan = gan; - // - pic_u->typ_e = u3_pico_full; - pic_u->ful = ful; - - _pier_peek_plan(pir_u, pic_u); -} - -/* u3_pier_peek_last(): read namespace, injecting ship and case. -*/ -void -u3_pier_peek_last(u3_pier* pir_u, - u3_noun gan, - c3_m car_m, - u3_atom des, - u3_noun pax, - void* ptr_v, - u3_peek_cb fun_f) -{ - u3_pico* pic_u = u3_pico_init(); - - pic_u->ptr_v = ptr_v; - pic_u->fun_f = fun_f; - pic_u->gan = gan; - // - pic_u->typ_e = u3_pico_once; - pic_u->las_u.car_m = car_m; - pic_u->las_u.des = des; - pic_u->las_u.pax = pax; - - _pier_peek_plan(pir_u, pic_u); -} - -/* _pier_stab(): parse path -*/ -static u3_noun -_pier_stab(u3_noun pac) -{ - return u3do("stab", pac); -} - -/* _pier_on_scry_done(): scry callback. -*/ -static void -_pier_on_scry_done(void* ptr_v, u3_noun nun) -{ - u3_pier* pir_u = ptr_v; - u3_weak res = u3r_at(7, nun); - - if (u3_none == res) { - u3l_log("pier: scry failed"); - } - else { - u3_weak out; - c3_c *ext_c, *pac_c; - - u3l_log("pier: scry succeeded"); - - if ( u3_Host.ops_u.puk_c ) { - pac_c = u3_Host.ops_u.puk_c; - } - else { - pac_c = u3_Host.ops_u.pek_c; - } - - // try to serialize as requested - // - { - u3_atom puf = u3i_string(u3_Host.ops_u.puf_c); - if ( c3y == u3r_sing(c3__jam, puf) ) { - c3_d len_d; - c3_y* byt_y; - u3s_jam_xeno(res, &len_d, &byt_y); - out = u3i_bytes(len_d, byt_y); - ext_c = "jam"; - free(byt_y); - } - else if ( c3y == u3a_is_atom(res) ) { - out = u3dc("scot", u3k(puf), u3k(res)); - ext_c = "txt"; - } - else { - u3l_log("pier: cannot export cell as %s", u3_Host.ops_u.puf_c); - out = u3_none; - } - u3z(puf); - } - - // if serialization and export path succeeded, write to disk - // - if ( u3_none != out ) { - c3_c fil_c[256]; - snprintf(fil_c, 256, "%s.%s", pac_c + 1, ext_c); - - u3_unix_save(fil_c, out); - u3l_log("pier: scry result in %s/.urb/put/%s", u3_Host.dir_c, fil_c); - } - } - - u3l_log("pier: exit"); - u3_pier_exit(pir_u); - - u3z(nun); -} - -/* _pier_work_init(): begin processing new events -*/ -static void -_pier_work_init(u3_pier* pir_u) -{ - u3_work* wok_u; - - c3_assert( u3_psat_wyrd == pir_u->sat_e ); - - pir_u->sat_e = u3_psat_work; - pir_u->wok_u = wok_u = c3_calloc(sizeof(*wok_u)); - wok_u->pir_u = pir_u; - wok_u->fec_u.rel_d = pir_u->log_u->dun_d; - - _pier_work_time(pir_u); - - // XX plan kelvin event - // - - // XX snapshot timer - // XX moveme - // - { - c3_l cod_l = u3a_lush(c3__save); - u3_save_io_init(pir_u); - u3a_lop(cod_l); - } - - // initialize pre i/o polling handle - // - uv_prepare_init(u3L, &wok_u->pep_u); - wok_u->pep_u.data = wok_u; - uv_prepare_start(&wok_u->pep_u, _pier_work_fore_cb); - - // initialize post i/o polling handle - // - uv_check_init(u3L, &wok_u->cek_u); - wok_u->cek_u.data = wok_u; - uv_check_start(&wok_u->cek_u, _pier_work_afte_cb); - - // initialize idle i/o polling handle - // - // NB, not started - // - uv_idle_init(u3L, &wok_u->idl_u); - wok_u->idl_u.data = wok_u; - - // // setup u3_lord work callbacks - // // - // u3_lord_work_cb cb_u = { - // .ptr_v = wok_u, - // .spin_f = _pier_on_lord_work_spin, - // .spun_f = _pier_on_lord_work_spun, - // .done_f = _pier_on_lord_work_done, - // .bail_f = _pier_on_lord_work_bail - // }; - // u3_lord_work_init(pir_u->god_u, cb_u); - - // XX this is messy, revise - // - if ( u3_Host.ops_u.pek_c ) { - u3_noun pex = u3do("stab", u3i_string(u3_Host.ops_u.pek_c)); - u3_noun car; - u3_noun dek; - u3_noun pax; - if ( c3n == u3r_trel(pex, &car, &dek, &pax) - || c3n == u3a_is_cat(car) ) - { - u3m_p("pier: invalid scry", pex); - _pier_on_scry_done(pir_u, u3_nul); - } else { - // run the requested scry, jam to disk, then exit - // - u3l_log("pier: scry"); - u3_pier_peek_last(pir_u, u3_nul, u3k(car), u3k(dek), u3k(pax), - pir_u, _pier_on_scry_done); - } - u3z(pex); - } - else { - // initialize i/o drivers - // - wok_u->car_u = u3_auto_init(pir_u); - u3_auto_talk(wok_u->car_u); - } - - _pier_work(wok_u); -} - -/* _pier_wyrd_good(): %wyrd version negotation succeeded. -*/ -static void -_pier_wyrd_good(u3_pier* pir_u, u3_ovum* egg_u) -{ - // restore event callbacks - // - { - u3_lord* god_u = pir_u->god_u; - god_u->cb_u.work_done_f = _pier_on_lord_work_done; - god_u->cb_u.work_bail_f = _pier_on_lord_work_bail; - } - - // initialize i/o drivers - // - _pier_work_init(pir_u); - - // free %wyrd driver and ovum - // - { - u3_auto* car_u = egg_u->car_u; - u3_auto_done(egg_u); - c3_free(car_u); - } -} - -/* _pier_wyrd_fail(): %wyrd version negotation failed. -*/ -static void -_pier_wyrd_fail(u3_pier* pir_u, u3_ovum* egg_u, u3_noun lud) -{ - // XX version negotiation failed, print upgrade message - // - u3l_log("pier: version negotation failed"); - - // XX only print trace with -v ? - // - if ( u3_nul != lud ) { - u3_auto_bail_slog(egg_u, u3k(u3t(lud))); - } - - u3z(lud); - - // free %wyrd driver and ovum - // - { - u3_auto* car_u = egg_u->car_u; - u3_auto_done(egg_u); - c3_free(car_u); - } - - u3_pier_bail(pir_u); -} - -// XX organizing version constants -// -#define VERE_NAME "vere" -#define VERE_ZUSE 416 -#define VERE_LULL 327 - -/* _pier_wyrd_aver(): check for %wend effect and version downgrade. RETAIN -*/ -static c3_o -_pier_wyrd_aver(u3_noun act) -{ - u3_noun fec, kel, ver; - - // XX review, %wend re: %wyrd optional? - // - while ( u3_nul != act ) { - u3x_cell(act, &fec, &act); - - if ( c3__wend == u3h(fec) ) { - kel = u3t(fec); - - // traverse $wynn, check for downgrades - // - while ( u3_nul != kel ) { - u3x_cell(kel, &ver, &kel); - - // check for %zuse downgrade - // - if ( (c3__zuse == u3h(ver)) - && (VERE_ZUSE != u3t(ver)) ) - { - return c3n; - } - - // XX in the future, send %wend to serf - // to also negotiate downgrade of nock/hoon/&c? - // (we don't want to have to filter effects) - // - } - } - } - - return c3y; -} - -/* _pier_on_lord_wyrd_done(): callback for successful %wyrd event. -*/ -static void -_pier_on_lord_wyrd_done(void* ptr_v, - u3_ovum* egg_u, - u3_fact* tac_u, - u3_gift* gif_u) -{ - u3_pier* pir_u = ptr_v; - - c3_assert( u3_psat_wyrd == pir_u->sat_e ); - - // arvo's side of version negotiation succeeded - // traverse [gif_y] and validate - // - if ( c3n == _pier_wyrd_aver(gif_u->act) ) { - u3_fact_free(tac_u); - u3_gift_free(gif_u); - - // XX messaging, cli argument to bypass - // - u3l_log("pier: version negotiation failed; downgrade"); - _pier_wyrd_fail(pir_u, egg_u, u3_nul); - } - else { - // enqueue %wyrd event-log commit - // - u3_disk_plan(pir_u->log_u, tac_u); - - // finalize %wyrd success - // - _pier_wyrd_good(pir_u, egg_u); - - // plan %wyrd effects - // - _pier_gift_plan(pir_u->wok_u, gif_u); - } -} - -/* _pier_on_lord_wyrd_bail(): callback for failed %wyrd event. -*/ -static void -_pier_on_lord_wyrd_bail(void* ptr_v, u3_ovum* egg_u, u3_noun lud) -{ - u3_pier* pir_u = ptr_v; - - c3_assert( u3_psat_wyrd == pir_u->sat_e ); - - // XX add cli argument to bypass negotiation failure - // -#if 1 - // print %wyrd failure and exit - // - // XX check bail mote, retry on %intr, %meme, &c - // - _pier_wyrd_fail(pir_u, egg_u, lud); -#else - // XX temporary hack to fake %wyrd success - // - { - _pier_wyrd_good(pir_u, egg_u); - u3z(lud); - } -#endif -} - -/* _pier_wyrd_init(): construct %wyrd. -*/ -static u3_noun -_pier_wyrd_card(u3_pier* pir_u) -{ - u3_lord* god_u = pir_u->god_u; - u3_noun sen; - - _pier_work_time(pir_u); - - { - c3_l sev_l; - u3_noun now; - struct timeval tim_u; - gettimeofday(&tim_u, 0); - - now = u3_time_in_tv(&tim_u); - sev_l = u3r_mug(now); - sen = u3dc("scot", c3__uv, sev_l); - - u3z(now); - } - - // XX god_u not necessarily available yet, refactor call sites - // - u3_noun ver = u3nt(u3i_string(VERE_NAME), - u3dc("scot", c3__ta, u3i_string(URBIT_VERSION)), - u3_nul); - u3_noun kel = u3nl(u3nc(c3__zuse, VERE_ZUSE), // XX from both king and serf? - u3nc(c3__lull, VERE_LULL), // XX from both king and serf? - u3nc(c3__arvo, 240), // XX from both king and serf? - u3nc(c3__hoon, 140), // god_u->hon_y - u3nc(c3__nock, 4), // god_u->noc_y - u3_none); - u3_noun wir = u3nc(c3__arvo, u3_nul); - return u3nt(c3__wyrd, u3nc(sen, ver), kel); -} - -/* _pier_wyrd_init(): send %wyrd. -*/ -static void -_pier_wyrd_init(u3_pier* pir_u) -{ - u3_noun cad = _pier_wyrd_card(pir_u); - u3_noun wir = u3nc(c3__arvo, u3_nul); - - pir_u->sat_e = u3_psat_wyrd; - - u3l_log("vere: checking version compatibility"); - - { - u3_lord* god_u = pir_u->god_u; - u3_auto* car_u = c3_calloc(sizeof(*car_u)); - u3_ovum* egg_u = u3_ovum_init(0, u3_blip, wir, cad); - u3_noun ovo; - - car_u->pir_u = pir_u; - car_u->nam_m = c3__wyrd; - - u3_auto_plan(car_u, egg_u); - - // instead of subscribing with u3_auto_peer(), - // we swizzle the [god_u] callbacks for full control - // - god_u->cb_u.work_done_f = _pier_on_lord_wyrd_done; - god_u->cb_u.work_bail_f = _pier_on_lord_wyrd_bail; - - c3_assert( u3_auto_next(car_u, &ovo) == egg_u ); - - { - struct timeval tim_tv; - gettimeofday(&tim_tv, 0); - u3_lord_work(god_u, egg_u, u3nc(u3_time_in_tv(&tim_tv), ovo)); - } - } -} - -/* _pier_play_plan(): enqueue events for replay. -*/ -static void -_pier_play_plan(u3_play* pay_u, u3_info fon_u) -{ - u3_fact** ext_u; - c3_d old_d; - - if ( !pay_u->ext_u ) { - c3_assert( !pay_u->ent_u ); - ext_u = &pay_u->ext_u; - old_d = pay_u->sen_d; - } - else { - ext_u = &pay_u->ent_u->nex_u; - old_d = pay_u->ent_u->eve_d; - } - -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: play plan %" PRIu64 "-%" PRIu64 " at %" PRIu64 "\r\n", - fon_u.ext_u->eve_d, - fon_u.ent_u->eve_d, - old_d); -#endif - - c3_assert( (1ULL + old_d) == fon_u.ext_u->eve_d ); - - *ext_u = fon_u.ext_u; - pay_u->ent_u = fon_u.ent_u; -} - -/* _pier_play_send(): detach a batch of up to [len_w] events from queue. -*/ -static u3_info -_pier_play_next(u3_play* pay_u, c3_w len_w) -{ - u3_fact* tac_u = pay_u->ext_u; - u3_info fon_u; - - // XX just share batch with lord, save last sent to pay_u->sen_u - // - - // set batch entry and exit pointers - // - { - fon_u.ext_u = tac_u; - - while ( len_w-- && tac_u->nex_u ) { - tac_u = tac_u->nex_u; - } - - fon_u.ent_u = tac_u; - } - - // detatch batch from queue - // - if ( tac_u->nex_u ) { - pay_u->ext_u = tac_u->nex_u; - tac_u->nex_u = 0; - } - else { - pay_u->ent_u = pay_u->ext_u = 0; - } - - return fon_u; -} - -/* _pier_play_send(): send a batch of events to the worker for replay. -*/ -static void -_pier_play_send(u3_play* pay_u) -{ - u3_pier* pir_u = pay_u->pir_u; - c3_w len_w; - - // awaiting read - // - if ( !pay_u->ext_u ) { - return; - } - - // XX fill the pipe how much? - // (god_u->dep_w > PIER_WORK_BATCH) ) - // - - // the first batch must be >= the lifecycle barrier - // - if ( !pay_u->sen_d ) { - len_w = c3_max(pir_u->lif_w, PIER_PLAY_BATCH); - } - else { - c3_d lef_d = (pay_u->eve_d - pay_u->sen_d); - len_w = c3_min(lef_d, PIER_PLAY_BATCH); - } - - { - u3_info fon_u = _pier_play_next(pay_u, len_w); - - // bump sent counter - // - pay_u->sen_d = fon_u.ent_u->eve_d; - -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: play send %" PRIu64 "-%" PRIu64 "\r\n", fon_u.ext_u->eve_d, fon_u.ent_u->eve_d); -#endif - - u3_lord_play(pir_u->god_u, fon_u); - } -} - -/* _pier_play_read(): read events from disk for replay. -*/ -static void -_pier_play_read(u3_play* pay_u) -{ - u3_pier* pir_u = pay_u->pir_u; - c3_d las_d; - - if ( pay_u->ent_u ) { - las_d = pay_u->ent_u->eve_d; - - // cap the pir_u->pay_u queue depth - // - if ( (las_d - pay_u->ext_u->eve_d) >= PIER_PLAY_BATCH ) { - return; - } - } - else { - las_d = pay_u->sen_d; - } - - { - c3_d nex_d = (1ULL + las_d); - c3_d len_d = c3_min(pay_u->eve_d - las_d, PIER_READ_BATCH); - - if ( len_d - && (nex_d > pay_u->req_d) ) - { - u3_disk_read(pir_u->log_u, nex_d, len_d); - pay_u->req_d = nex_d; - -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: play read %" PRIu64 " at %" PRIu64 "\r\n", len_d, nex_d); -#endif - } - } -} - -/* _pier_play(): send a batch of events to the worker for log replay. -*/ -static void -_pier_play(u3_play* pay_u) -{ - u3_pier* pir_u = pay_u->pir_u; - u3_lord* god_u = pir_u->god_u; - u3_disk* log_u = pir_u->log_u; - - if ( god_u->eve_d == pay_u->eve_d ) { - // XX should be play_cb - // - u3l_log("---------------- playback complete ----------------"); - u3_term_stop_spinner(); - - if ( pay_u->eve_d < log_u->dun_d ) { - // u3l_log("pier: replay barrier reached, shutting down"); - // // XX graceful shutdown - // // - // u3_lord_save(pir_u->god_u); - // u3_pier_bail(pir_u); - // exit(0); - - // XX temporary hack - // - u3l_log("pier: replay barrier reached, cramming"); - u3_pier_cram(pir_u); - } - else if ( pay_u->eve_d == log_u->dun_d ) { - u3_lord_save(pir_u->god_u); - - // early exit, preparing for upgrade - // - // XX check kelvins? - // - if ( c3y == u3_Host.pep_o ) { - u3_pier_exit(pir_u); - } - else { - _pier_wyrd_init(pir_u); - } - } - } - else { - c3_assert( god_u->eve_d < pay_u->eve_d ); - _pier_play_send(pay_u); - _pier_play_read(pay_u); - } -} - -/* _pier_on_lord_play_done(): log replay batch completion from worker. -*/ -static void -_pier_on_lord_play_done(void* ptr_v, u3_info fon_u, c3_l mug_l) -{ - u3_pier* pir_u = ptr_v; - u3_fact* tac_u = fon_u.ent_u; - u3_fact* nex_u; - - c3_assert( u3_psat_play == pir_u->sat_e ); - - u3l_log("pier: (%" PRIu64 "): play: done", tac_u->eve_d); - - // XX optional - // - if ( tac_u->mug_l && (tac_u->mug_l != mug_l) ) { - u3l_log("pier: (%" PRIu64 "): play: mug mismatch %x %x", - tac_u->eve_d, - tac_u->mug_l, - mug_l); - // u3_pier_bail(pir_u); - } - - // dispose successful - // - { - tac_u = fon_u.ext_u; - - while ( tac_u ) { - nex_u = tac_u->nex_u; - u3_fact_free(tac_u); - tac_u = nex_u; - } - } - - _pier_play(pir_u->pay_u); -} - -/* _pier_on_lord_play_bail(): log replay batch failure from worker. -*/ -static void -_pier_on_lord_play_bail(void* ptr_v, u3_info fon_u, - c3_l mug_l, c3_d eve_d, u3_noun dud) -{ - u3_pier* pir_u = ptr_v; - - c3_assert( u3_psat_play == pir_u->sat_e ); - - { - u3_fact* tac_u = fon_u.ext_u; - u3_fact* nex_u; - c3_l las_l = 0; - - // dispose successful - // - while ( tac_u->eve_d <= eve_d ) { - nex_u = tac_u->nex_u; - las_l = tac_u->mug_l; - u3_fact_free(tac_u); - tac_u = nex_u; - } - - // XX optional - // - if ( las_l && (las_l != mug_l) ) { - u3l_log("pier: (%" PRIu64 "): play bail: mug mismatch %x %x", - (c3_d)(eve_d - 1ULL), - las_l, - mug_l); - // u3_pier_bail(pir_u); - } - - // XX enable to retry - // -#if 0 - { - u3l_log("pier: (%" PRIu64 "): play: retry", eve_d); - - fon_u.ext_u = tac_u; - - // we're enqueuing here directly onto the exit. - // like, _pier_play_plan() in reverse - // - if ( !pay_u->ext_u ) { - pay_u->ext_u = fon_u.ext_u; - pay_u->ent_u = fon_u.ent_u; - } - else { - fon_u.ent_u->nex_u = pay_u->ext_u; - pay_u->ext_u = fon_u.ext_u; - } - - _pier_play(pir_u->pay_u); - u3z(dud); - } -#else - { - u3l_log("pier: (%" PRIu64 "): play: bail", eve_d); - u3_pier_punt_goof("play", dud); - { - u3_noun wir, tag; - u3x_qual(tac_u->job, 0, &wir, &tag, 0); - u3_pier_punt_ovum("play", u3k(wir), u3k(tag)); - } - - u3_pier_bail(pir_u); - exit(1); - } -#endif - } -} - -/* _pier_play_init(): begin boot/replay up to [eve_d]. -*/ -static void -_pier_play_init(u3_pier* pir_u, c3_d eve_d) -{ - u3_lord* god_u = pir_u->god_u; - u3_disk* log_u = pir_u->log_u; - u3_play* pay_u; - - c3_assert( (u3_psat_init == pir_u->sat_e) - || (u3_psat_boot == pir_u->sat_e) ); - - c3_assert( eve_d > god_u->eve_d ); - c3_assert( eve_d <= log_u->dun_d ); - - pir_u->sat_e = u3_psat_play; - pir_u->pay_u = pay_u = c3_calloc(sizeof(*pay_u)); - pay_u->pir_u = pir_u; - pay_u->eve_d = eve_d; - pay_u->sen_d = god_u->eve_d; - - u3l_log("---------------- playback starting ----------------"); - if ( (1ULL + god_u->eve_d) == eve_d ) { - u3l_log("pier: replaying event %" PRIu64, eve_d); - } - else { - u3l_log("pier: replaying events %" PRIu64 "-%" PRIu64, - (c3_d)(1ULL + god_u->eve_d), - eve_d); - } - - u3_term_start_spinner(c3__play, c3n); - - _pier_play(pay_u); -} - -/* _pier_on_disk_read_done(): event log read success. -*/ -static void -_pier_on_disk_read_done(void* ptr_v, u3_info fon_u) -{ - u3_pier* pir_u = ptr_v; - - c3_assert( u3_psat_play == pir_u->sat_e ); - - _pier_play_plan(pir_u->pay_u, fon_u); - _pier_play(pir_u->pay_u); -} - -/* _pier_on_disk_read_bail(): event log read failure. -*/ -static void -_pier_on_disk_read_bail(void* ptr_v, c3_d eve_d) -{ - u3_pier* pir_u = ptr_v; - - c3_assert( u3_psat_play == pir_u->sat_e ); - - // XX s/b play_bail_cb - // - fprintf(stderr, "pier: disk read bail\r\n"); - u3_term_stop_spinner(); - u3_pier_bail(pir_u); -} - -/* _pier_on_disk_write_done(): event log write success. -*/ -static void -_pier_on_disk_write_done(void* ptr_v, c3_d eve_d) -{ - u3_pier* pir_u = ptr_v; - u3_disk* log_u = pir_u->log_u; - -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: (%" PRIu64 "): db commit: complete\r\n", eve_d); -#endif - - if ( u3_psat_boot == pir_u->sat_e ) { - // lord already live - // - if ( c3y == pir_u->god_u->liv_o ) { - // XX print bootstrap commit complete - // XX s/b boot_complete_cb - // - _pier_play_init(pir_u, log_u->dun_d); - } - } - else { - c3_assert( (u3_psat_work == pir_u->sat_e) - || (u3_psat_done == pir_u->sat_e) ); - - _pier_work(pir_u->wok_u); - } -} - -/* _pier_on_disk_write_bail(): event log write failure. -*/ -static void -_pier_on_disk_write_bail(void* ptr_v, c3_d eve_d) -{ - u3_pier* pir_u = ptr_v; - - if ( u3_psat_boot == pir_u->sat_e ) { - // XX nice message - // - } - - // XX - // - fprintf(stderr, "pier: disk write bail\r\n"); - u3_pier_bail(pir_u); -} - -/* _pier_on_lord_slog(): debug printf from worker. -*/ -static void -_pier_on_lord_slog(void* ptr_v, c3_w pri_w, u3_noun tan) -{ - u3_pier* pir_u = ptr_v; - - if ( 0 != pir_u->sog_f ) { - pir_u->sog_f(pir_u->sop_p, pri_w, u3k(tan)); - } - - u3_pier_tank(0, pri_w, tan); -} - -/* _pier_on_lord_save(): worker (non-portable) snapshot complete. -*/ -static void -_pier_on_lord_save(void* ptr_v) -{ - u3_pier* pir_u = ptr_v; - -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: (%" PRIu64 "): lord: save\r\n", pir_u->god_u->eve_d); -#endif - - // _pier_next(pir_u); -} - -/* _pier_on_lord_cram(): worker state-export complete (portable snapshot). -*/ -static void -_pier_on_lord_cram(void* ptr_v) -{ - u3_pier* pir_u = ptr_v; - -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: (%" PRIu64 "): lord: cram\r\n", pir_u->god_u->eve_d); -#endif - - // XX temporary hack - // - if ( u3_psat_play == pir_u->sat_e ) { - u3l_log("pier: cram complete, shutting down"); - u3_pier_bail(pir_u); - exit(0); - } - - // if ( u3_psat_done == pir_u->sat_e ) { - // fprintf(stderr, "snap cb exit\r\n"); - // u3_lord_exit(pir_u->god_u); - // } - // else { - // _pier_next(pir_u); - // } -} - -static void -_pier_done(u3_pier* pir_u); - -/* _pier_on_lord_exit(): worker shutdown. -*/ -static void -_pier_on_lord_exit(void* ptr_v) -{ - u3_pier* pir_u = ptr_v; - - // the lord has already gone - // - pir_u->god_u = 0; - - if ( u3_psat_done != pir_u->sat_e ) { - u3l_log("pier: serf shutdown unexpected"); - u3_pier_bail(pir_u); - } - // if we made it all the way here, it's our jab to wrap up - // - else { - _pier_done(pir_u); - } -} - -/* _pier_on_lord_bail(): worker error. -*/ -static void -_pier_on_lord_bail(void* ptr_v) -{ - u3_pier* pir_u = ptr_v; - - // the lord has already gone - // - pir_u->god_u = 0; - - u3_pier_bail(pir_u); -} - -/* _pier_on_lord_live(): worker is ready. -*/ -static void -_pier_on_lord_live(void* ptr_v) -{ - u3_pier* pir_u = ptr_v; - u3_lord* god_u = pir_u->god_u; - u3_disk* log_u = pir_u->log_u; - -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: (%" PRIu64 "): boot at mug %x\r\n", god_u->eve_d, god_u->mug_l); -#endif - - c3_assert( god_u->eve_d <= log_u->dun_d ); - - if ( u3_psat_boot == pir_u->sat_e ) { - // boot-sequence commit complete - // - if ( log_u->sen_d - && (log_u->sen_d == log_u->dun_d) ) { - // XX print bootstrap commit complete - // XX s/b boot_complete_cb - // - _pier_play_init(pir_u, log_u->dun_d); - } - } - else { - c3_assert( u3_psat_init == pir_u->sat_e ); - c3_assert( log_u->sen_d == log_u->dun_d ); - - if ( god_u->eve_d < log_u->dun_d ) { - c3_d eve_d; - - // XX revisit - // - if ( u3_Host.ops_u.til_c ) { - if ( 1 == sscanf(u3_Host.ops_u.til_c, "%" PRIu64 "", &eve_d) ) { - u3l_log("pier: replay till %" PRIu64, eve_d); - } - else { - u3l_log("pier: ignoring invalid replay barrier '%s'", - u3_Host.ops_u.til_c); - eve_d = log_u->dun_d; - } - } - else { - eve_d = log_u->dun_d; - } - - _pier_play_init(pir_u, eve_d); - } - else { - // early exit, preparing for upgrade - // - // XX check kelvins? - // - if ( c3y == u3_Host.pep_o ) { - u3_pier_exit(pir_u); - } - else { - _pier_wyrd_init(pir_u); - } - } - } -} - -/* u3_pier_mass(): construct a $mass branch with noun/list. -*/ -u3_noun -u3_pier_mass(u3_atom cod, u3_noun lit) -{ - return u3nt(cod, c3n, lit); -} - -/* u3_pier_mase(): construct a $mass leaf. -*/ -u3_noun -u3_pier_mase(c3_c* cod_c, u3_noun dat) -{ - return u3nt(u3i_string(cod_c), c3y, dat); -} - -/* u3_pier_info(): pier status info as noun. -*/ -u3_noun -u3_pier_info(u3_pier* pir_u) -{ - u3_noun nat; - - switch (pir_u->sat_e) { - default: { - nat = u3_pier_mass(u3i_string("state-unknown"), u3_nul); - } break; - - case u3_psat_init: { - nat = u3_pier_mass(c3__init, u3_nul); - } break; - - case u3_psat_boot: { - nat = u3_pier_mass(c3__boot, u3_nul); - } break; - - case u3_psat_play: { - u3_play* pay_u = pir_u->pay_u; - - nat = u3_pier_mass(c3__play, - u3i_list( - u3_pier_mase("target", u3i_chub(pay_u->eve_d)), - u3_pier_mase("sent", u3i_chub(pay_u->sen_d)), - u3_pier_mase("read", u3i_chub(pay_u->req_d)), - u3_none)); - } break; - - case u3_psat_work: { - u3_work* wok_u = pir_u->wok_u; - - nat = u3_pier_mass(c3__work, - u3i_list( - u3_pier_mase("effects-released", u3i_chub(wok_u->fec_u.rel_d)), - u3_pier_mase("pending-any", __(wok_u->fec_u.ext_u)), - u3_pier_mase("pending-start", - ( wok_u->fec_u.ext_u - ? u3i_chub(wok_u->fec_u.ext_u->eve_d) - : 0 )), - u3_pier_mase("pending-final", - ( wok_u->fec_u.ent_u - ? u3i_chub(wok_u->fec_u.ent_u->eve_d) - : 0 )), - u3_pier_mase("wall-any", __(wok_u->wal_u)), - u3_pier_mase("wall-event", - ( wok_u->wal_u - ? u3i_chub(wok_u->wal_u->eve_d) - : 0)), - u3_pier_mass(c3__auto, u3_auto_info(wok_u->car_u)), - u3_none)); - } break; - - case u3_psat_done: { - nat = u3_pier_mass(c3__done, u3_nul); - } break; - } - - return u3_pier_mass( - c3__pier, - u3i_list( - nat, - u3_disk_info(pir_u->log_u), - u3_lord_info(pir_u->god_u), - u3_none)); -} - -/* u3_pier_slog(): print status info. -*/ -void -u3_pier_slog(u3_pier* pir_u) -{ - switch ( pir_u->sat_e ) { - default: { - u3l_log("pier: unknown state: %u", pir_u->sat_e); - } break; - - case u3_psat_init: { - u3l_log("pier: init"); - } break; - - case u3_psat_boot: { - u3l_log("pier: boot"); - } break; - - case u3_psat_play: { - u3l_log("pier: play"); - - { - u3_play* pay_u = pir_u->pay_u; - - u3l_log(" target: %" PRIu64, pay_u->eve_d); - u3l_log(" sent: %" PRIu64, pay_u->sen_d); - u3l_log(" read: %" PRIu64, pay_u->req_d); - } - } break; - - case u3_psat_work: { - u3l_log("pier: work"); - - { - u3_work* wok_u = pir_u->wok_u; - - u3l_log(" effects: released=%" PRIu64, wok_u->fec_u.rel_d); - - if ( wok_u->fec_u.ext_u ) { - if ( wok_u->fec_u.ext_u != wok_u->fec_u.ent_u ) { - u3l_log(" pending %" PRIu64 "-%" PRIu64, - wok_u->fec_u.ext_u->eve_d, - wok_u->fec_u.ent_u->eve_d); - - } - else { - u3l_log(" pending %" PRIu64, wok_u->fec_u.ext_u->eve_d); - } - } - - if ( wok_u->wal_u ) { - u3l_log(" wall: %" PRIu64, wok_u->wal_u->eve_d); - } - - if ( wok_u->car_u ) { - u3_auto_slog(wok_u->car_u); - } - } - } break; - - case u3_psat_done: { - u3l_log("pier: done"); - } break; - } - - if ( pir_u->log_u ) { - u3_disk_slog(pir_u->log_u); - } - - if ( pir_u->god_u ) { - u3_lord_slog(pir_u->god_u); - } -} - -/* _pier_init(): create a pier, loading existing. -*/ -static u3_pier* -_pier_init(c3_w wag_w, c3_c* pax_c) -{ - // create pier - // - u3_pier* pir_u = c3_calloc(sizeof(*pir_u)); - - pir_u->pax_c = pax_c; - pir_u->sat_e = u3_psat_init; - pir_u->liv_o = c3n; - - // XX remove - // - pir_u->per_s = u3_Host.ops_u.per_s; - pir_u->pes_s = u3_Host.ops_u.pes_s; - pir_u->por_s = u3_Host.ops_u.por_s; - pir_u->sav_u = c3_calloc(sizeof(u3_save)); - - // initialize persistence - // - { - // XX load/set secrets - // - u3_disk_cb cb_u = { - .ptr_v = pir_u, - .read_done_f = _pier_on_disk_read_done, - .read_bail_f = _pier_on_disk_read_bail, - .write_done_f = _pier_on_disk_write_done, - .write_bail_f = _pier_on_disk_write_bail - }; - - if ( !(pir_u->log_u = u3_disk_init(pax_c, cb_u)) ) { - c3_free(pir_u); - return 0; - } - } - - // initialize compute - // - { - // XX load/set secrets - // - c3_d tic_d[1]; // ticket (unstretched) - c3_d sec_d[1]; // generator (unstretched) - c3_d key_d[4]; // secret (stretched) - - key_d[0] = key_d[1] = key_d[2] = key_d[3] = 0; - - u3_lord_cb cb_u = { - .ptr_v = pir_u, - .live_f = _pier_on_lord_live, - .spin_f = _pier_on_lord_work_spin, - .spun_f = _pier_on_lord_work_spun, - .slog_f = _pier_on_lord_slog, - .play_done_f = _pier_on_lord_play_done, - .play_bail_f = _pier_on_lord_play_bail, - .work_done_f = _pier_on_lord_work_done, - .work_bail_f = _pier_on_lord_work_bail, - .save_f = _pier_on_lord_save, - .cram_f = _pier_on_lord_cram, - .bail_f = _pier_on_lord_bail, - .exit_f = _pier_on_lord_exit - }; - - if ( !(pir_u->god_u = u3_lord_init(pax_c, wag_w, key_d, cb_u)) ) - { - // u3_disk_exit(pir_u->log_u) - c3_free(pir_u); - return 0; - } - } - - return pir_u; -} - -/* u3_pier_stay(): restart an existing pier. -*/ -u3_pier* -u3_pier_stay(c3_w wag_w, u3_noun pax) -{ - u3_pier* pir_u; - - if ( !(pir_u = _pier_init(wag_w, u3r_string(pax))) ) { - fprintf(stderr, "pier: stay: init fail\r\n"); - u3_king_bail(); - return 0; - } - - if ( c3n == u3_disk_read_meta(pir_u->log_u, pir_u->who_d, - &pir_u->fak_o, &pir_u->lif_w) ) - { - fprintf(stderr, "pier: disk read meta fail\r\n"); - // XX dispose - // - u3_pier_bail(pir_u); - exit(1); - } - - if ( c3y == u3_Host.ops_u.veb ) { - FILE* fil_u = u3_term_io_hija(); - u3_lmdb_stat(pir_u->log_u->mdb_u, fil_u); - u3_term_io_loja(1, fil_u); - } - - u3z(pax); - - return pir_u; -} - -/* _pier_pill_parse(): extract boot formulas and module/userspace ova from pill -*/ -static u3_boot -_pier_pill_parse(u3_noun pil) -{ - u3_boot bot_u; - u3_noun pil_p, pil_q; - - c3_assert( c3y == u3du(pil) ); - u3x_cell(pil, &pil_p, &pil_q); - - { - // XX use faster cue - // - u3_noun pro = u3m_soft(0, u3ke_cue, u3k(pil_p)); - u3_noun mot, tag, dat; - - if ( (c3n == u3r_trel(pro, &mot, &tag, &dat)) - || (u3_blip != mot) ) - { - u3m_p("mot", u3h(pro)); - fprintf(stderr, "boot: failed: unable to parse pill\r\n"); - u3_king_bail(); - exit(1); - } - - if ( c3y == u3r_sing_c("ivory", tag) ) { - fprintf(stderr, "boot: failed: unable to boot from ivory pill\r\n"); - u3_king_bail(); - exit(1); - } - else if ( c3__pill != tag ) { - if ( c3y == u3a_is_atom(tag) ) { - u3m_p("pill", tag); - } - fprintf(stderr, "boot: failed: unrecognized pill\r\n"); - u3_king_bail(); - exit(1); - } - - { - u3_noun typ; - c3_c* typ_c; - - if ( c3n == u3r_qual(dat, &typ, &bot_u.bot, &bot_u.mod, &bot_u.use) ) { - fprintf(stderr, "boot: failed: unable to extract pill\r\n"); - u3_king_bail(); - exit(1); - } - - if ( c3y == u3a_is_atom(typ) ) { - c3_c* typ_c = u3r_string(typ); - fprintf(stderr, "boot: parsing %%%s pill\r\n", typ_c); - c3_free(typ_c); - } - } - - u3k(bot_u.bot); u3k(bot_u.mod); u3k(bot_u.use); - u3z(pro); - } - - // optionally replace filesystem in userspace - // - if ( u3_nul != pil_q ) { - c3_w len_w = 0; - u3_noun ova = bot_u.use; - u3_noun new = u3_nul; - u3_noun ovo; - - while ( u3_nul != ova ) { - ovo = u3h(ova); - - u3_noun tag = u3h(u3t(ovo)); - if ( ( c3__into == tag ) || ( c3__park == tag ) ) { - c3_assert( 0 == len_w ); - len_w++; - ovo = u3t(pil_q); - } - - new = u3nc(u3k(ovo), new); - ova = u3t(ova); - } - - c3_assert( 1 == len_w ); - - u3z(bot_u.use); - bot_u.use = u3kb_flop(new); - } - - u3z(pil); - - return bot_u; -} - -/* _pier_boot_make(): construct boot sequence -*/ -static u3_boot -_pier_boot_make(u3_noun who, - u3_noun wyr, - u3_noun ven, - u3_noun pil, - u3_weak fed) -{ - u3_boot bot_u = _pier_pill_parse(pil); // transfer - - // prepend entropy and identity to the module sequence - // - { - u3_noun cad, wir = u3nt(u3_blip, c3__arvo, u3_nul); - c3_w eny_w[16]; - c3_rand(eny_w); - - cad = u3nt(c3__verb, u3_nul, ( c3y == u3_Host.ops_u.veb ) ? c3n : c3y); - bot_u.mod = u3nc(u3nc(u3k(wir), cad), bot_u.mod); - - cad = u3nc(c3__wack, u3i_words(16, eny_w)); - bot_u.mod = u3nc(u3nc(u3k(wir), cad), bot_u.mod); - - cad = u3nc(c3__whom, who); // transfer [who] - bot_u.mod = u3nc(u3nc(u3k(wir), cad), bot_u.mod); - - wir = u3nt(u3_blip, c3__arvo, u3_nul); - bot_u.mod = u3nc(u3nc(wir, wyr), bot_u.mod); // transfer [wir] and [wyr] - } - - // include additional key configuration events if we have multiple keys - // - if ( (u3_none != fed) && (c3y == u3du(u3h(fed))) ) { - u3_noun wir = u3nt(c3__j, c3__seed, u3_nul); - u3_noun tag = u3i_string("rekey"); - u3_noun kyz = u3t(u3t(fed)); - while ( u3_nul != kyz ) { - u3_noun cad = u3nc(u3k(tag), u3k(u3h(kyz))); - bot_u.use = u3nc(u3nc(u3k(wir), cad), bot_u.use); - kyz = u3t(kyz); - } - u3z(tag); u3z(wir); - } - - // prepend legacy boot event to the userspace sequence - // - { - // XX do something about this wire - // XX route directly to %jael? - // - c3_assert( c3y == u3a_is_cell(ven) ); - - u3_noun wir = u3nq(c3__d, c3__term, '1', u3_nul); - u3_noun cad = u3nt(c3__boot, u3_Host.ops_u.lit, ven); // transfer - - bot_u.use = u3nc(u3nc(wir, cad), bot_u.use); - } - - u3z(fed); - return bot_u; -} - -/* _pier_boot_plan(): construct and commit boot sequence -*/ -static c3_o -_pier_boot_plan(u3_pier* pir_u, - u3_noun who, - u3_noun ven, - u3_noun pil, - u3_weak fed) -{ - u3_boot bot_u; - { - pir_u->sat_e = u3_psat_boot; - pir_u->fak_o = ( c3__fake == u3h(ven) ) ? c3y : c3n; - u3r_chubs(0, 2, pir_u->who_d, who); - - bot_u = _pier_boot_make(who, _pier_wyrd_card(pir_u), ven, pil, fed); - pir_u->lif_w = u3qb_lent(bot_u.bot); - } - - if ( c3n == u3_disk_save_meta(pir_u->log_u, pir_u->who_d, - pir_u->fak_o, pir_u->lif_w) ) - { - // XX dispose bot_u - // - return c3n; - } - - // insert boot sequence directly - // - // Note that these are not ovum or (pair @da ovum) events, - // but raw nock formulas to be directly evaluated as the - // subject of the lifecycle formula [%2 [%0 3] %0 2]. - // All subsequent events will be (pair date ovum). - // - { - u3_noun fol = bot_u.bot; - - while ( u3_nul != fol ) { - u3_disk_boot_plan(pir_u->log_u, u3k(u3h(fol))); - fol = u3t(fol); - } - } - - // insert module and userspace events - // - { - u3_noun ova = bot_u.mod; - u3_noun bit = u3qc_bex(48); // 1/2^16 seconds - u3_noun now; - - { - struct timeval tim_tv; - gettimeofday(&tim_tv, 0); - now = u3_time_in_tv(&tim_tv); - } - - - while ( u3_nul != ova ) { - u3_disk_boot_plan(pir_u->log_u, u3nc(u3k(now), u3k(u3h(ova)))); - now = u3ka_add(now, u3k(bit)); - ova = u3t(ova); - } - - ova = bot_u.use; - - while ( u3_nul != ova ) { - u3_disk_boot_plan(pir_u->log_u, u3nc(u3k(now), u3k(u3h(ova)))); - now = u3ka_add(now, u3k(bit)); - ova = u3t(ova); - } - - u3z(bit); u3z(now); - } - - u3_disk_boot_save(pir_u->log_u); - - u3z(bot_u.bot); - u3z(bot_u.mod); - u3z(bot_u.use); - - return c3y; -} - -/* u3_pier_boot(): start a new pier. -*/ -u3_pier* -u3_pier_boot(c3_w wag_w, // config flags - u3_noun who, // identity - u3_noun ven, // boot event - u3_noun pil, // type-of/path-to pill - u3_noun pax, // path to pier - u3_weak fed) // extra private keys -{ - u3_pier* pir_u; - - if ( !(pir_u = _pier_init(wag_w, u3r_string(pax))) ) { - fprintf(stderr, "pier: boot: init fail\r\n"); - u3_king_bail(); - return 0; - } - - // XX must be called from on_lord_live - // - if ( c3n == _pier_boot_plan(pir_u, who, ven, pil, fed) ) { - fprintf(stderr, "pier: boot plan fail\r\n"); - // XX dispose - // - u3_pier_bail(pir_u); - exit(1); - } - - u3z(pax); - - return pir_u; -} - -/* _pier_save_cb(): save snapshot upon serf/disk synchronization. -*/ -static void -_pier_save_cb(void* ptr_v, c3_d eve_d) -{ - u3_pier* pir_u = ptr_v; - -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: (%" PRIu64 "): save: send at %" PRIu64 "\r\n", pir_u->god_u->eve_d, eve_d); -#endif - - u3_lord_save(pir_u->god_u); -} - -/* u3_pier_save(): save a non-portable snapshot -*/ -c3_o -u3_pier_save(u3_pier* pir_u) -{ -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: (%" PRIu64 "): save: plan\r\n", pir_u->god_u->eve_d); -#endif - if ( u3_psat_play == pir_u->sat_e ) { - u3_lord_save(pir_u->god_u); - return c3y; - } - - if ( u3_psat_work == pir_u->sat_e ) { - _pier_wall_plan(pir_u, 0, pir_u, _pier_save_cb); - return c3y; - } - - return c3n; -} - -/* _pier_cram_cb(): save snapshot upon serf/disk synchronization. -*/ -static void -_pier_cram_cb(void* ptr_v, c3_d eve_d) -{ - u3_pier* pir_u = ptr_v; - -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: (%" PRIu64 "): cram: send at %" PRIu64 "\r\n", pir_u->god_u->eve_d, eve_d); -#endif - - u3_lord_cram(pir_u->god_u); -} - -/* u3_pier_cram(): save a portable snapshot. -*/ -c3_o -u3_pier_cram(u3_pier* pir_u) -{ -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: (%" PRIu64 "): cram: plan\r\n", pir_u->god_u->eve_d); -#endif - - if ( u3_psat_play == pir_u->sat_e ) { - u3_lord_cram(pir_u->god_u); - return c3y; - } - - if ( u3_psat_work == pir_u->sat_e ) { - _pier_wall_plan(pir_u, 0, pir_u, _pier_cram_cb); - return c3y; - } - - return c3n; -} - -/* u3_pier_meld(): globally deduplicate persistent state. -*/ -void -u3_pier_meld(u3_pier* pir_u) -{ -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: (%" PRIu64 "): meld: plan\r\n", pir_u->god_u->eve_d); -#endif - - u3_lord_meld(pir_u->god_u); -} - -/* u3_pier_pack(): defragment persistent state. -*/ -void -u3_pier_pack(u3_pier* pir_u) -{ -#ifdef VERBOSE_PIER - fprintf(stderr, "pier: (%" PRIu64 "): meld: plan\r\n", pir_u->god_u->eve_d); -#endif - - u3_lord_pack(pir_u->god_u); -} - -/* _pier_work_close_cb(): dispose u3_work after closing handles. -*/ -static void -_pier_work_close_cb(uv_handle_t* idl_u) -{ - u3_work* wok_u = idl_u->data; - c3_free(wok_u); -} - -/* _pier_work_close(): close drivers/handles in the u3_psat_work state. -*/ -static void -_pier_work_close(u3_work* wok_u) -{ - u3_auto_exit(wok_u->car_u); - - // free pending effects - // - { - u3_gift* gif_u = wok_u->fec_u.ext_u; - u3_gift* nex_u; - - while ( gif_u ) { - nex_u = gif_u->nex_u; - u3_gift_free(gif_u); - gif_u = nex_u; - } - } - - uv_close((uv_handle_t*)&wok_u->pep_u, _pier_work_close_cb); - uv_close((uv_handle_t*)&wok_u->cek_u, 0); - uv_close((uv_handle_t*)&wok_u->idl_u, 0); - wok_u->pep_u.data = wok_u; -} - -/* _pier_done(): dispose pier. -*/ -static void -_pier_free(u3_pier* pir_u) -{ - c3_free(pir_u->pax_c); - - // XX remove - // - c3_free(pir_u->sav_u); - - c3_free(pir_u); -} - -/* _pier_done(): graceful shutdown complete, notify king. -*/ -static void -_pier_done(u3_pier* pir_u) -{ - // XX unlink properly - // - u3K.pir_u = 0; - _pier_free(pir_u); - u3_king_done(); -} - -/* _pier_exit(): synchronous shutdown. -*/ -static void -_pier_exit(u3_pier* pir_u) -{ - c3_assert( u3_psat_done == pir_u->sat_e ); - - if ( pir_u->log_u ) { - u3_disk_exit(pir_u->log_u); - pir_u->log_u = 0; - } - - if ( pir_u->god_u ) { - u3_lord_exit(pir_u->god_u); - pir_u->god_u = 0; - } - else { - // otherwise called in _pier_on_lord_exit() - // - _pier_done(pir_u); - } -} - -/* _pier_work_exit(): commence graceful shutdown. -*/ -static void -_pier_work_exit_cb(void* ptr_v, c3_d eve_d) -{ - u3_pier* pir_u = ptr_v; - - _pier_work_close(pir_u->wok_u); - pir_u->wok_u = 0; - - _pier_exit(pir_u); -} - -/* _pier_work_exit(): setup graceful shutdown callbacks. -*/ -static void -_pier_work_exit(u3_pier* pir_u) -{ - _pier_wall_plan(pir_u, 0, pir_u, _pier_save_cb); - _pier_wall_plan(pir_u, 0, pir_u, _pier_work_exit_cb); - - // XX moveme, XX bails if not started - // - { - c3_l cod_l = u3a_lush(c3__save); - u3_save_io_exit(pir_u); - u3a_lop(cod_l); - } - - pir_u->sat_e = u3_psat_done; -} - -/* u3_pier_exit(): graceful shutdown. -*/ -void -u3_pier_exit(u3_pier* pir_u) -{ - switch ( pir_u->sat_e ) { - default: { - fprintf(stderr, "pier: unknown exit: %u\r\n", pir_u->sat_e); - c3_assert(0); - } - - case u3_psat_done: return; - - case u3_psat_work: return _pier_work_exit(pir_u); - - case u3_psat_init: break; - - case u3_psat_boot: { - // XX properly dispose boot - // XX also on actual boot - // - c3_free(pir_u->bot_u); - pir_u->bot_u = 0; - } break; - - case u3_psat_play: { - // XX dispose play q - // - c3_free(pir_u->pay_u); - pir_u->pay_u = 0; - } break; - } - - pir_u->sat_e = u3_psat_done; - _pier_exit(pir_u); -} - -/* u3_pier_bail(): immediately shutdown due to error. -*/ -void -u3_pier_bail(u3_pier* pir_u) -{ - u3_Host.xit_i = 1; - - // halt serf - // - if ( pir_u->god_u ) { - u3_lord_halt(pir_u->god_u); - pir_u->god_u = 0; - } - - // exig i/o drivers - // - if ( (u3_psat_work == pir_u->sat_e) - && pir_u->wok_u ) - { - _pier_work_close(pir_u->wok_u); - pir_u->wok_u = 0; - } - - // close db - // - if ( pir_u->log_u ) { - u3_disk_exit(pir_u->log_u); - pir_u->log_u = 0; - } - - pir_u->sat_e = u3_psat_done; - - _pier_done(pir_u); -} - -/* c3_rand(): fill a 512-bit (16-word) buffer. -*/ -void -c3_rand(c3_w* rad_w) -{ - if ( 0 != ent_getentropy(rad_w, 64) ) { - fprintf(stderr, "c3_rand getentropy: %s\n", strerror(errno)); - // XX review - // - u3_king_bail(); - } -} - -/* _pier_dump_tape(): dump a tape, old style. Don't do this. -*/ -static void -_pier_dump_tape(FILE* fil_u, u3_noun tep) -{ - u3_noun tap = tep; - - while ( c3y == u3du(tap) ) { - c3_c car_c; - - // XX this utf-8 caution is unwarranted - // - // we already write() utf8 directly to streams in term.c - // - // if ( u3h(tap) >= 127 ) { - // car_c = '?'; - // } else - car_c = u3h(tap); - - putc(car_c, fil_u); - tap = u3t(tap); - } - - u3z(tep); -} - -/* _pier_dump_wall(): dump a wall, old style. Don't do this. -*/ -static void -_pier_dump_wall(FILE* fil_u, u3_noun wol) -{ - u3_noun wal = wol; - - while ( u3_nul != wal ) { - _pier_dump_tape(fil_u, u3k(u3h(wal))); - - wal = u3t(wal); - - if ( u3_nul != wal ) { - putc(13, fil_u); - putc(10, fil_u); - } - } - - u3z(wol); -} - -/* u3_pier_tank(): dump single tank. -*/ -void -u3_pier_tank(c3_l tab_l, c3_w pri_w, u3_noun tac) -{ - u3_noun blu = u3_term_get_blew(0); - c3_l col_l = u3h(blu); - FILE* fil_u = u3_term_io_hija(); - - // XX temporary, for urb.py test runner - // - if ( c3y == u3_Host.ops_u.dem ) { - fil_u = stderr; - } - - if ( c3n == u3_Host.ops_u.tem ) { - switch ( pri_w ) { - case 3: fprintf(fil_u, "\033[31m>>> "); break; - case 2: fprintf(fil_u, "\033[33m>> "); break; - case 1: fprintf(fil_u, "\033[32m> "); break; - case 0: fprintf(fil_u, "\033[90m" ); break; - } - } - else { - switch ( pri_w ) { - case 3: fprintf(fil_u, ">>> "); break; - case 2: fprintf(fil_u, ">> "); break; - case 1: fprintf(fil_u, "> "); break; - } - } - - // if we have no arvo kernel and can't evaluate nock - // only print %leaf tanks - // - if ( 0 == u3A->roc ) { - if ( c3__leaf == u3h(tac) ) { - _pier_dump_tape(fil_u, u3k(u3t(tac))); - } - } - // We are calling nock here, but hopefully need no protection. - // - else { - u3_noun wol = u3dc("wash", u3nc(tab_l, col_l), u3k(tac)); - - _pier_dump_wall(fil_u, wol); - } - - if ( c3n == u3_Host.ops_u.tem ) { - fprintf(fil_u, "\033[0m"); - } - - fflush(fil_u); - - u3_term_io_loja(0, fil_u); - u3z(blu); - u3z(tac); -} - -/* u3_pier_punt(): dump tank list. -*/ -void -u3_pier_punt(c3_l tab_l, u3_noun tac) -{ - u3_noun cat = tac; - - while ( c3y == u3r_du(cat) ) { - u3_pier_tank(tab_l, 0, u3k(u3h(cat))); - cat = u3t(cat); - } - - u3z(tac); -} - -/* u3_pier_punt_goof(): dump a [mote tang] crash report. -*/ -void -u3_pier_punt_goof(const c3_c* cap_c, u3_noun dud) -{ - u3_noun bud = dud; - u3_noun mot, tan; - - u3x_cell(dud, &mot, &tan); - - u3l_log(""); - u3_pier_punt(0, u3qb_flop(tan)); - - { - c3_c* mot_c = u3r_string(mot); - u3l_log("%s: bail: %%%s", cap_c, mot_c); - c3_free(mot_c); - } - - u3z(bud); -} - -/* u3_pier_punt_ovum(): print ovum details. -*/ -void -u3_pier_punt_ovum(const c3_c* cap_c, u3_noun wir, u3_noun tag) -{ - c3_c* tag_c = u3r_string(tag); - u3_noun riw = u3do("spat", wir); - c3_c* wir_c = u3r_string(riw); - - u3l_log("%s: %%%s event on %s failed", cap_c, tag_c, wir_c); - - c3_free(tag_c); - c3_free(wir_c); - u3z(riw); -} - -/* u3_pier_sway(): print trace. -*/ -void -u3_pier_sway(c3_l tab_l, u3_noun tax) -{ - u3_noun mok = u3dc("mook", 2, tax); - - u3_pier_punt(tab_l, u3k(u3t(mok))); - u3z(mok); -} - -/* u3_pier_mark(): mark all Loom allocations in all u3_pier structs. -*/ -c3_w -u3_pier_mark(FILE* fil_u) -{ - return 0; -} diff --git a/pkg/urbit/vere/save.c b/pkg/urbit/vere/save.c deleted file mode 100644 index 956d750cc..000000000 --- a/pkg/urbit/vere/save.c +++ /dev/null @@ -1,63 +0,0 @@ -/* vere/save.c -** -*/ -#include "all.h" -#include "vere/vere.h" - -/* _save_time_cb(): timer callback. -*/ -static void -_save_time_cb(uv_timer_t* tim_u) -{ - u3_pier *pir_u = tim_u->data; - u3_pier_save(pir_u); -} - -#if 0 -/* u3_save_ef_chld(): report save termination. -*/ -void -u3_save_ef_chld(u3_pier *pir_u) -{ - u3_save* sav_u = pir_u->sav_u; - c3_i loc_i; - c3_w pid_w; - - /* modified for cases with no pid_w - */ - u3l_log("checkpoint: complete %d", sav_u->pid_w); - pid_w = wait(&loc_i); - if (0 != sav_u->pid_w) { - c3_assert(pid_w == sav_u->pid_w); - } - else { - c3_assert(pid_w > 0); - } - sav_u->pid_w = 0; -} -#endif - -/* u3_save_io_init(): initialize autosave. -*/ -void -u3_save_io_init(u3_pier *pir_u) -{ - u3_save* sav_u = pir_u->sav_u; - - sav_u->req_d = 0; - sav_u->dun_d = 0; - sav_u->pid_w = 0; - - sav_u->tim_u.data = pir_u; - uv_timer_init(u3L, &sav_u->tim_u); - uv_timer_start(&sav_u->tim_u, _save_time_cb, 120000, 120000); -} - -/* u3_save_io_exit(): terminate save I/O. -*/ -void -u3_save_io_exit(u3_pier *pir_u) -{ - u3_save* sav_u = pir_u->sav_u; - uv_close((uv_handle_t*)&sav_u->tim_u, 0); -} diff --git a/pkg/urbit/vere/time.c b/pkg/urbit/vere/time.c deleted file mode 100644 index 6e41c1e56..000000000 --- a/pkg/urbit/vere/time.c +++ /dev/null @@ -1,170 +0,0 @@ -/* vere/time.c -** -*/ -#include "all.h" -#include "vere/vere.h" - -/* u3_time_sec_in(): urbit seconds from unix time. -** -** Adjust for future leap secs! -*/ -c3_d -u3_time_sec_in(c3_w unx_w) -{ - return 0x8000000cce9e0d80ULL + (c3_d)unx_w; -} - -/* u3_time_sec_out(): unix time from urbit seconds. -** -** Adjust for future leap secs! -*/ -c3_w -u3_time_sec_out(c3_d urs_d) -{ - c3_d adj_d = (urs_d - 0x8000000cce9e0d80ULL); - - if ( adj_d > 0xffffffffULL ) { - fprintf(stderr, "Agh! It's 2106! And no one's fixed this shite!\n"); - exit(1); - } - return (c3_w)adj_d; -} - -/* u3_time_fsc_in(): urbit fracto-seconds from unix microseconds. -*/ -c3_d -u3_time_fsc_in(c3_w usc_w) -{ - c3_d usc_d = usc_w; - - return ((usc_d * 65536ULL) / 1000000ULL) << 48ULL; -} - -/* u3_time_fsc_out: unix microseconds from urbit fracto-seconds. -*/ -c3_w -u3_time_fsc_out(c3_d ufc_d) -{ - return (c3_w) (((ufc_d >> 48ULL) * 1000000ULL) / 65536ULL); -} - -/* u3_time_msc_out: unix microseconds from urbit fracto-seconds. -*/ -c3_w -u3_time_msc_out(c3_d ufc_d) -{ - return (c3_w) (((ufc_d >> 48ULL) * 1000ULL) / 65536ULL); -} - -/* u3_time_in_tv(): urbit time from struct timeval. -*/ -u3_atom -u3_time_in_tv(struct timeval* tim_tv) -{ - c3_w unx_w = tim_tv->tv_sec; - c3_w usc_w = tim_tv->tv_usec; - c3_d cub_d[2]; - - cub_d[0] = u3_time_fsc_in(usc_w); - cub_d[1] = u3_time_sec_in(unx_w); - - return u3i_chubs(2, cub_d); -} - -/* u3_time_out_tv(): struct timeval from urbit time. -*/ -void -u3_time_out_tv(struct timeval* tim_tv, u3_noun now) -{ - c3_d ufc_d = u3r_chub(0, now); - c3_d urs_d = u3r_chub(1, now); - - tim_tv->tv_sec = u3_time_sec_out(urs_d); - tim_tv->tv_usec = u3_time_fsc_out(ufc_d); - - u3z(now); -} - -/* u3_time_in_ts(): urbit time from struct timespec. -*/ -u3_atom -u3_time_in_ts(struct timespec* tim_ts) -{ - struct timeval tim_tv; - - tim_tv.tv_sec = tim_ts->tv_sec; - tim_tv.tv_usec = (tim_ts->tv_nsec / 1000); - - return u3_time_in_tv(&tim_tv); -} - -#if defined(U3_OS_linux) || defined(U3_OS_mingw) -/* u3_time_t_in_ts(): urbit time from time_t. -*/ -u3_atom -u3_time_t_in_ts(time_t tim) -{ - struct timeval tim_tv; - - tim_tv.tv_sec = tim; - tim_tv.tv_usec = 0; - - return u3_time_in_tv(&tim_tv); -} -#endif // defined(U3_OS_linux) || defined(U3_OS_mingw) - -/* u3_time_out_ts(): struct timespec from urbit time. -*/ -void -u3_time_out_ts(struct timespec* tim_ts, u3_noun now) -{ - struct timeval tim_tv; - - u3_time_out_tv(&tim_tv, now); - - tim_ts->tv_sec = tim_tv.tv_sec; - tim_ts->tv_nsec = (tim_tv.tv_usec * 1000); -} - -/* u3_time_gap_ms(): (wen - now) in ms. -*/ -c3_d -u3_time_gap_ms(u3_noun now, u3_noun wen) -{ - if ( c3n == u3ka_gth(u3k(wen), u3k(now)) ) { - u3z(wen); u3z(now); - return 0ULL; - } - else { - u3_noun dif = u3ka_sub(wen, now); - c3_d fsc_d = u3r_chub(0, dif); - c3_d sec_d = u3r_chub(1, dif); - - u3z(dif); - return (sec_d * 1000ULL) + u3_time_msc_out(fsc_d); - } -} - -/* u3_time_gap_double(): (wen - now) in libev resolution. -*/ -double -u3_time_gap_double(u3_noun now, u3_noun wen) -{ - mpz_t now_mp, wen_mp, dif_mp; - double sec_g = (((double)(1ULL << 32ULL)) * ((double)(1ULL << 32ULL))); - double gap_g, dif_g; - - u3r_mp(now_mp, now); - u3r_mp(wen_mp, wen); - mpz_init(dif_mp); - mpz_sub(dif_mp, wen_mp, now_mp); - - u3z(now); - u3z(wen); - - dif_g = mpz_get_d(dif_mp) / sec_g; - gap_g = (dif_g > 0.0) ? dif_g : 0.0; - mpz_clear(dif_mp); mpz_clear(wen_mp); mpz_clear(now_mp); - - return gap_g; -} diff --git a/pkg/urbit/vere/ward.c b/pkg/urbit/vere/ward.c deleted file mode 100644 index f0c426020..000000000 --- a/pkg/urbit/vere/ward.c +++ /dev/null @@ -1,241 +0,0 @@ -/* vere/ward.c -*/ -#include "all.h" -#include "vere/vere.h" - -// ward: lifecycle management for common structures -// -// should contain anything allocated in multiple modules, -// or allocated in one and freed in another -// - -/* u3_dent_init(): initialize file record. -*/ -u3_dent* -u3_dent_init(const c3_c* nam_c) -{ - u3_dent *det_u = c3_malloc(sizeof(*det_u)); - det_u->nex_u = 0; - det_u->nam_c = c3_malloc(1 + strlen(nam_c)); - strcpy(det_u->nam_c, nam_c); - - return det_u; -} - -/* u3_dent_free(): dispose file record. -*/ -void -u3_dent_free(u3_dent *det_u) -{ - c3_free(det_u->nam_c); - c3_free(det_u); -} - -/* u3_dire_init(): initialize directory record. -*/ -u3_dire* -u3_dire_init(const c3_c* pax_c) -{ - u3_dire *dir_u = c3_malloc(sizeof *dir_u); - dir_u->all_u = 0; - dir_u->pax_c = c3_malloc(1 + strlen(pax_c)); - strcpy(dir_u->pax_c, pax_c); - - return dir_u; -} - -/* u3_dire_free(): dispose directory record. -*/ -void -u3_dire_free(u3_dire *dir_u) -{ - { - u3_dent *det_u = dir_u->all_u; - u3_dent *nex_u; - - while ( det_u ) { - nex_u = det_u->nex_u; - u3_dent_free(det_u); - det_u = nex_u; - } - } - - c3_free(dir_u->pax_c); - c3_free(dir_u); -} - -/* u3_fact_init(): initialize completed event. -*/ -u3_fact* -u3_fact_init(c3_d eve_d, c3_l mug_l, u3_noun job) -{ - u3_fact *tac_u = c3_malloc(sizeof(*tac_u)); - tac_u->eve_d = eve_d; - tac_u->mug_l = mug_l; - tac_u->nex_u = 0; - tac_u->job = job; - - return tac_u; -} - -/* u3_fact_free(): dispose completed event. -*/ -void -u3_fact_free(u3_fact *tac_u) -{ - u3z(tac_u->job); - c3_free(tac_u); -} - -/* u3_gift_init(): initialize effect list. -*/ -u3_gift* -u3_gift_init(c3_d eve_d, u3_noun act) -{ - u3_gift *gif_u = c3_malloc(sizeof(*gif_u)); - gif_u->eve_d = eve_d; - gif_u->nex_u = 0; - gif_u->act = act; - - return gif_u; -} - -/* u3_gift_free(): dispose effect list. -*/ -void -u3_gift_free(u3_gift *gif_u) -{ - u3z(gif_u->act); - c3_free(gif_u); -} - -/* u3_ovum_init: initialize an unlinked potential event -*/ -u3_ovum* -u3_ovum_init(c3_w mil_w, - u3_noun tar, - u3_noun wir, - u3_noun cad) -{ - u3_ovum* egg_u = c3_malloc(sizeof(*egg_u)); - egg_u->car_u = 0; - egg_u->try_w = 0; - egg_u->ptr_v = 0; - egg_u->mil_w = mil_w; - egg_u->tar = tar; - egg_u->wir = wir; - egg_u->cad = cad; - - egg_u->pre_u = egg_u->nex_u = 0; - - egg_u->cb_u.news_f = 0; - egg_u->cb_u.bail_f = 0; - - // spinner defaults - // - egg_u->pin_u.lab = u3k(u3h(wir)); - egg_u->pin_u.del_o = c3y; - - return egg_u; -} - -/* u3_ovum_free: dispose an unlinked potential event -*/ -void -u3_ovum_free(u3_ovum *egg_u) -{ - u3z(egg_u->pin_u.lab); - u3z(egg_u->tar); - u3z(egg_u->wir); - u3z(egg_u->cad); - - c3_free(egg_u); -} - -/* u3_pico_init(): initialize a scry request struct -*/ -u3_pico* -u3_pico_init() -{ - u3_pico* pic_u = c3_calloc(sizeof(*pic_u)); - return pic_u; -} - -/* u3_pico_free(): dispose a scry request struct -*/ -void -u3_pico_free(u3_pico* pic_u) -{ - u3z(pic_u->gan); - - switch ( pic_u->typ_e ) { - default: c3_assert(0); - - case u3_pico_full: { - u3z(pic_u->ful); - } break; - - case u3_pico_once: { - u3z(pic_u->las_u.des); - u3z(pic_u->las_u.pax); - } break; - } - - c3_free(pic_u); -} - -/* u3_mcut_char(): measure/cut character. -*/ -c3_w -u3_mcut_char(c3_c* buf_c, c3_w len_w, c3_c chr_c) -{ - if ( buf_c ) { - buf_c[len_w] = chr_c; - } - return len_w + 1; -} - -/* u3_mcut_cord(): measure/cut cord. -*/ -c3_w -u3_mcut_cord(c3_c* buf_c, c3_w len_w, u3_noun san) -{ - c3_w ten_w = u3r_met(3, san); - - if ( buf_c ) { - u3r_bytes(0, ten_w, (c3_y *)(buf_c + len_w), san); - } - u3z(san); - return (len_w + ten_w); -} - -/* u3_mcut_path(): measure/cut cord list. -*/ -c3_w -u3_mcut_path(c3_c* buf_c, c3_w len_w, c3_c sep_c, u3_noun pax) -{ - u3_noun axp = pax; - - while ( u3_nul != axp ) { - u3_noun h_axp = u3h(axp); - - len_w = u3_mcut_cord(buf_c, len_w, u3k(h_axp)); - axp = u3t(axp); - - if ( u3_nul != axp ) { - len_w = u3_mcut_char(buf_c, len_w, sep_c); - } - } - u3z(pax); - return len_w; -} - -/* u3_mcut_host(): measure/cut host. -*/ -c3_w -u3_mcut_host(c3_c* buf_c, c3_w len_w, u3_noun hot) -{ - len_w = u3_mcut_path(buf_c, len_w, '.', u3kb_flop(u3k(hot))); - u3z(hot); - return len_w; -} diff --git a/pkg/urbit/version b/pkg/urbit/version deleted file mode 100644 index 07fe6f6c9..000000000 --- a/pkg/urbit/version +++ /dev/null @@ -1 +0,0 @@ -1.15 \ No newline at end of file diff --git a/pkg/urbit/worker/serf.c b/pkg/urbit/worker/serf.c deleted file mode 100644 index ec20a32ec..000000000 --- a/pkg/urbit/worker/serf.c +++ /dev/null @@ -1,1133 +0,0 @@ -/* worker/serf.c -*/ -#include "all.h" -#include -#include - -/* -|% -:: +writ: from king to serf -:: -:: next steps: -:: - %peek persistent dates (in arvo or serf)? -:: - |mass should be a query of the serf directly -:: - add duct or vane stack for spinner -:: -+$ writ - $% $: %live - $% [%cram eve=@] - [%exit cod=@] - [%save eve=@] - [%meld ~] - [%pack ~] - == == - [%peek mil=@ sam=*] :: gang (each path $%([%once @tas @tas path] [beam @tas beam])) - [%play eve=@ lit=(list ?((pair @da ovum) *))] - [%work mil=@ job=(pair @da ovum)] - == -:: +plea: from serf to king -:: -+$ plea - $% [%live ~] - [%ripe [pro=%1 hon=@ nok=@] eve=@ mug=@] - [%slog pri=@ tank] - [%flog cord] - $: %peek - $% [%done dat=(unit (cask))] - [%bail dud=goof] - == == - $: %play - $% [%done mug=@] - [%bail eve=@ mug=@ dud=goof] - == == - $: %work - $% [%done eve=@ mug=@ fec=(list ovum)] - [%swap eve=@ mug=@ job=(pair @da ovum) fec=(list ovum)] - [%bail lud=(list goof)] - == == - == --- -*/ - -/* _serf_space(): print n spaces. -*/ -static void -_serf_space(FILE* fil_u, c3_w n) -{ - for (; n > 0; n--) - (fprintf(fil_u," ")); -} - -/* _serf_print_memory(): print memory amount. -** -** Helper for _serf_prof(), just an un-captioned u3a_print_memory(). -*/ -static void -_serf_print_memory(FILE* fil_u, c3_w wor_w) -{ - c3_w byt_w = (wor_w * 4); - c3_w gib_w = (byt_w / 1000000000); - c3_w mib_w = (byt_w % 1000000000) / 1000000; - c3_w kib_w = (byt_w % 1000000) / 1000; - c3_w bib_w = (byt_w % 1000); - - if ( gib_w ) { - (fprintf(fil_u, "GB/%d.%03d.%03d.%03d\r\n", - gib_w, mib_w, kib_w, bib_w)); - } - else if ( mib_w ) { - (fprintf(fil_u, "MB/%d.%03d.%03d\r\n", mib_w, kib_w, bib_w)); - } - else if ( kib_w ) { - (fprintf(fil_u, "KB/%d.%03d\r\n", kib_w, bib_w)); - } - else { - (fprintf(fil_u, "B/%d\r\n", bib_w)); - } -} - -/* _serf_prof(): print memory profile. RETAIN. -*/ -c3_w -_serf_prof(FILE* fil_u, c3_w den, u3_noun mas) -{ - c3_w tot_w = 0; - u3_noun h_mas, t_mas; - - if ( c3n == u3r_cell(mas, &h_mas, &t_mas) ) { - _serf_space(fil_u, den); - fprintf(fil_u, "mistyped mass\r\n"); - return tot_w; - } - else if ( _(u3du(h_mas)) ) { - _serf_space(fil_u, den); - fprintf(fil_u, "mistyped mass head\r\n"); - { - c3_c* lab_c = u3m_pretty(h_mas); - fprintf(fil_u, "h_mas: %s", lab_c); - c3_free(lab_c); - } - return tot_w; - } - else { - _serf_space(fil_u, den); - - { - c3_c* lab_c = u3m_pretty(h_mas); - fprintf(fil_u, "%s: ", lab_c); - c3_free(lab_c); - } - - u3_noun it_mas, tt_mas; - - if ( c3n == u3r_cell(t_mas, &it_mas, &tt_mas) ) { - fprintf(fil_u, "mistyped mass tail\r\n"); - return tot_w; - } - else if ( c3y == it_mas ) { - tot_w += u3a_mark_noun(tt_mas); - _serf_print_memory(fil_u, tot_w); - -#if 1 - /* The basic issue here is that tt_mas is included in .sac - * (the whole profile), so they can't both be roots in the - * normal sense. When we mark .sac later on, we want tt_mas - * to appear unmarked, but its children should be already - * marked. - */ - if ( _(u3a_is_dog(tt_mas)) ) { - u3a_box* box_u = u3a_botox(u3a_to_ptr(tt_mas)); -#ifdef U3_MEMORY_DEBUG - if ( 1 == box_u->eus_w ) { - box_u->eus_w = 0xffffffff; - } - else { - box_u->eus_w -= 1; - } -#else - if ( -1 == (c3_w)box_u->use_w ) { - box_u->use_w = 0x80000000; - } - else { - box_u->use_w += 1; - } -#endif - } -#endif - - return tot_w; - } - else if ( c3n == it_mas ) { - fprintf(fil_u, "\r\n"); - - while ( _(u3du(tt_mas)) ) { - tot_w += _serf_prof(fil_u, den+2, u3h(tt_mas)); - tt_mas = u3t(tt_mas); - } - - _serf_space(fil_u, den); - fprintf(fil_u, "--"); - _serf_print_memory(fil_u, tot_w); - - return tot_w; - - } - else { - _serf_space(fil_u, den); - fprintf(fil_u, "mistyped (strange) mass tail\r\n"); - return tot_w; - } - } -} - -/* _serf_grab(): garbage collect, checking for profiling. RETAIN. -*/ -static void -_serf_grab(u3_noun sac) -{ - if ( u3_nul == sac) { - if ( u3C.wag_w & (u3o_debug_ram | u3o_check_corrupt) ) { - u3m_grab(sac, u3_none); - } - } - else { - c3_w tot_w = 0; - FILE* fil_u; - -#ifdef U3_MEMORY_LOG - { - u3_noun wen = u3dc("scot", c3__da, u3k(u3A->now)); - c3_c* wen_c = u3r_string(wen); - - c3_c nam_c[2048]; - snprintf(nam_c, 2048, "%s/.urb/put/mass", u3P.dir_c); - - struct stat st; - if ( -1 == stat(nam_c, &st) ) { - c3_mkdir(nam_c, 0700); - } - - c3_c man_c[2054]; - snprintf(man_c, 2053, "%s/%s-serf.txt", nam_c, wen_c); - - fil_u = c3_fopen(man_c, "w"); - fprintf(fil_u, "%s\r\n", wen_c); - - c3_free(wen_c); - u3z(wen); - } -#else - { - fil_u = stderr; - } -#endif - - c3_assert( u3R == &(u3H->rod_u) ); - fprintf(fil_u, "\r\n"); - - tot_w += u3a_maid(fil_u, "total userspace", _serf_prof(fil_u, 0, sac)); - tot_w += u3m_mark(fil_u); - tot_w += u3a_maid(fil_u, "space profile", u3a_mark_noun(sac)); - - u3a_print_memory(fil_u, "total marked", tot_w); - u3a_print_memory(fil_u, "free lists", u3a_idle(u3R)); - u3a_print_memory(fil_u, "sweep", u3a_sweep()); - - fflush(fil_u); - -#ifdef U3_MEMORY_LOG - { - fclose(fil_u); - } -#endif - - u3z(sac); - - u3l_log(""); - } -} - -/* u3_serf_grab(): garbage collect. -*/ -void -u3_serf_grab(void) -{ - u3_noun sac = u3_nul; - - c3_assert( u3R == &(u3H->rod_u) ); - - { - u3_noun sam, gon; - - { - u3_noun pax = u3nc(c3__whey, u3_nul); - u3_noun lyc = u3nc(u3_nul, u3_nul); - sam = u3nt(lyc, c3n, u3nq(c3__once, u3_blip, u3_blip, pax)); - } - - gon = u3m_soft(0, u3v_peek, sam); - - { - u3_noun tag, dat, val; - u3x_cell(gon, &tag, &dat); - - if ( (u3_blip == tag) - && (u3_nul != dat) - && (c3y == u3r_pq(u3t(dat), c3__omen, 0, &val)) - && (c3y == u3r_p(val, c3__mass, &sac)) ) - { - u3k(sac); - } - } - - u3z(gon); - } - - fprintf(stderr, "serf: measuring memory:\r\n"); - - if ( u3_nul != sac ) { - _serf_grab(sac); - } - else { - u3a_print_memory(stderr, "total marked", u3m_mark(stderr)); - u3a_print_memory(stderr, "free lists", u3a_idle(u3R)); - u3a_print_memory(stderr, "sweep", u3a_sweep()); - fprintf(stderr, "\r\n"); - } - - fflush(stderr); -} - -/* u3_serf_post(): update serf state post-writ. -*/ -void -u3_serf_post(u3_serf* sef_u) -{ - if ( c3y == sef_u->rec_o ) { - u3m_reclaim(); - sef_u->rec_o = c3n; - } - - // XX this runs on replay too, |mass s/b elsewhere - // - if ( c3y == sef_u->mut_o ) { - _serf_grab(sef_u->sac); - sef_u->sac = u3_nul; - sef_u->mut_o = c3n; - } - - if ( c3y == sef_u->pac_o ) { - u3a_print_memory(stderr, "serf: pack: gained", u3m_pack()); - u3l_log(""); - sef_u->pac_o = c3n; - } -} - -/* _serf_sure_feck(): event succeeded, send effects. -*/ -static u3_noun -_serf_sure_feck(u3_serf* sef_u, c3_w pre_w, u3_noun vir) -{ - c3_o rec_o = c3n; - c3_o pac_o = c3n; - - // intercept |mass, observe |reset - // - { - u3_noun riv = vir; - c3_w i_w = 0; - - while ( u3_nul != riv ) { - u3_noun fec = u3t(u3h(riv)); - - // assumes a max of one %mass effect per event - // - if ( c3__mass == u3h(fec) ) { - // save a copy of the %mass data - // - sef_u->sac = u3k(u3t(fec)); - // replace the %mass data with ~ - // - // For efficient transmission to daemon. - // - riv = u3kb_weld(u3qb_scag(i_w, vir), - u3nc(u3nt(u3k(u3h(u3h(riv))), c3__mass, u3_nul), - u3qb_slag(1 + i_w, vir))); - u3z(vir); - vir = riv; - break; - } - - // reclaim memory from persistent caches on |reset - // - if ( c3__vega == u3h(fec) ) { - rec_o = c3y; - } - - riv = u3t(riv); - i_w++; - } - } - - // after a successful event, we check for memory pressure. - // - // if we've exceeded either of two thresholds, we reclaim - // from our persistent caches, and notify the daemon - // (via a "fake" effect) that arvo should trim state - // (trusting that the daemon will enqueue an appropriate event). - // For future flexibility, the urgency of the notification is represented - // by a *decreasing* number: 0 is maximally urgent, 1 less so, &c. - // - // high-priority: 2^22 contiguous words remaining (~8 MB) - // low-priority: 2^27 contiguous words remaining (~536 MB) - // XX maybe use 2^23 (~16 MB) and 2^26 (~268 MB? - // - // XX these thresholds should trigger notifications sent to the king - // instead of directly triggering these remedial actions. - // - { - u3_noun pri = u3_none; - c3_w pos_w = u3a_open(u3R); - c3_w low_w = (1 << 27); - c3_w hig_w = (1 << 22); - - if ( (pre_w > low_w) && !(pos_w > low_w) ) { - // XX set flag(s) in u3V so we don't repeat endlessly? - // - pac_o = c3y; - rec_o = c3y; - pri = 1; - } - else if ( (pre_w > hig_w) && !(pos_w > hig_w) ) { - pac_o = c3y; - rec_o = c3y; - pri = 0; - } - // reclaim memory from persistent caches periodically - // - // XX this is a hack to work two things - // - bytecode caches grow rapidly and can't be simply capped - // - we don't make very effective use of our free lists - // - else if ( 0 == (sef_u->dun_d % 1000ULL) ) { - rec_o = c3y; - } - - // notify daemon of memory pressure via "fake" effect - // - if ( u3_none != pri ) { - u3_noun cad = u3nc(u3nt(u3_blip, c3__arvo, u3_nul), - u3nc(c3__trim, pri)); - vir = u3nc(cad, vir); - } - } - - sef_u->rec_o = c3o(sef_u->rec_o, rec_o); - sef_u->pac_o = c3o(sef_u->pac_o, pac_o); - - return vir; -} - -/* _serf_sure_core(): event succeeded, save state. -*/ -static void -_serf_sure_core(u3_serf* sef_u, u3_noun cor) -{ - sef_u->dun_d = sef_u->sen_d; - - u3z(u3A->roc); - u3A->roc = cor; - u3A->eve_d = sef_u->dun_d; - sef_u->mug_l = u3r_mug(u3A->roc); - sef_u->mut_o = c3y; -} - -/* _serf_sure(): event succeeded, save state and process effects. -*/ -static u3_noun -_serf_sure(u3_serf* sef_u, c3_w pre_w, u3_noun par) -{ - // vir/(list ovum) list of effects - // cor/arvo arvo core - // - u3_noun vir, cor; - u3x_cell(par, &vir, &cor); - - _serf_sure_core(sef_u, u3k(cor)); - vir = _serf_sure_feck(sef_u, pre_w, u3k(vir)); - - u3z(par); - return vir; -} - -/* _serf_make_crud(): -*/ -static u3_noun -_serf_make_crud(u3_noun job, u3_noun dud) -{ - u3_noun now, ovo, new; - u3x_cell(job, &now, &ovo); - - new = u3nt(u3i_vint(u3k(now)), - u3nt(u3_blip, c3__arvo, u3_nul), - u3nt(c3__crud, dud, u3k(ovo))); - - u3z(job); - return new; -} - -/* _serf_poke(): RETAIN -*/ -static u3_noun -_serf_poke(u3_serf* sef_u, c3_c* cap_c, c3_w mil_w, u3_noun job) -{ - u3_noun now, ovo, wen, gon; - u3x_cell(job, &now, &ovo); - - wen = u3A->now; - u3A->now = u3k(now); - -#ifdef U3_EVENT_TIME_DEBUG - struct timeval b4; - c3_c* txt_c; - - gettimeofday(&b4, 0); - - { - u3_noun tag = u3h(u3t(ovo)); - txt_c = u3r_string(tag); - - if ( (c3__belt != tag) - && (c3__crud != tag) ) - { - u3l_log("serf: %s (%" PRIu64 ") %s", cap_c, sef_u->sen_d, txt_c); - } - } -#endif - - gon = u3m_soft(mil_w, u3v_poke, u3k(ovo)); - -#ifdef U3_EVENT_TIME_DEBUG - { - struct timeval f2, d0; - c3_w ms_w; - c3_w clr_w; - - gettimeofday(&f2, 0); - timersub(&f2, &b4, &d0); - - ms_w = (d0.tv_sec * 1000) + (d0.tv_usec / 1000); - clr_w = ms_w > 1000 ? 1 : ms_w < 100 ? 2 : 3; // red, green, yellow - - if ( clr_w != 2 ) { - u3l_log("\x1b[3%dm%%%s (%" PRIu64 ") %4d.%02dms\x1b[0m", - clr_w, txt_c, sef_u->sen_d, ms_w, - (int) (d0.tv_usec % 1000) / 10); - } - - c3_free(txt_c); - } -#endif - - if ( u3_blip != u3h(gon) ) { - u3z(u3A->now); - u3A->now = wen; - } - else { - u3z(wen); - } - - return gon; -} - -/* _serf_work(): apply event, capture effects. -*/ -static u3_noun -_serf_work(u3_serf* sef_u, c3_w mil_w, u3_noun job) -{ - u3_noun gon; - c3_w pre_w = u3a_open(u3R); - - // event numbers must be continuous - // - c3_assert( sef_u->sen_d == sef_u->dun_d); - sef_u->sen_d++; - - gon = _serf_poke(sef_u, "work", mil_w, job); // retain - - // event accepted - // - if ( u3_blip == u3h(gon) ) { - u3_noun vir = _serf_sure(sef_u, pre_w, u3k(u3t(gon))); - - u3z(gon); u3z(job); - return u3nc(c3__done, u3nt(u3i_chubs(1, &sef_u->dun_d), - sef_u->mug_l, - vir)); - } - // event rejected -- bad ciphertext - // - else if ( c3__evil == u3h(gon) ) { - sef_u->sen_d = sef_u->dun_d; - - u3z(job); - return u3nt(c3__bail, gon, u3_nul); - } - // event rejected - // - else { - // stash $goof from first crash - // - u3_noun dud = u3k(gon); - - // XX reclaim on %meme first? - // - - job = _serf_make_crud(job, dud); - gon = _serf_poke(sef_u, "crud", mil_w, job); // retain - - // error notification accepted - // - if ( u3_blip == u3h(gon) ) { - u3_noun vir = _serf_sure(sef_u, pre_w, u3k(u3t(gon))); - - u3z(gon); u3z(dud); - return u3nc(c3__swap, u3nq(u3i_chubs(1, &sef_u->dun_d), - sef_u->mug_l, - job, - vir)); - } - // error notification rejected - // - else { - sef_u->sen_d = sef_u->dun_d; - - // XX reclaim on %meme ? - // - - u3z(job); - return u3nq(c3__bail, gon, dud, u3_nul); - } - } -} - -/* u3_serf_work(): apply event, producing effects. -*/ -u3_noun -u3_serf_work(u3_serf* sef_u, c3_w mil_w, u3_noun job) -{ - c3_t tac_t = !!( u3C.wag_w & u3o_trace ); - c3_c lab_c[2056]; - u3_noun pro; - - // XX refactor tracing - // - if ( tac_t ) { - u3_noun wir = u3h(u3t(job)); - u3_noun cad = u3h(u3t(u3t(job))); - - { - c3_c* cad_c = u3m_pretty(cad); - c3_c* wir_c = u3m_pretty_path(wir); - snprintf(lab_c, 2056, "work [%s %s]", wir_c, cad_c); - c3_free(cad_c); - c3_free(wir_c); - } - - u3t_event_trace(lab_c, 'B'); - } - - // %work must be performed against an extant kernel - // - c3_assert( 0 != sef_u->mug_l); - - pro = u3nc(c3__work, _serf_work(sef_u, mil_w, job)); - - if ( tac_t ) { - u3t_event_trace(lab_c, 'E'); - } - - return pro; -} - -/* _serf_play_life(): -*/ -static u3_noun -_serf_play_life(u3_serf* sef_u, u3_noun eve) -{ - u3_noun gon; - - c3_assert( 0ULL == sef_u->sen_d ); - - { - u3_noun len = u3qb_lent(eve); - c3_assert( c3y == u3r_safe_chub(len, &sef_u->sen_d) ); - u3z(len); - } - - // ensure zero-initialized kernel - // - // XX assert? - // - u3A->roc = 0; - - gon = u3m_soft(0, u3v_life, eve); - - // lifecycle sequence succeeded - // - if ( u3_blip == u3h(gon) ) { - // save product as initial arvo kernel - // - _serf_sure_core(sef_u, u3k(u3t(gon))); - - u3z(gon); - return u3nc(c3__done, sef_u->mug_l); - } - // lifecycle sequence failed - // - else { - // send failure message and trace - // - sef_u->dun_d = sef_u->sen_d = 0; - - return u3nq(c3__bail, 0, 0, gon); - } -} - -/* _serf_play_poke(): RETAIN -*/ -static u3_noun -_serf_play_poke(u3_noun job) -{ - u3_noun now, ovo, wen, gon; - u3x_cell(job, &now, &ovo); - - wen = u3A->now; - u3A->now = u3k(now); - gon = u3m_soft(0, u3v_poke, u3k(ovo)); - - if ( u3_blip != u3h(gon) ) { - u3z(u3A->now); - u3A->now = wen; - } - else { - u3z(wen); - } - - return gon; -} - -/* _serf_play_list(): -*/ -static u3_noun -_serf_play_list(u3_serf* sef_u, u3_noun eve) -{ - c3_w pre_w = u3a_open(u3R); - u3_noun vev = eve; - u3_noun job, gon; - - while ( u3_nul != eve ) { - job = u3h(eve); - - // bump sent event counter - // - sef_u->sen_d++; - - gon = _serf_play_poke(job); - - // event succeeded, save and continue - // - if ( u3_blip == u3h(gon) ) { - // vir/(list ovum) list of effects - // cor/arvo arvo core - // - u3_noun vir, cor; - u3x_trel(gon, 0, &vir, &cor); - - _serf_sure_core(sef_u, u3k(cor)); - - // process effects to set u3_serf_post flags - // - u3z(_serf_sure_feck(sef_u, pre_w, u3k(vir))); - - u3z(gon); - - // skip |mass on replay - // - u3z(sef_u->sac); - sef_u->sac = u3_nul; - - eve = u3t(eve); - } - // event failed, stop and send trace - // - else { - // reset sent event counter - // - sef_u->sen_d = sef_u->dun_d; - - // XX reclaim on meme ? - // - - // send failure notification - // - u3z(vev); - return u3nc(c3__bail, u3nt(u3i_chubs(1, &sef_u->dun_d), - sef_u->mug_l, - gon)); - } - } - - u3z(vev); - return u3nc(c3__done, sef_u->mug_l); -} - -/* u3_serf_play(): apply event list, producing status. -*/ -u3_noun -u3_serf_play(u3_serf* sef_u, c3_d eve_d, u3_noun lit) -{ - c3_assert( eve_d == 1ULL + sef_u->sen_d ); - - // XX better condition for no kernel? - // - return u3nc(c3__play, ( 0ULL == sef_u->dun_d ) - ? _serf_play_life(sef_u, lit) - : _serf_play_list(sef_u, lit)); -} - -/* u3_serf_peek(): dereference namespace. -*/ -u3_noun -u3_serf_peek(u3_serf* sef_u, c3_w mil_w, u3_noun sam) -{ - u3_noun gon = u3m_soft(mil_w, u3v_peek, sam); - u3_noun pro; - - { - u3_noun tag, dat; - u3x_cell(gon, &tag, &dat); - - // read succeeded, produce result - // - if ( u3_blip == tag ) { - pro = u3nc(c3__done, u3k(dat)); - u3z(gon); - } - // read failed, produce trace - // - // NB, reads should *not* fail deterministically - // - else { - pro = u3nc(c3__bail, gon); - } - } - - return u3nc(c3__peek, pro); -} - -/* _serf_writ_live_exit(): exit on command. -*/ -static void -_serf_writ_live_exit(u3_serf* sef_u, c3_w cod_w) -{ - if ( u3C.wag_w & u3o_debug_cpu ) { - FILE* fil_u; - - { - u3_noun wen = u3dc("scot", c3__da, u3k(u3A->now)); - c3_c* wen_c = u3r_string(wen); - - c3_c nam_c[2048]; - snprintf(nam_c, 2048, "%s/.urb/put/profile", u3P.dir_c); - - struct stat st; - if ( -1 == stat(nam_c, &st) ) { - c3_mkdir(nam_c, 0700); - } - - c3_c man_c[2054]; - snprintf(man_c, 2053, "%s/%s.txt", nam_c, wen_c); - - fil_u = c3_fopen(man_c, "w"); - - c3_free(wen_c); - u3z(wen); - } - - u3t_damp(fil_u); - - { - fclose(fil_u); - } - } - - // XX move to jets.c - // - c3_free(u3D.ray_u); - - sef_u->xit_f(); - - exit(cod_w); -} - -/* _serf_writ_live_save(): save snapshot. -*/ -static void -_serf_writ_live_save(u3_serf* sef_u, c3_d eve_d) -{ - if( eve_d != sef_u->dun_d ) { - fprintf(stderr, "serf (%" PRIu64 "): save failed: %" PRIu64 "\r\n", - sef_u->dun_d, - eve_d); - exit(1); - } - - u3e_save(); -} - -/* u3_serf_live(): apply %live command [com], producing *ret on c3y. -*/ -c3_o -u3_serf_live(u3_serf* sef_u, u3_noun com, u3_noun* ret) -{ - u3_noun tag, dat; - - // refcounts around snapshots require special handling - // - if ( c3n == u3r_cell(com, &tag, &dat) ) { - u3z(com); - return c3n; - } - - switch ( tag ) { - default: { - u3z(com); - return c3n; - } - - case c3__exit: { - c3_y cod_y; - - if ( c3n == u3r_safe_byte(dat, &cod_y) ) { - u3z(com); - return c3n; - } - - u3z(com); - // NB, doesn't return - // - _serf_writ_live_exit(sef_u, cod_y); - *ret = u3nc(c3__live, u3_nul); - return c3y; - } - - // NB: the %cram $writ only saves the rock, it doesn't load it - // - case c3__cram: { - c3_d eve_d; - - if ( c3n == u3r_safe_chub(dat, &eve_d) ) { - u3z(com); - return c3n; - } - - u3z(com); - - if( eve_d != sef_u->dun_d ) { - fprintf(stderr, "serf (%" PRIu64 "): cram failed: %" PRIu64 "\r\n", - sef_u->dun_d, - eve_d); - return c3n; - } - - u3l_log("serf (%" PRIu64 "): saving rock", sef_u->dun_d); - - if ( c3n == u3u_cram(sef_u->dir_c, eve_d) ) { - fprintf(stderr, "serf (%" PRIu64 "): unable to jam state\r\n", eve_d); - return c3n; - } - - if ( u3r_mug(u3A->roc) != sef_u->mug_l ) { - fprintf(stderr, "serf (%" PRIu64 "): mug mismatch 0x%08x 0x%08x\r\n", - eve_d, sef_u->mug_l, u3r_mug(u3A->roc)); - return c3n; - } - - u3e_save(); - u3_serf_grab(); - - *ret = u3nc(c3__live, u3_nul); - return c3y; - } - - case c3__pack: { - if ( u3_nul != dat ) { - u3z(com); - return c3n; - } - else { - u3z(com); - u3a_print_memory(stderr, "serf: pack: gained", u3m_pack()); - *ret = u3nc(c3__live, u3_nul); - return c3y; - } - } - - case c3__meld: { - if ( u3_nul != dat ) { - u3z(com); - return c3n; - } - else { - u3z(com); - u3u_meld(); - *ret = u3nc(c3__live, u3_nul); - return c3y; - } - } - - case c3__save: { - c3_d eve_d; - - if ( c3n == u3r_safe_chub(dat, &eve_d) ) { - u3z(com); - return c3n; - } - - u3z(com); - _serf_writ_live_save(sef_u, eve_d); - *ret = u3nc(c3__live, u3_nul); - return c3y; - } - } -} - -/* u3_serf_writ(): apply writ [wit], producing plea [*pel] on c3y. -*/ -c3_o -u3_serf_writ(u3_serf* sef_u, u3_noun wit, u3_noun* pel) -{ - u3_noun tag, com; - c3_o ret_o; - - if ( c3n == u3r_cell(wit, &tag, &com) ) { - ret_o = c3n; - } - else { - switch ( tag ) { - default: { - ret_o = c3n; - } break; - - case c3__live: { - // since %live can take snapshots, it's refcount protocol is unique - // - u3k(com); - u3z(wit); - return u3_serf_live(sef_u, com, pel); - } break; - - case c3__peek: { - u3_noun tim, sam; - c3_w mil_w; - - if ( (c3n == u3r_cell(com, &tim, &sam)) || - (c3n == u3r_safe_word(tim, &mil_w)) ) - { - ret_o = c3n; - } - else { - *pel = u3_serf_peek(sef_u, mil_w, u3k(sam)); - ret_o = c3y; - } - } break; - - case c3__play: { - u3_noun eve, lit; - c3_d eve_d; - - if ( (c3n == u3r_cell(com, &eve, &lit)) || - (c3n == u3a_is_cell(lit)) || - (c3n == u3r_safe_chub(eve, &eve_d)) ) - { - ret_o = c3n; - } - else { - *pel = u3_serf_play(sef_u, eve_d, u3k(lit)); - ret_o = c3y; - } - } break; - - case c3__work: { - u3_noun tim, job; - c3_w mil_w; - - if ( (c3n == u3r_cell(com, &tim, &job)) || - (c3n == u3r_safe_word(tim, &mil_w)) ) - { - ret_o = c3n; - } - else { - *pel = u3_serf_work(sef_u, mil_w, u3k(job)); - ret_o = c3y; - } - } break; - } - } - - u3z(wit); - return ret_o; -} - -/* _serf_ripe(): produce initial serf state as [eve=@ mug=@] -*/ -static u3_noun -_serf_ripe(u3_serf* sef_u) -{ - // u3l_log("serf: ripe %" PRIu64, sef_u->dun_d); - - sef_u->mug_l = ( 0 == sef_u->dun_d ) - ? 0 - : u3r_mug(u3A->roc); - - return u3nc(u3i_chubs(1, &sef_u->dun_d), sef_u->mug_l); -} - -/* u3_serf_init(): init or restore, producing status. -*/ -u3_noun -u3_serf_init(u3_serf* sef_u) -{ - u3_noun rip; - - { - c3_w pro_w = 1; - c3_y hon_y = 141; - c3_y noc_y = 4; - u3_noun ver = u3nt(pro_w, hon_y, noc_y); - - rip = u3nt(c3__ripe, ver, _serf_ripe(sef_u)); - } - - // XX move to u3_serf_post() - // - // measure/print static memory usage if < 1/2 of the loom is available - // - // { - // c3_w pen_w = u3a_open(u3R); - - // if ( !(pen_w > (1 << 28)) ) { - // fprintf(stderr, "\r\n"); - // u3a_print_memory(stderr, "serf: contiguous free space", pen_w); - // u3_serf_grab(); - // } - // } - - sef_u->pac_o = c3n; - sef_u->rec_o = c3n; - sef_u->mut_o = c3n; - sef_u->sac = u3_nul; - - return rip; -} diff --git a/pkg/urcrypt/.gitignore b/pkg/urcrypt/.gitignore deleted file mode 100644 index b464b3f2f..000000000 --- a/pkg/urcrypt/.gitignore +++ /dev/null @@ -1,56 +0,0 @@ -*.pc -config.h -config.status -libtool - -# the following was adapted from -# https://github.com/github/gitignore/blob/991e760c1c6d50fdda246e0178b9c58b06770b90/Autotools.gitignore - -# http://www.gnu.org/software/automake - -Makefile.in -build-aux/ar-lib -/mdate-sh -/py-compile -/test-driver -/ylwrap -.deps/ -.dirstamp - -# http://www.gnu.org/software/autoconf - -autom4te.cache -/autoscan.log -/autoscan-*.log -/aclocal.m4 -build-aux/compile -/config.cache -build-aux/config.guess -/config.h.in -build-aux/config.log -build-aux/config.status -build-aux/config.sub -/configure -/configure.scan -build-aux/depcomp -build-aux/install-sh -build-aux/missing -/stamp-h1 - -# https://www.gnu.org/software/libtool/ - -build-aux/ltmain.sh - -# http://www.gnu.org/software/m4/ - -build-aux/m4/libtool.m4 -build-aux/m4/ltoptions.m4 -build-aux/m4/ltsugar.m4 -build-aux/m4/ltversion.m4 -build-aux/m4/lt~obsolete.m4 - -# Generated Makefile -# (meta build system like autotools, -# can automatically generate from config.status script -# (which is called by configure script)) -Makefile diff --git a/pkg/urcrypt/Makefile.am b/pkg/urcrypt/Makefile.am deleted file mode 100644 index 971b3e16e..000000000 --- a/pkg/urcrypt/Makefile.am +++ /dev/null @@ -1,130 +0,0 @@ -ACLOCAL_AMFLAGS = -I build-aux/m4 - -AM_CFLAGS = -Wall -g -O3 - -lib_LTLIBRARIES = liburcrypt.la -noinst_LTLIBRARIES = libed25519.la \ - libge_additions.la \ - libargon2.la \ - libkeccak_tiny.la \ - libscrypt.la - -include_HEADERS = urcrypt/urcrypt.h -noinst_HEADERS = urcrypt/util.h \ - ed25519/src/ed25519.h \ - ed25519/src/ge.h \ - ge-additions/ge-additions.h \ - argon2/include/argon2.h \ - argon2/src/blake2/blake2.h \ - scrypt/sha256.h \ - scrypt/libscrypt.h - -# main library -pkgconfig_DATA = liburcrypt-$(URCRYPT_API_VERSION).pc -DISTCLEANFILES = $(pkgconfig_DATA) - -liburcrypt_la_CPPFLAGS = -I$(srcdir)/ed25519/src \ - -I$(srcdir)/ge-additions \ - -I$(srcdir)/argon2/include \ - -I$(srcdir)/argon2/src/blake2 \ - -I$(srcdir)/keccak-tiny \ - -I$(srcdir)/scrypt -liburcrypt_la_LIBADD = $(LIBCRYPTO_LIBS) \ - $(LIBSECP256K1_LIBS) \ - $(LIBAES_SIV_LIBS) \ - libed25519.la \ - libge_additions.la \ - libargon2.la \ - libkeccak_tiny.la \ - libscrypt.la -liburcrypt_la_CFLAGS = $(LIBCRYPTO_CFLAGS) \ - $(LIBSECP256K1_CFLAGS) \ - $(LIBAES_SIV_CFLAGS) -# urcrypt_ is used for public symbols, urcrypt__ for internal. -liburcrypt_la_LDFLAGS = -export-symbols-regex '^urcrypt_[^_]' \ - -version-info $(URCRYPT_LT_VERSION) -liburcrypt_la_SOURCES = urcrypt/aes_cbc.c \ - urcrypt/aes_ecb.c \ - urcrypt/aes_siv.c \ - urcrypt/argon.c \ - urcrypt/ed25519.c \ - urcrypt/ge_additions.c \ - urcrypt/ripemd.c \ - urcrypt/scrypt.c \ - urcrypt/keccak.c \ - urcrypt/secp256k1.c \ - urcrypt/sha.c \ - urcrypt/util.c \ - urcrypt/util.h - -# ed25519 -libed25519_la_CFLAGS = -Wno-unused-result -libed25519_la_SOURCES = ed25519/src/fixedint.h \ - ed25519/src/sha512.h \ - ed25519/src/fe.h \ - ed25519/src/precomp_data.h \ - ed25519/src/sc.h \ - ed25519/src/add_scalar.c \ - ed25519/src/keypair.c \ - ed25519/src/sc.c \ - ed25519/src/seed.c \ - ed25519/src/verify.c \ - ed25519/src/ge.c \ - ed25519/src/fe.c \ - ed25519/src/key_exchange.c \ - ed25519/src/sha512.c \ - ed25519/src/sign.c - -# ge-additions -libge_additions_la_CPPFLAGS = -I$(srcdir)/ed25519/src -libge_additions_la_CFLAGS = -Werror -pedantic -std=gnu99 -libge_additions_la_SOURCES = ge-additions/ge-additions.c - -# argon2 -libargon2_la_CPPFLAGS = -I$(srcdir)/argon2/include -DARGON2_NO_THREADS -libargon2_la_CFLAGS = -Wno-unused-value -Wno-unused-function -libargon2_la_SOURCES = argon2/src/core.h \ - argon2/src/thread.h \ - argon2/src/encoding.h \ - argon2/src/blake2/blake2-impl.h \ - argon2/src/blake2/blamka-round-opt.h \ - argon2/src/blake2/blamka-round-ref.h \ - argon2/src/argon2.c \ - argon2/src/core.c \ - argon2/src/blake2/blake2b.c \ - argon2/src/thread.c \ - argon2/src/encoding.c - -# argon2 different sources for different CPU architectures -# opt.c requires SSE instructions and won't work on AArch64 et al. -if ARCH_X86_64 -libargon2_la_SOURCES += \ - argon2/src/opt.c -endif -if ARCH_GENERIC -libargon2_la_SOURCES += \ - argon2/src/ref.c -endif - -# scrypt -libscrypt_la_CPPFLAGS = -D_FORTIFY_SOURCE=2 -libscrypt_la_SOURCES = scrypt/b64.c \ - scrypt/crypto-mcf.c \ - scrypt/crypto-scrypt-saltgen.c \ - scrypt/crypto_scrypt-check.c \ - scrypt/crypto_scrypt-hash.c \ - scrypt/crypto_scrypt-hexconvert.c \ - scrypt/crypto_scrypt-nosse.c \ - scrypt/main.c \ - scrypt/sha256.c \ - scrypt/slowequals.c \ - scrypt/b64.h \ - scrypt/crypto_scrypt-hexconvert.h \ - scrypt/slowequals.h \ - scrypt/sysendian.h - -# keccak-tiny -libkeccak_tiny_la_CFLAGS = -march=native -std=c11 -Wextra -Wpedantic -Wall -libkeccak_tiny_la_SOURCES = keccak-tiny/keccak-tiny.c \ - keccak-tiny/define-macros.h \ - keccak-tiny/keccak-tiny.h diff --git a/pkg/urcrypt/README.md b/pkg/urcrypt/README.md deleted file mode 100644 index 80073c89d..000000000 --- a/pkg/urcrypt/README.md +++ /dev/null @@ -1,36 +0,0 @@ -What is urcrypt? ----------------- -urcrypt is a library of cryptography routines used by urbit jets. - -Why is urcrypt? ---------------- -Urbit's C runtime (long the only urbit runtime) has accumulated a collection of -cryptography dependencies, some with custom additions or patches. These -libraries have different conventions and have been managed by u3 in an ad-hoc -manner. Reproducing that arrangement in other runtimes is tricky and -error-prone. The (sometimes inconsistent) logic must be reproduced and suitable -cryptography primitives must be found (or worse, written) for the new -environment. - -To ease these burdens, urcrypt isolates the quirks behind a consistent calling -convention. Everything is a little-endian byte array, and each jetted operation -has a corresponding function in the library. Jets simply unpack their nouns, -call urcrypt, and pack the results. - -What is a cryptography routine? -------------------------------- -This is more of a subjective question than it might appear. Any of the following -conditions are sufficient, but not necessary, for a function to be included in -urcrypt: - - * The routine is sensitive to side-channel attacks (encryption, etc) - * Some property of the routine is cryptographically useful (SHA, RIPE, etc) - * The routine typically lives in a crypto library, for whatever reason. - -A word on OpenSSL ------------------ -Urcrypt depends on OpenSSL's libcrypto, which has global state. In order -to avoid dealing with this state, urcrypt refuses to build with an internal -libcrypto. Either build statically (pass `--disable-shared` to `./configure`) -or provide a shared libcrypto for urcrypt to link against. It is the library -user's responsibility to initialize openssl, set custom memory functions, etc. diff --git a/pkg/urcrypt/argon2/.gitattributes b/pkg/urcrypt/argon2/.gitattributes deleted file mode 100644 index 177bed95d..000000000 --- a/pkg/urcrypt/argon2/.gitattributes +++ /dev/null @@ -1,10 +0,0 @@ -# Export ignore -.gitattributes export-ignore -.gitignore export-ignore -.travis.yml export-ignore -appveyor.yml export-ignore -export.sh export-ignore -latex/* export-ignore - -# Linguist documentation -latex/* linguist-documentation diff --git a/pkg/urcrypt/argon2/.gitignore b/pkg/urcrypt/argon2/.gitignore deleted file mode 100644 index 4cfff979b..000000000 --- a/pkg/urcrypt/argon2/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -argon2 -libargon2.a -libargon2.so* -libargon2.dylib -.DS_Store -src/*.o -src/blake2/*.o -genkat -.idea -*.pyc -testcase -*.gcda -*.gcno -*.gcov -bench -vs2015/build -Argon2.sdf -Argon2.VC.opendb -*.zip -*.tar.gz -tags diff --git a/pkg/urcrypt/argon2/.travis.yml b/pkg/urcrypt/argon2/.travis.yml deleted file mode 100644 index 265fc48c0..000000000 --- a/pkg/urcrypt/argon2/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -language: c - -compiler: - - clang - - gcc - -os: - - linux - - osx - -# Clang on Linux needs to run in a VM to use ASAN. -# See: https://github.com/travis-ci/travis-ci/issues/9033 -matrix: - exclude: - - compiler: clang - os: linux - include: - - compiler: clang - os: linux - sudo: true - -script: make && make testci - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/pkg/urcrypt/argon2/Argon2.sln b/pkg/urcrypt/argon2/Argon2.sln deleted file mode 100644 index 8c23fdc58..000000000 --- a/pkg/urcrypt/argon2/Argon2.sln +++ /dev/null @@ -1,160 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Argon2OptTestCI", "vs2015\Argon2OptTestCI\Argon2OptTestCI.vcxproj", "{12956597-5E42-433A-93F3-D4EFF50AA207}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Argon2RefTestCI", "vs2015\Argon2RefTestCI\Argon2RefTestCI.vcxproj", "{8A1F7F84-34AF-4DB2-9D58-D4823DFE79E9}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Argon2OptGenKAT", "vs2015\Argon2OptGenKAT\Argon2OptGenKAT.vcxproj", "{DBBAAAE6-4560-4D11-8280-30A6650A82EF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Argon2RefGenKAT", "vs2015\Argon2RefGenKAT\Argon2RefGenKAT.vcxproj", "{71921B4C-A795-4A37-95A3-99D600E01211}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Argon2Opt", "vs2015\Argon2Opt\Argon2Opt.vcxproj", "{CAA75C57-998C-494E-B8A5-5894EF0FC528}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Argon2Ref", "vs2015\Argon2Ref\Argon2Ref.vcxproj", "{B9CAC9CE-9F0D-4F52-8D67-FDBBAFCD0DE2}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Argon2OptBench", "vs2015\Argon2OptBench\Argon2OptBench.vcxproj", "{B3A0FB44-0C1C-4EC3-B155-8B39371F8EE4}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Argon2RefBench", "vs2015\Argon2RefBench\Argon2RefBench.vcxproj", "{99203F6A-6E8C-42FC-8C7C-C07E8913D539}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Argon2OptDll", "vs2015\Argon2OptDll\Argon2OptDll.vcxproj", "{3A898DD8-ACAE-4269-ADFE-EB7260D71583}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Argon2RefDll", "vs2015\Argon2RefDll\Argon2RefDll.vcxproj", "{19D911A1-533C-4475-B313-F372481A35D4}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - ReleaseStatic|x64 = ReleaseStatic|x64 - ReleaseStatic|x86 = ReleaseStatic|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {12956597-5E42-433A-93F3-D4EFF50AA207}.Debug|x64.ActiveCfg = Debug|x64 - {12956597-5E42-433A-93F3-D4EFF50AA207}.Debug|x64.Build.0 = Debug|x64 - {12956597-5E42-433A-93F3-D4EFF50AA207}.Debug|x86.ActiveCfg = Debug|Win32 - {12956597-5E42-433A-93F3-D4EFF50AA207}.Debug|x86.Build.0 = Debug|Win32 - {12956597-5E42-433A-93F3-D4EFF50AA207}.Release|x64.ActiveCfg = Release|x64 - {12956597-5E42-433A-93F3-D4EFF50AA207}.Release|x64.Build.0 = Release|x64 - {12956597-5E42-433A-93F3-D4EFF50AA207}.Release|x86.ActiveCfg = Release|Win32 - {12956597-5E42-433A-93F3-D4EFF50AA207}.Release|x86.Build.0 = Release|Win32 - {12956597-5E42-433A-93F3-D4EFF50AA207}.ReleaseStatic|x64.ActiveCfg = ReleaseStatic|x64 - {12956597-5E42-433A-93F3-D4EFF50AA207}.ReleaseStatic|x64.Build.0 = ReleaseStatic|x64 - {12956597-5E42-433A-93F3-D4EFF50AA207}.ReleaseStatic|x86.ActiveCfg = ReleaseStatic|Win32 - {12956597-5E42-433A-93F3-D4EFF50AA207}.ReleaseStatic|x86.Build.0 = ReleaseStatic|Win32 - {8A1F7F84-34AF-4DB2-9D58-D4823DFE79E9}.Debug|x64.ActiveCfg = Debug|x64 - {8A1F7F84-34AF-4DB2-9D58-D4823DFE79E9}.Debug|x64.Build.0 = Debug|x64 - {8A1F7F84-34AF-4DB2-9D58-D4823DFE79E9}.Debug|x86.ActiveCfg = Debug|Win32 - {8A1F7F84-34AF-4DB2-9D58-D4823DFE79E9}.Debug|x86.Build.0 = Debug|Win32 - {8A1F7F84-34AF-4DB2-9D58-D4823DFE79E9}.Release|x64.ActiveCfg = Release|x64 - {8A1F7F84-34AF-4DB2-9D58-D4823DFE79E9}.Release|x64.Build.0 = Release|x64 - {8A1F7F84-34AF-4DB2-9D58-D4823DFE79E9}.Release|x86.ActiveCfg = Release|Win32 - {8A1F7F84-34AF-4DB2-9D58-D4823DFE79E9}.Release|x86.Build.0 = Release|Win32 - {8A1F7F84-34AF-4DB2-9D58-D4823DFE79E9}.ReleaseStatic|x64.ActiveCfg = ReleaseStatic|x64 - {8A1F7F84-34AF-4DB2-9D58-D4823DFE79E9}.ReleaseStatic|x64.Build.0 = ReleaseStatic|x64 - {8A1F7F84-34AF-4DB2-9D58-D4823DFE79E9}.ReleaseStatic|x86.ActiveCfg = ReleaseStatic|Win32 - {8A1F7F84-34AF-4DB2-9D58-D4823DFE79E9}.ReleaseStatic|x86.Build.0 = ReleaseStatic|Win32 - {DBBAAAE6-4560-4D11-8280-30A6650A82EF}.Debug|x64.ActiveCfg = Debug|x64 - {DBBAAAE6-4560-4D11-8280-30A6650A82EF}.Debug|x64.Build.0 = Debug|x64 - {DBBAAAE6-4560-4D11-8280-30A6650A82EF}.Debug|x86.ActiveCfg = Debug|Win32 - {DBBAAAE6-4560-4D11-8280-30A6650A82EF}.Debug|x86.Build.0 = Debug|Win32 - {DBBAAAE6-4560-4D11-8280-30A6650A82EF}.Release|x64.ActiveCfg = Release|x64 - {DBBAAAE6-4560-4D11-8280-30A6650A82EF}.Release|x64.Build.0 = Release|x64 - {DBBAAAE6-4560-4D11-8280-30A6650A82EF}.Release|x86.ActiveCfg = Release|Win32 - {DBBAAAE6-4560-4D11-8280-30A6650A82EF}.Release|x86.Build.0 = Release|Win32 - {DBBAAAE6-4560-4D11-8280-30A6650A82EF}.ReleaseStatic|x64.ActiveCfg = ReleaseStatic|x64 - {DBBAAAE6-4560-4D11-8280-30A6650A82EF}.ReleaseStatic|x64.Build.0 = ReleaseStatic|x64 - {DBBAAAE6-4560-4D11-8280-30A6650A82EF}.ReleaseStatic|x86.ActiveCfg = ReleaseStatic|Win32 - {DBBAAAE6-4560-4D11-8280-30A6650A82EF}.ReleaseStatic|x86.Build.0 = ReleaseStatic|Win32 - {71921B4C-A795-4A37-95A3-99D600E01211}.Debug|x64.ActiveCfg = Debug|x64 - {71921B4C-A795-4A37-95A3-99D600E01211}.Debug|x64.Build.0 = Debug|x64 - {71921B4C-A795-4A37-95A3-99D600E01211}.Debug|x86.ActiveCfg = Debug|Win32 - {71921B4C-A795-4A37-95A3-99D600E01211}.Debug|x86.Build.0 = Debug|Win32 - {71921B4C-A795-4A37-95A3-99D600E01211}.Release|x64.ActiveCfg = Release|x64 - {71921B4C-A795-4A37-95A3-99D600E01211}.Release|x64.Build.0 = Release|x64 - {71921B4C-A795-4A37-95A3-99D600E01211}.Release|x86.ActiveCfg = Release|Win32 - {71921B4C-A795-4A37-95A3-99D600E01211}.Release|x86.Build.0 = Release|Win32 - {71921B4C-A795-4A37-95A3-99D600E01211}.ReleaseStatic|x64.ActiveCfg = ReleaseStatic|x64 - {71921B4C-A795-4A37-95A3-99D600E01211}.ReleaseStatic|x64.Build.0 = ReleaseStatic|x64 - {71921B4C-A795-4A37-95A3-99D600E01211}.ReleaseStatic|x86.ActiveCfg = ReleaseStatic|Win32 - {71921B4C-A795-4A37-95A3-99D600E01211}.ReleaseStatic|x86.Build.0 = ReleaseStatic|Win32 - {CAA75C57-998C-494E-B8A5-5894EF0FC528}.Debug|x64.ActiveCfg = Debug|x64 - {CAA75C57-998C-494E-B8A5-5894EF0FC528}.Debug|x64.Build.0 = Debug|x64 - {CAA75C57-998C-494E-B8A5-5894EF0FC528}.Debug|x86.ActiveCfg = Debug|Win32 - {CAA75C57-998C-494E-B8A5-5894EF0FC528}.Debug|x86.Build.0 = Debug|Win32 - {CAA75C57-998C-494E-B8A5-5894EF0FC528}.Release|x64.ActiveCfg = Release|x64 - {CAA75C57-998C-494E-B8A5-5894EF0FC528}.Release|x64.Build.0 = Release|x64 - {CAA75C57-998C-494E-B8A5-5894EF0FC528}.Release|x86.ActiveCfg = Release|Win32 - {CAA75C57-998C-494E-B8A5-5894EF0FC528}.Release|x86.Build.0 = Release|Win32 - {CAA75C57-998C-494E-B8A5-5894EF0FC528}.ReleaseStatic|x64.ActiveCfg = ReleaseStatic|x64 - {CAA75C57-998C-494E-B8A5-5894EF0FC528}.ReleaseStatic|x64.Build.0 = ReleaseStatic|x64 - {CAA75C57-998C-494E-B8A5-5894EF0FC528}.ReleaseStatic|x86.ActiveCfg = ReleaseStatic|Win32 - {CAA75C57-998C-494E-B8A5-5894EF0FC528}.ReleaseStatic|x86.Build.0 = ReleaseStatic|Win32 - {B9CAC9CE-9F0D-4F52-8D67-FDBBAFCD0DE2}.Debug|x64.ActiveCfg = Debug|x64 - {B9CAC9CE-9F0D-4F52-8D67-FDBBAFCD0DE2}.Debug|x64.Build.0 = Debug|x64 - {B9CAC9CE-9F0D-4F52-8D67-FDBBAFCD0DE2}.Debug|x86.ActiveCfg = Debug|Win32 - {B9CAC9CE-9F0D-4F52-8D67-FDBBAFCD0DE2}.Debug|x86.Build.0 = Debug|Win32 - {B9CAC9CE-9F0D-4F52-8D67-FDBBAFCD0DE2}.Release|x64.ActiveCfg = Release|x64 - {B9CAC9CE-9F0D-4F52-8D67-FDBBAFCD0DE2}.Release|x64.Build.0 = Release|x64 - {B9CAC9CE-9F0D-4F52-8D67-FDBBAFCD0DE2}.Release|x86.ActiveCfg = Release|Win32 - {B9CAC9CE-9F0D-4F52-8D67-FDBBAFCD0DE2}.Release|x86.Build.0 = Release|Win32 - {B9CAC9CE-9F0D-4F52-8D67-FDBBAFCD0DE2}.ReleaseStatic|x64.ActiveCfg = ReleaseStatic|x64 - {B9CAC9CE-9F0D-4F52-8D67-FDBBAFCD0DE2}.ReleaseStatic|x64.Build.0 = ReleaseStatic|x64 - {B9CAC9CE-9F0D-4F52-8D67-FDBBAFCD0DE2}.ReleaseStatic|x86.ActiveCfg = ReleaseStatic|Win32 - {B9CAC9CE-9F0D-4F52-8D67-FDBBAFCD0DE2}.ReleaseStatic|x86.Build.0 = ReleaseStatic|Win32 - {B3A0FB44-0C1C-4EC3-B155-8B39371F8EE4}.Debug|x64.ActiveCfg = Debug|x64 - {B3A0FB44-0C1C-4EC3-B155-8B39371F8EE4}.Debug|x64.Build.0 = Debug|x64 - {B3A0FB44-0C1C-4EC3-B155-8B39371F8EE4}.Debug|x86.ActiveCfg = Debug|Win32 - {B3A0FB44-0C1C-4EC3-B155-8B39371F8EE4}.Debug|x86.Build.0 = Debug|Win32 - {B3A0FB44-0C1C-4EC3-B155-8B39371F8EE4}.Release|x64.ActiveCfg = Release|x64 - {B3A0FB44-0C1C-4EC3-B155-8B39371F8EE4}.Release|x64.Build.0 = Release|x64 - {B3A0FB44-0C1C-4EC3-B155-8B39371F8EE4}.Release|x86.ActiveCfg = Release|Win32 - {B3A0FB44-0C1C-4EC3-B155-8B39371F8EE4}.Release|x86.Build.0 = Release|Win32 - {B3A0FB44-0C1C-4EC3-B155-8B39371F8EE4}.ReleaseStatic|x64.ActiveCfg = ReleaseStatic|x64 - {B3A0FB44-0C1C-4EC3-B155-8B39371F8EE4}.ReleaseStatic|x64.Build.0 = ReleaseStatic|x64 - {B3A0FB44-0C1C-4EC3-B155-8B39371F8EE4}.ReleaseStatic|x86.ActiveCfg = ReleaseStatic|Win32 - {B3A0FB44-0C1C-4EC3-B155-8B39371F8EE4}.ReleaseStatic|x86.Build.0 = ReleaseStatic|Win32 - {99203F6A-6E8C-42FC-8C7C-C07E8913D539}.Debug|x64.ActiveCfg = Debug|x64 - {99203F6A-6E8C-42FC-8C7C-C07E8913D539}.Debug|x64.Build.0 = Debug|x64 - {99203F6A-6E8C-42FC-8C7C-C07E8913D539}.Debug|x86.ActiveCfg = Debug|Win32 - {99203F6A-6E8C-42FC-8C7C-C07E8913D539}.Debug|x86.Build.0 = Debug|Win32 - {99203F6A-6E8C-42FC-8C7C-C07E8913D539}.Release|x64.ActiveCfg = Release|x64 - {99203F6A-6E8C-42FC-8C7C-C07E8913D539}.Release|x64.Build.0 = Release|x64 - {99203F6A-6E8C-42FC-8C7C-C07E8913D539}.Release|x86.ActiveCfg = Release|Win32 - {99203F6A-6E8C-42FC-8C7C-C07E8913D539}.Release|x86.Build.0 = Release|Win32 - {99203F6A-6E8C-42FC-8C7C-C07E8913D539}.ReleaseStatic|x64.ActiveCfg = ReleaseStatic|x64 - {99203F6A-6E8C-42FC-8C7C-C07E8913D539}.ReleaseStatic|x64.Build.0 = ReleaseStatic|x64 - {99203F6A-6E8C-42FC-8C7C-C07E8913D539}.ReleaseStatic|x86.ActiveCfg = ReleaseStatic|Win32 - {99203F6A-6E8C-42FC-8C7C-C07E8913D539}.ReleaseStatic|x86.Build.0 = ReleaseStatic|Win32 - {3A898DD8-ACAE-4269-ADFE-EB7260D71583}.Debug|x64.ActiveCfg = Debug|x64 - {3A898DD8-ACAE-4269-ADFE-EB7260D71583}.Debug|x64.Build.0 = Debug|x64 - {3A898DD8-ACAE-4269-ADFE-EB7260D71583}.Debug|x86.ActiveCfg = Debug|Win32 - {3A898DD8-ACAE-4269-ADFE-EB7260D71583}.Debug|x86.Build.0 = Debug|Win32 - {3A898DD8-ACAE-4269-ADFE-EB7260D71583}.Release|x64.ActiveCfg = Release|x64 - {3A898DD8-ACAE-4269-ADFE-EB7260D71583}.Release|x64.Build.0 = Release|x64 - {3A898DD8-ACAE-4269-ADFE-EB7260D71583}.Release|x86.ActiveCfg = Release|Win32 - {3A898DD8-ACAE-4269-ADFE-EB7260D71583}.Release|x86.Build.0 = Release|Win32 - {3A898DD8-ACAE-4269-ADFE-EB7260D71583}.ReleaseStatic|x64.ActiveCfg = ReleaseStatic|x64 - {3A898DD8-ACAE-4269-ADFE-EB7260D71583}.ReleaseStatic|x64.Build.0 = ReleaseStatic|x64 - {3A898DD8-ACAE-4269-ADFE-EB7260D71583}.ReleaseStatic|x86.ActiveCfg = ReleaseStatic|Win32 - {3A898DD8-ACAE-4269-ADFE-EB7260D71583}.ReleaseStatic|x86.Build.0 = ReleaseStatic|Win32 - {19D911A1-533C-4475-B313-F372481A35D4}.Debug|x64.ActiveCfg = Debug|x64 - {19D911A1-533C-4475-B313-F372481A35D4}.Debug|x64.Build.0 = Debug|x64 - {19D911A1-533C-4475-B313-F372481A35D4}.Debug|x86.ActiveCfg = Debug|Win32 - {19D911A1-533C-4475-B313-F372481A35D4}.Debug|x86.Build.0 = Debug|Win32 - {19D911A1-533C-4475-B313-F372481A35D4}.Release|x64.ActiveCfg = Release|x64 - {19D911A1-533C-4475-B313-F372481A35D4}.Release|x64.Build.0 = Release|x64 - {19D911A1-533C-4475-B313-F372481A35D4}.Release|x86.ActiveCfg = Release|Win32 - {19D911A1-533C-4475-B313-F372481A35D4}.Release|x86.Build.0 = Release|Win32 - {19D911A1-533C-4475-B313-F372481A35D4}.ReleaseStatic|x64.ActiveCfg = ReleaseStatic|x64 - {19D911A1-533C-4475-B313-F372481A35D4}.ReleaseStatic|x64.Build.0 = ReleaseStatic|x64 - {19D911A1-533C-4475-B313-F372481A35D4}.ReleaseStatic|x86.ActiveCfg = ReleaseStatic|Win32 - {19D911A1-533C-4475-B313-F372481A35D4}.ReleaseStatic|x86.Build.0 = ReleaseStatic|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/pkg/urcrypt/argon2/CHANGELOG.md b/pkg/urcrypt/argon2/CHANGELOG.md deleted file mode 100644 index 0578fde27..000000000 --- a/pkg/urcrypt/argon2/CHANGELOG.md +++ /dev/null @@ -1,32 +0,0 @@ -# 20171227 -* Added ABI version number -* AVX2/AVX-512F optimizations of BLAMKA -* Set Argon2 version number from the command line -* New bindings -* Minor bug and warning fixes (no security issue) - -# 20161029 - -* Argon2id added -* Better documentation -* Dual licensing CC0 / Apache 2.0 -* Minor bug fixes (no security issue) - -# 20160406 - -* Version 1.3 of Argon2 -* Version number in encoded hash -* Refactored low-level API -* Visibility control for library symbols -* Microsoft Visual Studio solution -* New bindings -* Minor bug and warning fixes (no security issue) - - -# 20151206 - -* Python bindings -* Password read from stdin, instead of being an argument -* Compatibility FreeBSD, NetBSD, OpenBSD -* Constant-time verification -* Minor bug and warning fixes (no security issue) diff --git a/pkg/urcrypt/argon2/LICENSE b/pkg/urcrypt/argon2/LICENSE deleted file mode 100644 index fa611f7ac..000000000 --- a/pkg/urcrypt/argon2/LICENSE +++ /dev/null @@ -1,314 +0,0 @@ -Argon2 reference source code package - reference C implementations - -Copyright 2015 -Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves - -You may use this work under the terms of a Creative Commons CC0 1.0 -License/Waiver or the Apache Public License 2.0, at your option. The terms of -these licenses can be found at: - -- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 -- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 - -The terms of the licenses are reproduced below. - --------------------------------------------------------------------------------- - -Creative Commons Legal Code - -CC0 1.0 Universal - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. - --------------------------------------------------------------------------------- - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. diff --git a/pkg/urcrypt/argon2/Makefile b/pkg/urcrypt/argon2/Makefile deleted file mode 100644 index 1e1129fd6..000000000 --- a/pkg/urcrypt/argon2/Makefile +++ /dev/null @@ -1,187 +0,0 @@ -# -# Argon2 reference source code package - reference C implementations -# -# Copyright 2015 -# Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves -# -# You may use this work under the terms of a Creative Commons CC0 1.0 -# License/Waiver or the Apache Public License 2.0, at your option. The terms of -# these licenses can be found at: -# -# - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 -# - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 -# -# You should have received a copy of both of these licenses along with this -# software. If not, they may be obtained at the above URLs. -# - -RUN = argon2 -BENCH = bench -GENKAT = genkat - -# Increment on an ABI breaking change -ABI_VERSION = 1 - -DIST = phc-winner-argon2 - -SRC = src/argon2.c src/core.c src/blake2/blake2b.c src/thread.c src/encoding.c -SRC_RUN = src/run.c -SRC_BENCH = src/bench.c -SRC_GENKAT = src/genkat.c -OBJ = $(SRC:.c=.o) - -CFLAGS += -std=c89 -O3 -Wall -g -Iinclude -Isrc - -ifeq ($(NO_THREADS), 1) -CFLAGS += -DARGON2_NO_THREADS -else -CFLAGS += -pthread -endif - -CI_CFLAGS := $(CFLAGS) -Werror=declaration-after-statement -D_FORTIFY_SOURCE=2 \ - -Wextra -Wno-type-limits -Werror -coverage -DTEST_LARGE_RAM - -OPTTARGET ?= native -OPTTEST := $(shell $(CC) -Iinclude -Isrc -march=$(OPTTARGET) src/opt.c -c \ - -o /dev/null 2>/dev/null; echo $$?) -# Detect compatible platform -ifneq ($(OPTTEST), 0) -$(info Building without optimizations) - SRC += src/ref.c -else -$(info Building with optimizations for $(OPTTARGET)) - CFLAGS += -march=$(OPTTARGET) - SRC += src/opt.c -endif - -BUILD_PATH := $(shell pwd) -KERNEL_NAME := $(shell uname -s) - -LIB_NAME=argon2 -ifeq ($(KERNEL_NAME), Linux) - LIB_EXT := so.$(ABI_VERSION) - LIB_CFLAGS := -shared -fPIC -fvisibility=hidden -DA2_VISCTL=1 - SO_LDFLAGS := -Wl,-soname,lib$(LIB_NAME).$(LIB_EXT) - LINKED_LIB_EXT := so -endif -ifeq ($(KERNEL_NAME), $(filter $(KERNEL_NAME),FreeBSD NetBSD OpenBSD)) - LIB_EXT := so - LIB_CFLAGS := -shared -fPIC -endif -ifeq ($(KERNEL_NAME), Darwin) - LIB_EXT := $(ABI_VERSION).dylib - LIB_CFLAGS := -dynamiclib -install_name @rpath/lib$(LIB_NAME).$(LIB_EXT) - LINKED_LIB_EXT := dylib -endif -ifeq ($(findstring CYGWIN, $(KERNEL_NAME)), CYGWIN) - LIB_EXT := dll - LIB_CFLAGS := -shared -Wl,--out-implib,lib$(LIB_NAME).$(LIB_EXT).a -endif -ifeq ($(findstring MINGW, $(KERNEL_NAME)), MINGW) - LIB_EXT := dll - LIB_CFLAGS := -shared -Wl,--out-implib,lib$(LIB_NAME).$(LIB_EXT).a -endif -ifeq ($(findstring MSYS, $(KERNEL_NAME)), MSYS) - LIB_EXT := dll - LIB_CFLAGS := -shared -Wl,--out-implib,lib$(LIB_NAME).$(LIB_EXT).a -endif -ifeq ($(KERNEL_NAME), SunOS) - CC := gcc - CFLAGS += -D_REENTRANT - LIB_EXT := so - LIB_CFLAGS := -shared -fPIC -endif - -ifeq ($(KERNEL_NAME), Linux) -ifeq ($(CC), clang) - CI_CFLAGS += -fsanitize=address -fsanitize=undefined -endif -endif - -LIB_SH := lib$(LIB_NAME).$(LIB_EXT) -LIB_ST := lib$(LIB_NAME).a - -ifdef LINKED_LIB_EXT -LINKED_LIB_SH := lib$(LIB_NAME).$(LINKED_LIB_EXT) -endif - - -LIBRARIES = $(LIB_SH) $(LIB_ST) -HEADERS = include/argon2.h - -INSTALL = install - -DESTDIR = -PREFIX = /usr -INCLUDE_REL = include -LIBRARY_REL = lib -BINARY_REL = bin - -INST_INCLUDE = $(DESTDIR)$(PREFIX)/$(INCLUDE_REL) -INST_LIBRARY = $(DESTDIR)$(PREFIX)/$(LIBRARY_REL) -INST_BINARY = $(DESTDIR)$(PREFIX)/$(BINARY_REL) - -.PHONY: clean dist format $(GENKAT) all install - -all: $(RUN) libs -libs: $(LIBRARIES) - -$(RUN): $(SRC) $(SRC_RUN) - $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ - -$(BENCH): $(SRC) $(SRC_BENCH) - $(CC) $(CFLAGS) $^ -o $@ - -$(GENKAT): $(SRC) $(SRC_GENKAT) - $(CC) $(CFLAGS) $^ -o $@ -DGENKAT - -$(LIB_SH): $(SRC) - $(CC) $(CFLAGS) $(LIB_CFLAGS) $(LDFLAGS) $(SO_LDFLAGS) $^ -o $@ - -$(LIB_ST): $(OBJ) - ar rcs $@ $^ - -clean: - rm -f $(RUN) $(BENCH) $(GENKAT) - rm -f $(LIB_SH) $(LIB_ST) kat-argon2* - rm -f testcase - rm -rf *.dSYM - cd src/ && rm -f *.o - cd src/blake2/ && rm -f *.o - cd kats/ && rm -f kat-* diff* run_* make_* - -dist: - cd ..; \ - tar -c --exclude='.??*' -z -f $(DIST)-`date "+%Y%m%d"`.tgz $(DIST)/* - -test: $(SRC) src/test.c - $(CC) $(CFLAGS) -Wextra -Wno-type-limits $^ -o testcase - @sh kats/test.sh - ./testcase - -testci: $(SRC) src/test.c - $(CC) $(CI_CFLAGS) $^ -o testcase - @sh kats/test.sh - ./testcase - -.PHONY: test - -format: - clang-format -style="{BasedOnStyle: llvm, IndentWidth: 4}" \ - -i include/*.h src/*.c src/*.h src/blake2/*.c src/blake2/*.h - -install: $(RUN) libs - $(INSTALL) -d $(INST_INCLUDE) - $(INSTALL) -m 0644 $(HEADERS) $(INST_INCLUDE) - $(INSTALL) -d $(INST_LIBRARY) - $(INSTALL) $(LIBRARIES) $(INST_LIBRARY) -ifdef LINKED_LIB_SH - cd $(INST_LIBRARY) && ln -s $(notdir $(LIB_SH) $(LINKED_LIB_SH)) -endif - $(INSTALL) -d $(INST_BINARY) - $(INSTALL) $(RUN) $(INST_BINARY) - -uninstall: - cd $(INST_INCLUDE) && rm -f $(notdir $(HEADERS)) - cd $(INST_LIBRARY) && rm -f $(notdir $(LIBRARIES) $(LINKED_LIB_SH)) - cd $(INST_BINARY) && rm -f $(notdir $(RUN)) diff --git a/pkg/urcrypt/argon2/README.md b/pkg/urcrypt/argon2/README.md deleted file mode 100644 index 74cf17086..000000000 --- a/pkg/urcrypt/argon2/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# Argon2 - -This is a fork of [the reference C implementation of Argon2](https://github.com/P-H-C/phc-winner-argon2), the password-hashing function that won the [Password Hashing Competition (PHC)](https://password-hashing.net). - -## About Argon2u - -In addition to the official three variants (Argon2i, Argon2d, and Argon2id), this fork also implements a fourth variant, Argon2u. It operates similarly to Argon2id, in that it is a hybrid of Argon2i and Argon2d. Where Argon2id uses Argon2i's algorithm for the first two processed segments, Argon2u does this for the first three. - -## More about Argon2 - -Please see the [original repository](https://github.com/P-H-C/phc-winner-argon2) for information about Argon2. - -## Intellectual property - -Except for the components listed below, the Argon2 code in this -repository is copyright (c) 2015 Daniel Dinu, Dmitry Khovratovich (main -authors), Jean-Philippe Aumasson and Samuel Neves, and dual licensed under the -[CC0 License](https://creativecommons.org/about/cc0) and the -[Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0). For more info -see the LICENSE file. - -The string encoding routines in [`src/encoding.c`](src/encoding.c) are -copyright (c) 2015 Thomas Pornin, and under -[CC0 License](https://creativecommons.org/about/cc0). - -The BLAKE2 code in [`src/blake2/`](src/blake2) is copyright (c) Samuel -Neves, 2013-2015, and under -[CC0 License](https://creativecommons.org/about/cc0). - -All licenses are therefore GPL-compatible. diff --git a/pkg/urcrypt/argon2/appveyor.yml b/pkg/urcrypt/argon2/appveyor.yml deleted file mode 100644 index fb1f048ef..000000000 --- a/pkg/urcrypt/argon2/appveyor.yml +++ /dev/null @@ -1,25 +0,0 @@ -os: Visual Studio 2015 - -environment: - matrix: - - platform: x86 - configuration: Debug - - platform: x86 - configuration: Release - - platform: x64 - configuration: Debug - - platform: x64 - configuration: Release - -matrix: - fast_finish: false - -build: - parallel: true - project: Argon2.sln - verbosity: minimal - -test_script: - - ps: kats\test.ps1 - - ps: if ("Release" -eq $env:configuration) { vs2015\build\Argon2OptTestCI.exe } - - ps: if ("Release" -eq $env:configuration) { vs2015\build\Argon2RefTestCI.exe } diff --git a/pkg/urcrypt/argon2/argon2-specs.pdf b/pkg/urcrypt/argon2/argon2-specs.pdf deleted file mode 100644 index d916af6415c93ade373b61c9179f9928b2b1daa9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 459608 zcmb5VLy#~)w`E(lZQHhO+phY`wr$(CZQHhOoBel3M|8jFJGd`LCvudt6>FcJqzWQp zw2XADP^9zABkNF%oU8;41a?N21Ux)Y^fIQl=FS!bjI2zY1pn(m(Tn}Fb~be+pck_? zbT$<+HMTP`h2rCba&mSwHMD_p-@MV1cG_Y?=si&Ez7Lk8J5Ac_Npe+Gzg}5JXL;?^k@b=5P_JyvWx8mg=9j;j!NIQmq`Gp}%^*L} zH6*vTTs(PP-)*vRR@D3*VC@v@>AOkip)m`?98tmeC=) zJ0tDwld7hLddl}WTe`fI^6y6f5Iej2LhZ6v_uxmKQ_Err&d!<5v>|P)Wjq`NlD&yI z!e07A;{tmLv9yGH$t7gA>+aYt5(2{lfs-XkbW}hQa{gjW5U$7lo20 zM`u%YjlJ$mDru008sz+}M^o-@?&fepNBze(?5ewUDyZb74&Ag8I&q~$*I>}UYB=UN zbh4{fvo~|b*3M3HwKlVs?vq=oEh?k-lmWWGWg-jnGo$4YoJ6uXh;p-~ab9;*e z0Gbr%0t;dX1f_ld1HNp%Mm0n#ZE}{$gaks!N(~~yb+63EtbKL?0(llvLx6aUOGXxf zj-(L|Rs^iS(|`nW+fv?8E!#6^Fe(ZcPaY{zf@~&iz_xgyBCmel3ml)J&dQ3JsvTmq zJ)=6Dq#$w7t+mhC-o48>s-TAXMO;9%WNo3#F6gMa)%*lnQm~ZhXa>yJJihRD*d*V1A+Op_d zXWiP6IRw?GcLGV;9cF_$_^6N3Oc0e=5Q3IK(TLrfBXq7VCPpyjAF^16lRKW1O1g%- zwo)g$=HdMK;nldOIx8hNLVR#gPc0K z2IwVG4^1*PTPUJ8-hELgZ=p)Wn2^HRq~?76H?>QYTg6kBNlS z<|`$yX$RgH!NE{$byg zk*x?oc)@6xaIj@Sot=%x&rxRwrPP~M^eyt7!-+YpUYc7-f61T*UCDO3J}^W_@bpoq zIt21IY|(@A2Acw^l}qcrB-zN=AUg{7ID)R%rF(tCEvy`{0f7oMFQp!MHe>yixJ3t& zlK_cJKl?>+`)GtQ+6w@nQMY++@f(S5+&qf)>vv#Lq`OjJPTp_-% z#(dkuraBB9G$yR@e*|0{N`d;m}5Q0I6M(OHpu3qd|idRQ8!**r~A+%b#ko5L>{c_T|@XB#MbIRZuohW|+tM<-_j4hGi$!x?tY|2Ah@G`4KFR*`(x z)TfQ1mXCY&;i7?Jqni0RL}QA5q<#dHn?*#3KqC`xe0|mwwB?qJlWeO1kk~|Lsx_T9 zn&=ZjG#3MLFr^c^Nhv8r5;KdLNFEk)N&HYI1f)2W5|dq-OC&hGX)DejATYksC9x;M zH!T<6gZ6(412b{(Y6#C5-5-G# z1G-a>Nj%QX_793eFhE^L74H=yQ9y@5M28kpg2>?Gf`8#;{DV*cSoEfg0SXP>>r>SpfEjAQ z^844Ah(UC@@}*+CmcISlW&x6o@4(aqUZW=w?tQ>~-5F#M#&@59dky0O9sRQsD?mil znJf%2IjDtI!iL30d;vI#29Y=u7y&Rf1ra#@#%m22(iH<) z>1>cIMeYcuCL0Awv@6Zd?UPD{d=NNM)ywM$BW{H56@U1>%W5^a469;~FqP9?aUkKD z4nG88;;vIPRu{!F4}-C?fcGAe zNz)*AknLQ5XFtLx|IPm{D*f{IY^a&)x5<+A72Ne^^>kQ%*5=%Wy6tsSRKpGKsk^x- zKV{u8H+F52KM;S)+vwj#q1XS>)WtqNS&F*Zh+kRmxW<`J6=p5%)Kcm*Wg@@3tj$c(~sKdK7rN^^@Urf37TvXnq z`fz;8@poT)D|xA-{=j(_iA^tTMfoV!MQ*8zy45X7=jyi+u$A9vL{*0MTDBf-G*EJ@ zc3fTlCPbEM@Y-HEM7@qb`z&}1U6q&`=b{RqVRBa{2ixpwlbK zV{&60M{2(GmH6l_e9ZWk$`aE!{5)XMFeZ_{H?_1&nUT7VsI+cobO^1=(7` z*N#SKO_c5)( z_his9;JQnZ2WtJ3lbZ2@<%sXv#>?>Zw=z@qefaHNAFmI?n&da`=i@iB$3E4&XZ@FS z_V)Isxxs7u>DuBozG<7Vwtd<(=e=^eVTPPl(QK*$2^ z$zc(Yf@fMFH#QhG{g4ybpeb{8S)WXIT#Kg ztE^Zy7lV>f@6G8i<*>~qf);{16T{~r;0&{2PhaS4Mymnw41!w*RM;nE>)gMZS|{f$ za`&7cS_tczIe9^?=9NwH@hd#E(En!4hFljhsV)&O{P3^$VxU$8L}4id!YnhA(__R^ z1}!9&W+5_U*p6Dzv^y((30x#f<|&kDY5m6nB`VR83g^^nxe6u&kM0O)&`{F&MtxOQ znbU_}als^%o=(^7qf~CcxNgY8=z8L)AaL@1P(w@(($iWbvh=L(2dY95qvq^OHsBWR zU5$Cj*8D#&(~fA=ctQ3o6w7wlt5ZN9in!Cl)5HV?bJ9J1F^>=kf3(Y-~e@6>* zmY37(gFhU?cD6@kN!HB@--)WOxa)6>AJ~n(57|^Zg*4xcv-|@V{>Rtg?~DWZ7z4ai^j z^pbRCW%<&4ffs~x>+)^|- zQ*@*5JCVqy9fo-k9PFvSx+|LsPXFx0u0gmRu(EYsea^cKYWPiUvc*koZl;$=P8hHd z=h_OAxt@Q?ewxQ1H<0__TpS|30woRtWIpvwj}fnD-8KD_+0#l9_E6RWmXA@o`&rOv z((~x<$rEP-4Bfdgcm@r79aM6PcVs1vT-oaD()lAM#N~G2;nNj1q6nSk3#xx;rTy(w`U{ZW~+tHL0 zs6POd zLL0a}mpK10e*+8>Emqvbcy4;O>m4Y$;wV&IE{6bNq*sn{+zF&Uy4JNYwk8LB`#A5W zHm3Ts#1}5pmnc_ygG>Jn%>oYCo&*HkMG#G)E4Rw!1@9#ioUTAE_K>^j4C43PJ06&Y%uL*GyrYHibW`7N6>Bhv(Nww46K-`L?37k zkL)JD&HZn1E$=uU3_Fxk%cu@7tALN)j9L=w5;+J;RNt2u)Uva+hZ566z_bS8V}3(W zq8`(C&gvY6t&>^@bAgL+j~J6#3}QQ+Q|DO=>j?InnD$r^My}LEIH?o6*qSiKXz9?1 zJVgQS=TcNHWZ8{Zm+i!mzhrN9TlnCZsYjzRGz!UI%O?&uCuBgcvVKi{uh$+&n)MD& zx9;l`jn7SV@?)X$$OcC>n@G^024Oo|PQTmh394wF8?sZCSkjWCwf>28KJ-8#o`V#) zNFMiKrjE$0QM=F;I7mwOHY0X>u5J}OUStYeplOp1KW7_HA%+_edYgMnX%orIE|k`} zGp#*J*c8Ihh!O-1VN;GqWavQS(CDlJSY6ND=>$%lZ^dUV7X?&>Y)l;Hc036jbJqz$ zSyL#Jt~pGoBVt$UJf72cw<-eawqz!7q2ze!k5#Eq9P`EfB_~Z%FeqXX#qGC1%37s}ux&glI0ZL$^#7h{D zP%bB`>hyMBMiU3e$>DMvH+wAFWCCTzlxUPKrB~GscjPjOqPK~9RLP6S+vWv;`dGyY zF-`+nK%JUtP#NT*)JD|PD_l&lQYaFA49jU%LkkkrEglyT*{gpuSt~bM%e3NzVd{rv zs;uAV9Df$OfP4Cf!d?bH@Yu7bqjANDn=Iv?P>^^PAv@FP>5;)NFp#FwxfVFE9G_)!ORDz zvkAp3j;p8K4w;|+`BiDgekmQfpFtXwmpPK6Z&_`D-Pl;P0PE@>ST>3;lYTKe&~oyR z_u)4<@)m1RYGptte*6nhN@UeEU#=YwS&Ob<-;?IIZhh4`r9_ZRZ_#)66pwQs^^?!r zE2xHkLRaX*t{1R8r0yarQINix+Vqhn<(PnCNK;jP`WrmoG7hfz1Og?8#|{CsCz4O- zh&YAY_RQU-l;k-j&u%Q%OpoCCQV7_`Y%`8<*Xu{>SYasrUHb)k7X?C+xh`1bxr*hK zWuc25$`Ir;dg#zTnj{1m$X}_Q^frq1ps%Q<{6S;jO8g9WA;#D@U7B)$I{n}K%$0&0 zbNgDiHAz~bGhyo(F4dnU@WX#F-=D*04{_@Q_o~cKS&Grk@vGdRVvFvJ1%BoJw&5;B zp~2CCv-+P5*~Pm8kXjt7T89cX*^&hw`>v=Sv24RGT>HRzxsgvZfnEaWuIesU$dNPt z8TDU86YEBF0-(OLf%#Km+GI{9Q4$5RkQMF7Mkjg3kqZK+b5jC5c}}6Tc$d}(4RNy3#`7zzaGe02T%m_ z2O@{6;9dZv%mo+iQR7jw`Hr6i+QVxSBrD?S{J5jmLdhhuUG5vOg+NL#TcQPqJ^m)9 zO7IQjz4{R6qO6bgNT{v3F}(`3cLUO~EAR}-?c&M1XqhC*Gth5xN6iz>KzU;diXGO^ z`{Y=o8PffY>~%w#)@3@vbTX@{!hODTrZ9d^{msa7=s74#zdr2&Xv z4zKtY;SDO}2qcujX&a0q?TEkG4#7lM$b?Ec2yx0#$Gf?m7zM5rFK*C!L5_WaM9KCa zO17m;q70eStd5PilfpiV)QVgL4k?tY)OlMt_GTl}Q$n?)#XH4}2SBKQxaSJclY{^2 z-50qj*u20)l&SStmvJ&IICcPJ)X+D|X?})(%CD3m5(JIk|Y{-ALNP!NpJgqfeEt7gu zi)c!=X^e=H$qgT{0|lAHfmynp;Y+0QK4o}Ph!86lUt=MKt%#M~dXnQe6Fr zY;h$1rI%!WkGHQuDW;Jy=L1rzfo(#vO!{$8x`ANPAz8KZCirfWdmZiZ?p0nr4%5H( zk@A@>Ag9EiyV+gomljQzu+`9{`vQE(YiAddJQlFTu1Yz^A+rz~4*cur{*W+&AetYC zD_r4@a{id-uJo9+|1+hdHsg3N4h4vb3fC5&9@$kb&Q*(NIeg4jlUn>8suK$j*8d(< zz+%(2LmQ}CBPAzR#(Yk9{hn5FK|69obXV;!Log40*T8@Ihs@Ad~H zp(u#5AMynXRr9SG@S8cWDeNF{IL2Bdkc9+~amebpCPnc%*u;0gE_Y;QRgmng@^DEf zdC>JAR#n*spxibbXe)62C+Y8x!ar6vvJKs6MHq1h4!RaygR4W%xJ|t;CV1dj*F#>z z8edL>;Z-uZqQt566^qD2*piFOm zIn!T_YJF^4tPU|qEl|F>pu7fY~WKKP^(!8c3Px|()aE(?I(&dfURaUxy%GUcS z0CMRzHM&qGF6Ld^LCTb?l_gc1c>B_yz(M(|Xf!u^>WWgb2CHO^zM~fNvo%Y~yOgCH z`LZ&~Z#ICy0{tT3EZ$h=AG+|2d5JsH8`@Xi*)Brp+eyGudM_@1S%Pe2iardjQ?nIm zo3G$MG+c%&(I2C5mW#-%(st&se!#ePTvb{pV{n>ieCRa^ngSZoi0Ifbw)^bz@{)?( z$SJ&t!BBSA${fhc@0^PSV>4*@FXt*)lE*Z3mIPzk$13BkwAy6Z0>l{-jc1#euWUo+ zY!#WOIgxsRlSkOAJP%li&QMMZKVJD^Y}%h6f+sv)-Z&`nyL7{rupqO4Gyz?^GAiES zDXf?iF_!ZPGxbj*9%TvK?3QstIQyOoLP9KhC5UE-Jf=0^1y|hXSEXvs!0`yB7!!n} zY_(mPk$*NF7D=6cQFKROaTVjDK^gU)u=g~Q;>ttumS28t*Tiksxf%C1)|<=h9zb%A|Hz$a3i~%Dz3J0|x}w3pk3T^kgmQ0Y z_H)_z?(x%ZH2?Q`Iny=8UJ2t=yV{{G6PYx+`9)IHljtl|C`{_~&vjg8QuQ9x4#rOV zlmnC9=7U2|$J};1g)~}vn5SAJ*^Sl$)xeuYSltAuQt=HAO~m(;MRg{-^eMeZBgtQM zB5j}Z#CA_26yuLTxp$Gru)T2$ZPLF@Ij<~ii+!C|y=TebzERuPuha|k%&Ab;=l6tIN6Va${J4*cLxyJf=E-uIy|`d_GT z;Dh`BLfct5{$FipVPa?g?`nIG)_tH*R{>_EZu>M`uTu6fk|n zViikF4+E1r`^w7K4*xen&#(Pc8h!698gB)P?#JSZsvE9ZSKQhc#f#g}3*S0!ZIG^; zEmb9y>(PLe_D=5XQLinvSLbfn#cbiSUJ-+om!fJ9E*SUt6)l%3_fP9}?EAW!U+?ai zL${Z?Up~BzJ_}b}%UEZR9p1K;$8F8@Ue0KzmCL-aVARjSW(>|f3kD?h09!+u4}!Y~ z&eU$C1C7+>H~nv*D@w+W*V6!ULG^JPdc$?lw)E0@UxI$URphT8x*83MRvW^FPZ6!S z*Yzj3uJ2MqwsVROJC51K)vJc>#jUos3PO@AH=3-mm&Zj^YoRgsqVt!sa&oseSJ(6a zp6E*gy{K1 zBQd8~e8Z9pvWa8;Il*EYVCR4y46LjWFWdZMg0i0hARuV97S-*njU*c!sr;kKo7_rX zAD&Bq5g3!h27mVGZ7;nX!a_mlApkp@+&`fNgv+HV>xM=x| z`BJs4B15fEie%fU0y>xJ&!z1HIkB`OanPbu{~Ao>+g%hISlq(knN?LrCZj{2@;GvK zo>M-~2sQ0j_2xo``I=sgD@ddQPSSnH>p2?b3z2<-kl){HgZg%QOXuWJ%~H91ofrod z!h((d^n==~I8flnKOmu@>3Xe&C0{O9+#LR%`jLJLQ26rFVL>=0k_;#Eg#oBeGF1O? zKy%Dfv$qF>79{c~0#Y_lx^U%)0ALs8Z8nfLFjc#X-g8K^tWR-1<6JD%AXaf{=&&L4)RVV`>CP|KuG z^$jVp_ZIyE1rT4t3+hS-$>s#)=mQf8<`^Y0F2Hj_c=ejvI9Z)7pEVkOxzkjEjn%_3 zrNpQ&3o#|EjgLI0N)X=7Lq>-Y2~kvY*L+0! z-Mmz*uJWvdBp!Ibg*D=h4#-2ra4lD?(Jo684?rUom5pw#xXo7}LC=jWIJViaVXr+U z>SS=;EU~_lO|P|kQaFP{NMs%26j)Ad?jo-070CQhd5t2Ok$N=X?fS7&i93iz`Q@Av zXBSTq#1{m$UoxT-qPyreKgI?5NtMjna7$Z@P+XEjRw0#UdLyG5{9aE;H=5PWkTCup zGYrniRhp74&^&u_{6i{F%Pv5z<0wt+cf~;Ua3Ggf58X%iC#%7HM5WNyK$pO=vH;?p-?>>5`J*CO!P5@`W?kuA@=GB#>tI1tUODaM9eAyjwoIchfI-& z*?mOn2P6MF$*|-^2VqVXkd92#G7~x?loqP`xY3YIU>8++*l8Yg;*OP0Vo2FT3bHMszrGu;LM6|H?zNOOrR{a*qHF*e#!QMQm&}G2G_;Xl9QNfioTCr9XaW`$)^RNO{ZA5+|5vlm-Yy)S ze(J$)$^UTt!w?4#{^-uUFQ}LMH@V}FXBpowZg9BGT%k#f%6za+fm-0$3|)Mgb@pfy z7kX)zw*a?04&Bte&fqr~)Cze!!&6pD+csqf8DStQn_!gvY3p0y&lS?GaLN~nz+ zD0!(^kkIl{1}hPi9DNkAJc9hdNc#(0cLd9=eZVwyVBB z@dbEhd-ZGy+ymcWBM|=%=mvP>H$?$3ldW$2u8MlU7R89_kw?UCZ+-oWi{p>bb}DWoPr#dy)S z*11#gKvoB#GSw|RlS8=hInuZrC&y7zta+Du+z2w*dFGt1v7hib!?!b()ovr)58hO0 z+#Z5^Je@B44&=8U0^LX@#ayw(*bM#W32IDy+t?Q%fAshFgYRvtIeg%W@2b&b9a4P- z#Zk|fzv%cfb3)WOJ3Bt1hPLxzO_}Xg6=K1>gNXLCjIElmS)7>8^FdTnjE(Sh62TpN zDwv>I!PWhV*e0QjF+C$7lrwMo1*kyRBay#QA~(00XVO%-=o9F=m~!q@MYpU3nxN?% zd4yf3pcM*xDzGD1Y2p+-@v+>kKMAHBbz|&U9O#!c49ikwl*_7kPNdwH=UZ+q_4~gu zDjK=lDv5;CuWE)F&Q>ap6Xp@YMcI6RsKtinp6a;E)(Lb^#t$Lz-loF9DZL__29rpg znL^;2*bNOSTWNAbj)JnFd=~X+$tKl(GTAf1bzQ3R9zo2Flgmj!t_7uOY>O!RB1p(x z>vVhrsthIUZl~yq15_Mn?hF8Ir24p15MepVYkW*v;SL)M5&Uw|eHJYUoSgB7tIUZJ zUOk(16Fs(p(WV#_w!v`w*`f2rY8a_aH(PB)g59$VjUzmHakoO3lFE@wHK%+TyXAF5br++JeT08{Q=$eOe%wO^bKF1t{I{UC**+ztzdzyOnFBO}3x9-HLv5}mWz&Fu_X9u}Ti2O4)EO$+u>WF=AK+zt8lxbVWPLpaL)lLdY5W=^IWFJz7#o6e=5gctLud~D^ z0~gnn23d5-UC~u^;zicy`bowz?vjWKGM!d4$(=kL?B2;?OrGQ66Fr-ge#!*b1P(<1 zO$Ocfnhz>5ANsY+Cc^fR-Tn`W1)ua&3_OGE(xd6FYUEq=E zI~21W6d^!#K$5odBudI*hLd4r_VX;s?&UvDO*1_n2b|K10{75u2`2B+X^&mksG=bJ z;|&v0`c?v_EartgVR(EXOK3PKu&m^#74W)&HoE7)uZWLhRttVDsKyzRVVABUhi0h3 zbOy>n3LQJU^?>8ba=4BzJReoClek`n*)P28nWh}%qy1N zwDks{&0p{Tn$BVr2^Kl?f0tabNOM!MzLoOd$8JId6dT={j*QlcbPK@I?%nyRr$8}e zlz(iEGZDyGUG5=!nTEvxwt5YrK2&^pDqhZ6qejE{HPp|bpsg9vA?bc*2HgitpVcMl ztNiX-a)1;?B?)3eQs{aC3tgY|%YK%kK(1xbtlqBl7|&t#FB}_`W5fG6-eNs6C!jm} zI(oNFfU)`lJ%bO-|I}WLXEbM6GQVUQ zfw*=8MSZHP9_mwOPxUodOeFT7=&i;~orQ^NDm|f?AK+%NzdD`O<50X?&oVP)`CmS$X64#4wjbP`lNC4j5z_3mgO2?6@=o&5 z_xZe@B86@zKC@B(r9EAxOIJGBZlCc}LEY3_m;cng64_$Q^m_pWrIzV#)}18JazzwT zAOZ>Qf&1D26K;ISovThrQQurXdZs{|srF7f4HYj|P2F7jydtB2jD$_~`9A3)#tf%w zIbb<@XzN$2Ry4BPygY?WH)-i9iZ^jLztryPj}u{6HC()|*EO9Ane=jo=GAE4xh=b$ zcSW(zZ!8Z9@DACyS+}v+4@*W?m(s7KU~l4zd!EV6*YCux&#I@UbWp|Hl&~__GmTW& z4|ntE>kOzURRKfS3B7RN2_&;Y26nkR3|&OparIkB19-tQoN7xy1eS$ z!!rcA%U090n#d;VLAy&mP16Q&x~`O&g>~b(^%m{A{P4EaRsOuzZp5}dYuVWE+bH`v zKkj@AzB|fi-`eX(T5G@gLhk*&*A38{fs`Wx&FGP7^EtSJYjHulzh*8Dkc+bMJpbvSc`BfPal z9~Xt_EcVA{gnHrHRUv8s|dP3Z|Z)X z4N%(eaL*W^TWQ}b|CZ~%_=si+dJ+}B{7YiiMKk={D{jur;_>$T3y@#~uBdJe#Z*`c znGDRmXodB(UyIKTCWh9{vUNK@h?c{`4NfyqNKcfk0tVj8V}{78BLnqKA!txb+yH_L zLXnveN4G2sanz{T&o=jyP*BNEDSW`(8lz{pw8qwHPHoh|{Cg+0&9h zDEBDTBbAU&-TFp!Wo`Okc>(8v5p`?|4#^mf0E%D+1@e6)(9PYXw+CFUU43fT?q<0&-$tY8wU`HUwp%2;87aiq#DTZQ|oF-P^Wco=a) zr%#G%J3&^r>m9xv>Hc(5hu$8yP}PYK7MfC`E=b$&Y5t9LMEzDA_{~O=m^fKesba3t z%I11VR(|6mBoyHEAjD6gNv;+@t<5p`V|V;kMG**tW!Ru(HNL2n_42?JqnHK%^c2D7;|K2EnrbT#L z5{kNK*hjF1gn8ILB0uL)8L|%p<^rGIM>bIXWKp?!N6G|%t&9EjE8GM`>9D-3pyow| zFuW@Z?(n?i!l~1Ok!1UAxvbLVUHuUtc4z|pA_#xw&6+$Ye9AeU^4U-`Zn532j3JO4 z9pwP6+8=bhu(e5;oQpXTOZ z_;A>~w)|QcQzg0ztF*fucmljE8G;#l5b$roz61cTau{T2j}L*c5N`?nS!csOg!xBw z=!$&}2M@QtKip2`-4SwQ`vblWAMYm3FBgu{tAY)KsEFwZ8WzXJYZ6wlw4H@#oJCYr zUh|e?NY`J#_98JLPoRhlx-HPwTHoLbSQ)&gK^obQE&)|iDiyB%*(qE|vWmB^l4w4| z8iRj6=8Z`L|J?96oTb}?2e&dh$N0L^db?jtDGy_|m-n~;!>1IoTa_9Jr`1C)R~e*# z;Xg0E0=HvS;R`It75)@gti0GM;6G^N{*RjG5W?^uWr z2?Kz=J6-3k^om!quX*MHL1@`sXuc{^>xF*o^eBX}es}_@y7jInS;J|f9{)wQNXh(d)NO_cQMyU<|gJ*cic??KQt54%meV3)l3br z;X2GImJ}R?NzyC#`^1FgmHhOu)DjIc>O5&lp5EfTtQ$7CeQbuq6m%9htN|v-=jxDU zY_#pnTZ_#3BY0ezel?q*=;&QmiAebVrxVbOH9I6kgHmw~!0 z<%h4~IYj?w$vp6ao}zco|H)p;z!x;jDge3%<{W*3b{)DDRisC%pDdglID((tyQ^{V z!__-6P{qYLDn5hww1Va>)}~yU6V^&2 zx*k|0hMXvPvX3TS9Jpl3kWJ`0VpTR0e<06=sZV9mAfswjATST?6S{3+AXp|48K0+~ zX+MG9PPcOr$}zf4w+RwzX^j~wQ@3%AQtFQCcK>@Y68t{6f1>27eGDRj(53P8)3-$>ofLIPB-=F!oT6vGuL2Q7$Ml|~FjL>txZ^1l=>;gh` zZX7ec!WIW09wSI#Kc3?y^2Dgstm4V=*hEEt(eR~K6YME8#8T}FI zR|fzsE9VdU-hUqsDT4tp7I#i9nJqX1$qXrpk875W>&PgZcXZ4qS$~jb3c|rpI*-Cb zp&etJ@iwaM9Qt7gkOP?r204X#rcoyYt4qSbAM^D@!_WyJW9l6j_w+7Xl7>*>IoG3_ zow!}jd{pI??p`Va4nraW)LIb|3Cjg_5$rvbZV3J+@f0P>Iu5+kC^lF(Irf{jhsTw3 z50+y%te!OZV1=#Y&A{|=!vBxiCB6nte@KN${cHm~8Mj0(o5xCPq&?>(c z|G9;iV}nx`44~@jDvkW$qT=|pIpeW{Aey*PA0WuPl6_2}aBU!9lsME9ef&#BXG;-k z=7of#Pi`3IxadBLJKNp{kz}lqy}shnsX<$Uyu+rg!tUS$9ju1 zLS5{mcl$p@QOKdTFL$x&Tf%x+O#aKt(T2!Gk0iyw)nw8^LxV1n)m?c_A$WrURC}Mq zNu6C4fso#t&6|6we*+*#k0j3?0x2izpax}9!1ogVUIdm}>M+Nrlf z!WBP!6n;A=I|I6I73{EuIkN5aAP#v`^n*`vKeBCU6Wnz6SWuK??fXn6I$uDj?8>y| z_ALbG{+!d+s@yal25#Z`&rJEPGP7%>ct*mM{*8w7e#p)S4?^@6*2pGMr6P>nLpG5` zi4TXtDwW>k17ar*>4icLpuxbo#%K2swO)7Jal$vEj30~i?V(zimCy|CLym-71!S{9Dkec zhxltx>^(6MB>fOCK$T>D~1{oCy^ZV?geFTsDD8Zc%p225X%f|7+X$LUXtp;%zj*`(f) zA!JpZ`)E*E`|(CYk@}r-Z@PZSMCF4%at7wRlH-P?T@`O9Dm91`*glXg2qw!ZG%+hO zCxEe)Tks;DU-sS1nAx14H!EIEdL#$)d_>anD(feLpp5a*B-!)@i) z$NcR!2 z_nOq0NFf0p+|x`QR=858+-fLO@b_#mt_VHsw4_evzn$*NzkdRZi#U*uR3iqx zM-EB8ibrgKBn0({3J(d3pFgU!y>qaqSp*)#BX8N+||gssIln2X8X101t+N+ z<`lICr+`tFUGG9BpA}HcBxVlC4{3-Z!hSY*xFg z^Y?yj%7PJLXC$^0f48(nC0mCUDE{;amS@&0TS+pv#8bt7Yc(30CvD{Z_2KIG8E#*+ z_3N@(yh293xJm1vt~c=aW}73cq%&|-^p%2omQtQCHj30&i zx}$2E;4>MieQsK7rE1&SMfR_;vEAs2nk}_1PRfQE5rJg+$5V}1y+E#ap~oiD2xn%w}+(`&04Qxv|c2C zND8FXJ?-Q~folGw1Sm(*-yTklMgVRMC-E4Ux?03=(O)EkP-j#v|Fc~H_6cZZ3|qH;qM9~7H=BGnWQucld-`kCg=@@xpi0tmb###=)T{5^QN-h#-0 z4D2f|Ji)B}r$3j&J>+3GkLy4A))bAQ+b)VQi3DU`!x5L5i@34sEdfIHPOud^M`VL8 zo7?UO+CQZdm#bo0_9wEf(~I?8({RQF5}8P1sA7Mo9Me$PB@CkFliNo-VEHK*n0(hR4hyz4noJ__oI6g{~FN zXEE~8TuPbyc!v4lFJO`oj`|&RE1Ca>5wg@+3vtT60O78wVfKZQUD~gO$7QKDH}p=4 zjWmmoBrY=lQ3O&DeZ~JEFcITU#gY?Eqm1;&)5Y1>EvlvzeprPlNOP8>5+LQPEZ;nq z64bg*bvOOT&*QE~UC=J5YOX+>`4d-Ju?%+LXi6M@-qiWD z2HCF`d7~Qtnb*2u?`?!BwIyGq0&%<2PuT|N))_)tnX-p_KY*goV8h26io_M{FL8ez z2}kLHUujM)0Wgo6ofT}4*OQbF0Ca)DP7R9$Li!PQIZn~pAT2cGln3Eu8h#^x8(DqT z*7~f^B$h&pNhSr$L~qrf_kEL=>tK)ymA58IuuPN7K-&m^qsRV@;bwvSr)1mL4A5=I zG3;}DaB^}1GJD-Li14mF93ESMA0$@;zJgGC4Zu0l@;_*M$0%8veciWh+ugHm+qP}n zwr$&(?e5vOd$w&Gvu*qI`>wU_-fQ1A?m73vsWGZ5BQqi@Gvmpq`u{59iB9ZW9TzP$ zZ$CT%$TRfUA(D{X4>l9jbo6d|#keCKaMDm`p3}~~d4*mmxe11=@L^=LfCvtS32D+l z=yEuOs|eMHAn-A!Kn{S3Mn-hL@lD4L9VUGp0e**^mxMkl1d>CksHZ%@!C)uBO04K0 zbyucpRn~j>0PgX&W4tXdP6*{x@?Ly9yh2jHC9u`1_=EScFb*AOD?5msI;^-yCF&mO z_IFG0buY0nzED^)pZ3MPnrPFN{P)om;5x5$6pP?@#9AsjcDpJ*5$bDsUz!hL8NPm0 z3;qG+tSWjQQ9hn=<_3c0&lWnoz9p2?PCk%YuI&M=OkZ#$B;bJD6{>3qf3#(*8Ui|J8a(^9Rdw-IW0CKju;f?v`JL3U55farkDuL z$ePv)#1j{be;7%^6GvF(5)GR^c>kca;ufrIkV(7R*e>=R>|ag^W#L($A>@{ZuHu^? zPL2#px#e}njSr42y>G)Ig@shZvM-;Fu&%9PHe^&p7CUycaX@I<{J9>FN{%$llf9Xz z6XfCY5rJIEjKFb1oTd9mXA2h)NejZVGYWyZK4Vr00-ArWY#@KASje9p%@cw}h*X@A zD9#$VQ4nUA68a|4d^P3;n9>X-Gg3g3qmE?7QtN?Cid{Tw3sv**xR`4CFmmPvioaH?D8H6CB#56)^?617{lUGPf zxSTr7C_^NH1q4LmUCgJ8@$pm$7zr-mNumGigTQNA5L zw%QyIhV)lZyx{1j^ni3TLFjleH)dC?h?Ox;uEkf4^(C(-fhKWwvDkz@TnhH-NL^f= zcA@?1AXFjnvmc1Zl}ezOOb8Zzr$B+4!ZG0cAmaMbl`q>Z<|LbjZ*v7B0EGHqrF+5j zIYu26cN;2G*3a|e&67#jJU-?X#*5Va1yLfewN3WI05p~L>c#6ro?37lm6pQPkMSiA zMDL|dUx$=}sPq$Akj$QPfOb2rR$8}hGCD#n@&V9o%O-9pKdGgADU%zhS_&LcN9NFk zh({R0sZL`Q1oVQk0~VX+)9+L0=OXA%z57gkB7vzJ+wYd(YzjRm2v&mG710nMHN zD4UEjKGEoef^B%wDRFe9}K`^%d9iceqQ=f(T6-}zA^WoVb{?7?O4X$AVj zCrW5Kg&>D?H`%dS6pau_0J;h{XI8#i00jWK@Sb8Mznw=qLGOsq;LYWNGaqP4IOKZN zF&U&~3>kkyfbdMV%q*QiWSM*^xgv6;U~xWTHXp!-sFP0vA0!432tq9z0DS*&J8(Hp zSb(C;`HBBY1yKnV;4aJ%`#JIVC@(Z4p)fXjd-*&p=rOH(;?OM){m)Dwo>#XfotL&| zF8QDjNaBPIZxt)pdHe2RcH{iLh8F~%W{K0H4BZ8E2JI@42djz&bY}qybP8Z&Kmk+F2>o*= z2=gGBA6+wQ2v6$KCXQ%Tq2!AvKF2GVLHjpa(1qZUN$o_EUfCK;pSg2V+-{C91jBba zadNxhty*3b6*Yjk3mCF22bixQ4(-bd^u;b83;QzVJ{B;9u?#s_MND`LP_@Sz9nJOa zGLh#=O(HR zdGl?U&9{f`k|QC1{Sq)?=fp-Y3tm$A39vd1|p`od9f}r>&B4+Xjl6m}LK@ z=bWNr{hX6#Y)H*lWP%`Dnike|S^jaH2Pv_B&hYWUb`i~}zOWi|LEswLHcrapz!AK* zsAs(4T-LVqj{g`%2^iCZ$Lt3%E6Wce`GshAkCEiU8VgCXsy5Kj5l^NsBmM?V_WP;A zvZp+{+g%bW`}FSEoW?^Ux8X)q<2hZN^Kt5edk;hdbr1l6sKTAlTY6*%^A&QVLLPnC zS^-1Ya{N1p*qCkyk==L^N7w*A&ur#;@w5nda!zkMYx-mHvCpizWQsE8-^_;>>-ue3 zH&Y{P8lj5w^ij>iV%>^2d47JcSG+R%*ouIxkp=>@qTbYsffhjO4Q!ZC79c~0u*f;` z*rZyF!>ZQeD8ow8JU{1GI;7&nkHj4T@(0oC?#01T*Hf z{7ULzHQP?+qmF*88#7d4?`N>gX6G4X-NLLV$C+lGCs-@x8fD$qeZPIL)Lu7^GtPQv zTP^wgzJtOq%I5S-Z9UoFD#xL|XvjhqToyMEm7|9;mcx8Q`gchzPHWI9q=y9Hd(_=U zvKlhk3n`g*)RU9kcY{)O_X;=6P6Wz3S}nA?r! zkv8?SPN$^4f<3Ckml^uIf~rpxy^4agfBlV{=*WZp_QdnL(?z3zJU_Pv;(>wdGZ-F_7!gFB<``P@K-P z5fEHmuDdjn+#44HVM+*siXr&1qtEv2<~Ea* zSE-m4|FpIaFUMc+`4kC`w`_>uw9_KLshGn0b{!-r3lZmG!G5fAmpsNAp}eg>UJ`rH z;sqLob)1C}b$FRPE<2_j#$eYwl`igTWigoh_~D*JdqoFM=_U7_X83FO^cZ7z16aOt zmFcDBJz;Jc)Mi^;!E%-ynu9*K%ho;H*?_jCdWdRvIS5rgYKDCXap5fdgokzDG$J;J z+(|+q%k)eyTPu9~0+1gN>Hbgg>wov*`iFmt`nQ3KiIFoDosx^8^WTmtqIQnoeky;x z{+)vXicVfxM4k5Aqsv6rz{Z4toR-es!pMov%*58j(ZYz<-q@7lpLygB%uHlmYz)7> zy#7^8!q(JI*uuz}fRXJl^A<%YIzd4@cLFVD1{PXY4t4?tW)>#e@3@+cjhU96z^tWr6sGY6z_rkYF7z5jPU4I>j;$I2&@5EnG`QHf+0!DU* zzZ2i?VRZ72c1B7j&IDQnbl-kt1a!(K?#=|?760>)|E^ZThT*%+KlY6G`|{2`H1P5ksq33Ud8`7j26P>V)g|njvoq)Z) zuz|AyowS{if%SK5+St=+lRMkHYf~uOtN(Wy{+H(1|N8&`TXTQc{O{`gkMjE7IeG#{ zj=v5=@h=Cu|I*N368c*~bP_h-Di`{99erp0EBF7nhW`Bu`_AxRhIZ;)iHEE(6E09W z0Dr!m0PQXv{x~+$dIdcpk#%9Ro9OGj!PYuhi{EMxQJ*FrH`|tg9kL> zyDw*;lW8$WTxj3|OW85k&ilY3Y0StgW55KlX7qbgcetM&cqOWL&ar^gBc15$+xRVr z7X>G;93Tch)H^BU$9wJi->&#NO2`bQ5?A~U(^!>jjZS$M;|`raE|v16a&gu9B!dd7 zvf0R8whBCOy>6GlA-+ctLDfT0Hd-%vMGmUfmIEF^DtGt}`?ji^z=9z)X=pC%TNqTa zDKo*;7FF(aHMaq6osy^hDCr9?jzJo+hVY(c2WdoTBkBVg`o&4fU!B9?4_$4P1q%$n zu(ZdoUq3YBpJ;Jor8O=sDzP+19(ip|jT*)f@%&MN*S+uw(sX1g3+IRf1br}p;9kQ) z2F(D^a}7Z$+Z2f!M~29NHevvQ!}N1DwX6d!Qg{*aggKTIGgo8P3Ij-4KOj3JdM`Od z;c#bFm@-yK_yD7$m&V&-uhTgGpenc!T#i)I0iz*u`Qg3z$?TX%&6#3nPF|g$RP`DU zHj^0$r5svOkqb(ly7Qn*2~#THD_=_cI`LN*tX;x}*siP#GSMg7(<+Qfu>-w)1gN7e zV`KxGs7kOIauYk;Y=Y4_lGFQI>VdsQ5&PNHNaTohRmuRviM!6cUZh{_Ua9KPx^#=b zCT4)8u3+$<+cB!t7%B2_0Tt;{%Co1H`_b1Q(ndv8U@;8;7-Ax!$J3kGqq+CZJ)gH; zhPQWg|e~v{SWfTzO zprL}X>_|HnY~ap0tqOro%bw3uL$uHXuJF6hOWlYZ#sVS404uMNG zTNK1b=z>?2ibb$L!^o*u>t;bCX+Icvudu zDj(N9&ID#(haUg#|Mb|qyRgK)Jo@~!HRtY`jV0si>H&QMe`bC@6^}R2;bRtI!L!Y` zL3Uwjy!|*=A~)$aYgfFcz4P#NZkjq_;N`sggLWRC#`bv(j-<*v#j_Lohq6hlv1Xws zuDbITZEa_{d8SVM08fxZSt2tx(|;1uuu^i$ZU=X9SaLI;w;D)mbgB&1Kp3xdvzpfZ z)%FhVDTZXRwbau<>Ye)m#q5?iBU4Xc(rM4GG7sjMf~lKy zhl}ha49puqku)spXRNGg+O{DnC`%p%Q6?ZN z?M(?c^tx(p&Ik2yv1%HT=|ILc#Hd0m@f&MY*_>(KL%X-CH>8)`$~-RiNmCJabHJx+ ze*L!p%jPxThi!<$f9R(}gW`Ci9j88u3G^{nTE=r~lw#CN}^VXK)aXMJ{ixqH=>@zk~J7Tx4>9mQnxK;!AT z-)~Kqw-LGAwxWnR&cHSk67}C-Pv=~NcyjF{T8DSeNKgV>#|hoRVM-x@ zb{rnm@js9QHU0o&Re@)gv6sY-|IAaGKA1H6nUr4Ad!HYa&k}sR}U(cF>8j~dZOb*kT zlCyTweSwd2KEhgfg(qlNI0VSiEaEvCG&d2QXG-VP_Hyn^Eg>S3UkUQ&)!hRa5rZhQ zm~4Dzs4LZ&g&Ampf~5TZDp#Ai7v!226ZAsDIpu}F-LF1y1Un;eHn=kPeHtN0I$RuF zFl4sAWF@uf%*9IV`lj7$uPs+J%e$ePmlie-uN_>-moQ?gCF@LQU+cAocu7BsQLCd= z%mx(MU!j6D%b;o?Q{3Vv5OZXU#9XYmSr-b-dV#r;Y_6;RwnG@=0WxaVd0Aug*@ZFs zr)bETbGObF>miY~6mWmC)3){|2j(FuQLLOOfK+s5p|2;9by2K?L_D*=J#e^SC4H6T z46G!FL6DwjjYCIz;|>!y|0lL|wyzd)9Hvn-*QsI1rQ{3M(DM)f-kkYip92nvllfbV zWpYj;C1(s=-u%1QvSz=GM#NJ}Dt)YdMPU74Tvs&@4w=qd@{Vp@zkzJ-UfrkYcOpYG z#l)ZY;Ta0Gl$7*LlW1=2Wx1nuOy(3J%|#_TxzCJt+Wz#!(QcD2X)(6-Qf5Fhg6U8} z(M(qQ^-{(h@>cQh6*P-AFa58GToAyo6l#mBtR?`k}P3~C}2 zmCl7?4MIWfHw*!Ppa#goCLp0I{Ne4KQGOKcIATK(FVOzchke|_z(|>&_gFS$S8aA( z=VGQGUR_=8ei5Qo2_1rO*HO7K=%IR4MyF3Ec!i%_=(^9VV|Jw#X<&!XX(wV2hzJGW zm6BCiSbd~E^E2XflSO(|CAnEesiRc=QzR&gQj~ZMM0St@71_De0;g#^BI9xP%9f<+ zG06l51^;7SF;EA(yhvs1G9RZ@p}oehbe=q|pk?bdhW>ugwaa#MKWhy-)DF1VpuS7N zBZ9h(IJCYuhK61sddcX^Wd)o-`VVh%ZF@!6ul}G~PcvK>P-o3wGb#;8E{?nc2MY+u zz9rcr`?C$>s*5r6%u}6>zIltfZXQtCwCjxXUyi(A$ z+X0&Pq4$DX@Rn5=0#K!F&e?-@QB$ub-D|7Jv_~|4-sFx)n9q(U?dDiJhn?D}8mmY> zbmgw2ge^m=H^B(t?@>2f>HvvjqWAP~x;sF03QBlD5jJ|HakhFA54AowBvJ)g7}Pq2 zFGm-1AL*X4A-*9T{*d?#N@fnfCnAs*upkVy8&rG)0QlK^G2$`{eqfP^rq56G)sh-? zlP;R>(c*ya^xjGmN?$Q|dAU(zGT{#u#Y*k8s2fRK)W^2?b&JAMwX!a~!Dp(fn@HYn zdHTe0qzIq{FvJi9X2hG5AL^LRPeh)Ytt5=>rqf;lw}bE?6^0HF2vsIBg6@hy^pE?1 zHvb6)W0t)siw5WR4GgPx08RaY9Sj$Pu&WQ=q_!3Hm@5oKz9!j}iSX0qQdA3s^ax;W zuX_fKX$I|XHkYL-NTgN*=ME!)AT@u_v3?WYlew^t>?>uUM2PA!xUApenYGj~1yfke?{!%@_V`1N+i)6D=5zTD)^%|hDs z%?dSsT<-BcPhY*Dk2(q5`hGJ3o2Ao6{UlbTR-!{qCsEyrsDk-1-3NIdnA_QU56 z3ilZfhGl4;h^ta&!bfxCOifltYT3#y_)o{j-V(<|Py~0NnR@3w7~!-;nkhDTUtfOX zw7kvyCE%Bo^=Swb?t~eulHY(RQi*pxF8g--fwbuK zxQefp9L5!FZesvF+X?w-r%PLSXCsAzn@^6)s%K8krcSz4-L#_Kku_C`jiU&RioCm5 zUFBL3j*gkku2Pcy84`&7?pfIdI;(~fYRe@D$lDBZX5$eh$!}i20EKJ?$8aY@*?BZM zjDB>dti4VtuHUBk7Zm#EyT@&yeiRnT%Mkbt%@7&REa&R|1ZHY&a$JFIrSmg$ZBJGb2dd#{0iN7WdI8Pwr`Gd2G4f^aAvNVS z+#toknSIWsgU7OV)sl*bEhr{M$YSfU9$JI7q zg@cE$s_or4<)C`+6y|2QP8!TViAAEfUt~{h!#ojgqPlUyZ_Y-=+k^)O@pAS-rXP=MW4am$^9Ur-=)jt z=PJlrK}gN4fqES=u#-Q`m-O>lSbR2vYAJJ_u@elNympEP3P~ER`B4HHXAmdrNkX39 zpSQ?OSTb20&Of2N8wh5KcFspXr9QPPadmRTe@)ZG12TkMh`fY5To*cA&#@2Y4+4oP zTryf3?(Zw&PhO2){*M$62^M!>+t#6tTGFFDxQX&KpA|3aV4v>gAR=#!Oz ziT-am^*07(qW>FQ{sV(D(f<|a{e?ll=T%^${~M6fi83*LFaL{=GJkJi_y-@Q6a5YV znHc_6goWWd@t4V`BEi2=um24>W%|ai{~%?5mHJm~$^3snPJI%`ZTtCQM4n!t=nN2z zyoT;p3cKA>>Wg%Qne!z<$nU=vC71$c<|K(ccF&wXFalW+Hqh^hd{MFq0fTCXcTiR^ zM9|>Jo6~ukVc0tM+S1hq&trjWMT~Ozn*v7=X}t7ff|oSPw)7cR<@72`iCv5+nA(kR zX;v22|D=ofQd7o|z#Q~}9Uyo$eE^qk!SwF`@!>!q0YVmy+(7QiM-83hQXU;?=D<61 znMd_6ghd-;mKgc4b6YpbqtciGO(Ul@ak}Z|U9h=Z#i=h~FcMOY6U7ndH*y>lqEim^ zpLMa)45$;wDmbHDpYl?v=cx2P^}%oys5#LQaM7u7W-1eKywSrMM!tfg43JeDGgHPp z#O1UD?}J9vVTd5F3JRU((YqXt6k#}_9TRudOnyL8(vOr4>(bHfHbz!J{^=Yj>SV(5 z;GkI35vYgn9p0jH0}4y>>+%0B{(rR5f8exiEGz^}jDN}P|D4k@u`zM{U*NP%On(dU z|0k#YzI^_vzW;liR-4Q5ycKoQ3$+U<^BEZX`XH4lji~J$vK^UhtNSVsAWP;p;sK?c z6ayEKyO)Q+o-cn(?~`+T)BEeK$L{O-$fx`3j8%?h^UE#k>Un$nv$YMaH1(2q$insM zh^Cc$vFzEP^_haWcTMjmuO-fHVJn3qtV7Pl5w+Zm@38P05Z-b5>(gxUzS9GvxVOk7 zS3C4qq*5-otmWYS(M7dSS_WTivXjMFn^Nq}zR0M;iPG2$>*5T>u)7k+Ma3fso67d; z5p?X0djaQ<&E@jAMyDp}0hE%8)JppyGDmNo%zK|ve&7OODY!;9+XWDbg$*@gZxFDsh2=5 zY;yR78Or?!go!k*&0K{5nyAmkz#u&!@wI11umyC%P9dUv#ljHAKWXv-I@&ERv5qJ} zyb#=khM{K6u;=D0j-AnneL#OJtY1F*M+GcgWV;FE!wY^0bUUJ3zY%HXTn6x&B%3pew|Bcf0(?XaxtaZ9 zy#9BUl)9#wv(2lqthzcRv!0?#6% zYU1*pDzX5FS3q=_+&5Z-K?7N+)tN3j&C)WqHQ7Sz|Zf{)IhOQFMMWMtaC;$dlM#AeWcyX%q9AF?Zwn*v3eS`;(POXo)S|ubFIA4Xb9pn~}0z zBMZSpKkL`C8I!2ypuDfVGQH}o_z=p6F>hCUN5I^)p!b#Fy%zwSN@lENk3KVsyfdj_ z$b4ZMgnc-vzKr`wSu2Zdlk*&~s}2>8%XpA(2UPXdoS?9iHmUK*E0U?ygM_MphYAs9 z^8NftZ6l`!s;*3eDnk-J3T(78O5zU@o($QVi%+;`jZi!7(5G2%m!z=jbtEu`9bGKr zGnpHqy1ey;nH+Jy-@-ZMYJKEKGMeGDCa0BiAx?GSEWrp!pjRA4rEv5o!Ki2c#QJ7V z(LA)?K{5Nk;0 z@}FXZ3c)4Y1=K6c0}nU>?8pQQQzjbbTMUS%%Yno&E;=jrrTq}dW_6P#+a>LEF}lVS}hUzmy1qZ`y}g#5GWnxOmo8b}c#JsTxqQ<-tM`|DThayj3YQjjYy6UZBR z5--I{GqfAN+jJJXAX{$m1p5&N>;7XMWcw7NU+uAGt?05!(04QZ@iF;PUNA-M))-0b9_X_bkkjl8WXuGwQU=_-+@fabn zY*sWU!JntbaKUe%amb*x&T~>pW?E zL!V~4_0S6hm3zk}7dS;+M zfHc+SbA@s)sJl{shAUW+{#M@?_Kn%9U>z|h`DTDFZ4YV3O^pKgn#%xx{n^ow7$%MTP^`$c6fAB~%5?m_*eA^K+eL`c(>6_w4`Z zqEe!d>`nYq546&LuESyq@?^$}ZyV5~Ag0iY2g5MfUlI#amlH#z zE&W18BIsC~-0>-N52u>S&cn!5qZCw1E;<=Foa?Zz^V{?z(7bf#6OhdJ=Retf0dwbq{O zXBiJ5Au#zwFXSvZTRc24Aylh)mo5?`qyEz#gnaYSW~dW(?@-v_J<^m;y+hb*NRali zETq7M+t8-~>G&CQekNFlqU4dq$mLI8ajNuu0kgYIliFm5w9lWAfap@gTt)RUW;5e; zMi=Y;dex$;0wA8Q+G@oEJ*X0)IP{9H>}SS@^=v+_DhCNq=tq^R4+v>*611|~e11o* z5arBuplod|v5`=EAbn5#x$ynKam6^ix`9C{q2H9JGk}6pt&-N$F*23pv-rw z={FpvM<}XbOI01W%c#Mxc?Lo$t7@@~5gehTs+hql@sRX0 z9*n1cc+T7ftyanf2!o(?>Tqz7*BVgVvJxTAA=#H`BZwbmF2QO5@AwT3XYm1;;Us~t zd8_(oLxvD2Il=#^u_-+L_X04rR8G@?;Q>cgjJll=b-I9Lk5-hmQaDUIe>BS> z(Tllg6Zaz4&Zo)lZfVWg9E$wy*C`w8Kp#M{T&hNLr{d|Cw#FRtTfa{Ei^0vba=%r6 zUmZ5s1JZ0z8r*Iy-Z^R{oznJxbU~{MWH8^HS2b7^^ahiB4~MX{aP{0LoacGmZ&&WT zG!2Z!x&ZVtztvv#XHC=J{I;HRUPAcsB;1|CrW@pdejnezqzrbJ%eS%Fg}09Fk45Kc z@wkA8NsqCxNg#XqL#%P&lsF(Tpg$reBQ2NDbc%iL2&i-7a9upTcsN;isR@^m9Bxix z(dyWHL>nYauf%GU@G;31imLNBse69q>j)NA#nKh)6lo~8;|Jn!hl>1RVmtc&II@m} zDBRO{r^297oO(l--nFk_p`~A^@hOtH^@caSYac5=q~x4N1dZV|A{GIu?jXae7QVM? zesBHG+~YPtYtHbsP-OE;}UI>29$vVFq)b);*R2)e|+exl5r zZ`ZWZu`B_YCrql)Yq;t_ov1W>FWOkXGSEQ3Uy`rreIsX>_Z4(T5f3G2X@QT`e#G4_ zq1l%oP(0%bPm8LXRpE~5zmxb&3jxU7DD@!4M?v~R@%?ZbONaIpHU2rfV;|-({ReQ> z=$=yy%p7`BZ*7F$Bix2na7hRZx!4`6E3$)QpJ4iqb>hImH^Won5%28n#^vjF!Z9GD zot9${-aRJrrl5bIPgJhfP1h&kx(oNTHOG6QuO8Ajy#g{WWVX5cP(mu^NHL#JWXwHn z28}uXeAO-Benzwe1$Zz!NQ_x^p)@tz{#?rw^*YjC`R>(JbY*{WTKQBX z;A1SP!b4P74G+wp*u?t(}49kJ_=NBF z39TwUu$xHp=R)<(&J+i*PomyC%XQqc>x?JyDvdv<$tsTZ*Yw{4iDl} zS76w3%!%MSI*?l*-CT!yJGhTIo{RMic{ct?QPF*YEeb_j=iuxV#Pc0=?8N_GZ|{ml zkteIg`at74vU&_;a-VSceEg1e=9NY1qi9eCW3agF_h*4cKbU9V6^>~;hS*-e+O?K! zmFWcNWVmlTi-r?%L5awuT~ennM#$J45Q~~yczp}9hlc_e$NW*cTlmcZL6YP(GwMqM zEeJj&fY-Ioj!R8GN32F*J8(Ok^nD}$)T}IaLlCz|k_G)nt^70aCV>5>t3n&1fFK6cxWO)a+b7CT=?X2rz=|!o@ zYWdamq5?lGRB&y!Pv-YJQrlQ~AN^G?N z{MgoT^59&6{x|?|uC4@>u>5ngqw9lfb7Qdl@P^OWAm*zXnOf^w9RQ6u7dSjs0;&K% z;NjsJ;MLqz(cKW2_+(D?>3b)kU}|fdfq{urRGbf!jREc%B{KmqYk^k=7vS>uY)#Ez zfymW^df|TQgZYOPLHAzffdDu<)33 zZa<>mUnUab?4B?603I&@)Y<&L0P#s_xV_VZhhKi9pluzk{ zNZQ5*$E2?uuyu7R4l1?twm)@W)a;L2(Zt^7>S`%hftT5*!SQ#fcM!?TWNv;_ytk+s z0njqkx#D_Z6CbS8O-&ovF9v>+EeUjAq_{_?AwL^yu$ipRCuG1g_8qy@>j(i)Kzy)f zKTff5jyvbFWbzu)Vl(V~2E>FTO6zDlddbd7aj3+LT% z$AMV1r9NR*6k6-*x*r4$nEEQq@5ibtK!Z_vE1bj0bouwE29f(AMa_4f(GGwOK|JE1 z?_@EQ5Vy#ST5}}q3wn$WDkDl~6ib>8v?Lj;d)W)2zCC>0>wr(>jRs=)CaXJM+7T}# z2%J0Iw}8po%-J~R>PQp8qYzvM==faad0ffAHm|dmisor+SUCsp?kiDUTK}PsH(h(F zK^|zZ7c5l<@i1X?aFSxu3!Zwp&I4QarJ9cv(3vNVG2sNp+}l8<^7ZvG;dWKcIP*3^ zC6|P(jLltdm|DS#tma#3cdX()p#SM{h%Ky!h&QDWfs8Rgjizi1 zV~RJrwHV@koy3Bz9X(}YErk-AMd)OSCP;CwuU7k5Q{1kulP;|9>S)+l% zO@cs-qQtL;OasBPc(+W^q4_1e5;oY8+UehS%GU4W)ckR z-3va*(_Gb!V;F*A1HEYU-kqV$CoR@vo4@#u&?Fr+rr~C8lixFlgOtw!$!_}Y9%T!w zf^Itl6IlGsmo|jN#RHbBuq`{{0W3W%_S=$>yi3m(_e*xtg8~_WN9LGifo1Nr^uECp zsgr#`h7{VGRW7^NyVTi364e3?8dHj$IG3qkWpV22%Yi!xKF1>3s?aa!9;ASPazUG+ zknlKFHq+@uO3S+!?+ndThYbBUIC#;IIm{^H+^F;U_K7%f+7!lN$BrHh`%DzLhkeyk zV9y@E%G1>E`F)1R_7r&d`mjiB-kcLc4Ci?g6m+pyqws9K)1>Myy|Qp@%6e6_4dX+g zPN4BUv4DNNMgh`t^Y7_8I}I*dyG*pYLDR06N_~o@1%i2O(ukPyl|EDz=a2Y#2c|sC ze4*^zJtMaY$L@()3S}_OOoV$Q9-!wGJXHqFP{|_aYNJmMmL4JXyb~0<>xaR8F1(Rx z4St&(EPzI1epodK@Ju1hzH@D9Gt|8GxHhSY=4&2SJ~~NW*$rSaW7<&pyT4A5z&Hgi3k3h`i})?KoXHD~uYt7>hk@d^Ff`Z}v`m zlh6_f`rI+_+}eQ7kgk>(Egf+}{NTG*eL!tsnD5!9^BeF8t-_{wcq84NW~4%B%mR<4 z__)l*1X2vrNI@b+rT<9s)@np@v_g(D1fZpLwy*so*x6zNHRM2j?zwti1ba&^m zNSQrW)k?l=uMiFCp9VPm<$?51gtY*6mSMd}WXW?rOjSXo{imZe&-6+!45HoAdugMC z3o9XgJ6w>Q6Ifu05t!l0BS4D)v!Dd}T3Swx{Fl(<$G>FaerukZH+xnlR$C=jcaR%q z4MSPF_lEi)=fGZ?KQZ{dY|LcYht8URvG`C?t)y>k+7-I-XOrR4_12K0qpA8kimPB9OiqgWoNuW*uaN$9K180GrcgENSQ{LsP;a zQSuR}V8O&6`#wvAYae2Ij_Qg7!-8p?ZhS5w6EGH|yngW-&(p)!CuUlSa65%XoI4g8 zwob>07oKOnzU2)Kr8MG4Q0H+mSIK9sE-Tz=zx{Z%TgCI7!u5`n*ax61pS{w@aNK1G zgK_5-M@bSw#b#lwI*lbQUz28@I9G3+hT)7tk)?s6V5RC%{ikhDO>YWJ@?CU5uAHmf z`QlB~_Hb}T=Dw}|^H9b^jHSmNIIucqgeaW2Qnlsb<9eJEyWV}UnClg7I2g11AOH#hu^r0ca-;$hkHVsICF zZQb(`ACe^rJSFrR4jfr?8REj^2GTxD%pkcs%*U7^^}fT7po}XTZ)0XX!xwt!E$wVj z0jQ&t62{HUyr!_6DAFq^qVX39<;MEC-UZTF2?#kFNyT-D0y`t((Ad=^ddry~=8YEs z-bo9xtG$~^-W;(&kL7{<4%%EBJ=vY+u%FC^ypLfQ%I2Z9sDZVM=BWI|ebRfVN9m6t z6u+(JWp+V|N;7hek(}=0Wm;_pl(on40ieEWP1WKWswK(0_M+*tBaaHEY6vJ4I+K-y z6`~Gz+xq z4kR{}#;BTO#``i6`T2{Q35i0FL}E=DUQ-3fs4|X89%sdQbg(4Q-y}ThT~iq=Oh<@< z5OF$7$u_9ncv+MRo0BusD2b1agjNyw9wZ#9er@YeaF%GLtWt1hUb@Z$*H_Y2;5y!W zGLPmUKg;^kKQ>m=r_hiBt)G2Hr-jWLi@W()F@|=08k4=YI?`~TVx+!wa+4W}RS5iG zr0))1^z9=(#{+eURA!r>jjDSdt&0LID|@evDw=u8LOzyL0Toc4iWN?BiG8riK!Jy~sk=@9lDhPUtp-=!!@iWv7u^;hph**TmcSySycJ&?=*#!VvFt{e4K zyp&c!2xNBrFd{aiK?Q{xFZQ^iw}~VN55`DkSjQpi?#tS4_hH?ZOA1Z!zH)Oe1V|kR z68CIj@#k#FZbjYYrYU!(~2J9Ki4eM|$z9Pt&IkhFFn=WO6o@94Mm(C%Ys= zdolTdz)3_!AXIVAXXQI1x+^aX&)~iBr50bKGSN>mDe;aZO)OlWA&R@c(p4Td%Kn@vmbzQJjwej!qy(ll z5==!V?55kp{~15aUns+ik{r~E2_*S@18d<3V%>fg36>!<*UImES|SpQiX`b4J}bfQ zhLi!(k|82~TQVBd$zVY3U^L&x*M16BWn{XUtK(dMBRKIG^Gt8)(XplWE*N48Pr;nk zoAQ8HsbYK(oe9@zaHqDn*s8J!gH^lJM1BYznda3?5iV zt5Z^HH_PA-;mM<~sr-8u1QE)6k$nqJ3|WFG?*9~)X!jAc?u`B(d54S8x+%^h>U``~ z_vJ58{33qO$aF}L&jg273afb+5V&F|KY4N5%u3u_@0^v z^NORTt@dgMv$xaoXV~3~Dtz)|DsxRWj_|pvQY6=MV(pp#TVKX)rQ{e-pO59HH(ayn z2Qau%L0U~1l@&sc&o;w&0qQC^H7yi673te4NB>p*uj8Hdsz4-3bSu0NL?9=?Zi+0O zeo@O8$_S^h#v1XO7yLKVNI5C$ca95aoZ@2Ynk`eNoIZ6vZGU79xOF=^v!aTTKUP=U z4nz~5`htJLx;73PPCyXY!-)JYKP!a8yEGlkNU^2vRjoKeB5xd|%o-P?b$^Bjx1g4+ zsR*>R{#>h`&tqZ1kR}U;>H`eEueh!6sh`kDu z(;*&p!mX#PBrY`7Q&Q3;RxKb~`xDp)?G7D#pGh@Rb>f?9vMs{8a~$=;CEj%*z&@Wq zpN6u-vXi0U+^gj3C|Kgk{9d%~IquI)->-3*Gofu1IYPbRh4erl@0_0Vm7BOnmV<2I znRr9@N7QHts`S`2QHRqJ_#hHPG6{6LQ-=i_gL#gkqK(f;x1TyzNOIWOtQFOq4#kO} zGf@3Tl4Q}!@pLVO{@I;Fc9wz30!MQa)Ex3-h(#E96+>!yFHRhLF0V*_$3TWiPJXo_ z*fxfZ4%O<`I$qO7_?QxebDF+vHn^gbF|lD^ac)LEG4jOOD4l&rLh|@Ck0m(hcsP8Z zI1*yKXJal`glk zJ!Ai%P`|#a_u$L~pYg!Cau-iMsfo5aA~Ren_DucY-b3u4GnDFa)-Uqa_(=y++@u3@ zl?dDXkw2+O&Z6qI;aCCVYX{RLv#j}9KlKBzb*16_?UR)Urcwe{;zFRNa z{bFqEPpL_43*lqixZGu8dGxJm4mLlGzS25wO1yZ@ZF~Y8<@CI&qZ)A~5#j~5=7EOO zK7dV6$0KaGi%|TbB^H2OY#?Y8>ob1Ql(ByyF63nKga(4oDbyl2Q1`zWJBKD=m@qJ| zZQHhO+qP|c-?eSqwr$(CZRg7&IV3rx<~PhtO+DQ`LKCX(QhLG-ffokTTH1v1!<_1{ zCh-GS?7gBrfrS@eAmYvGOOr_YqG;KOK;pJoqmT8iFl86J2;Qx) zFWJs`ULDtXxKfBkgUw%d8?Ht7TD7yEjw)y-EZx}z@#8hw|2p7IjBRgmx32vm8g*WV z1#&%h0%5Vj=T|Y!Xbw_sh)nGp!d8;TTWfL*9~z|z%6JQvc|1?mJs{vAzsT5E$OgOQ zWtV%adeALKRW`y^`Lz_$d_>>K#}=7P-x6!tL8jeqz#KUjr)Xx1H9oB5DAp>6#{CXG zSk2PpR*V>#jVg1(gr2W=(eLiSd~$AeFYxxeyP+SVgBYS+5+nM{yEr8w)pH;si(lg+ zFYj;U1G$6}Fq~r&&Sr+vHj2*dmAmJ36DQZZHX&w4WOyl(3P0@rC-M7_W7YH`5e2@ z3F+Ag6`9~Qg46Gp`epOtdl1Y!y?LH^b>#tzfSE7bT>W3=iP!Rx)C^31AO5Ahy>IFanmOnBfI*`6O{-L5W=Q@ zTu|er@MI0C)m5lsm~(s{^>dnwy;j(s;KZVW><|MNMB-8{bO8_S`B$?fh=*5@_hKys zB^d*(Yiru?s)Z{wS~{Dpf-s2#Kvr)UUa%ET?XCDXe41p5%=+CfUB+!r2w8hX+nx^F zPlp%#K&rBSsuN%+GL;@Uzq6dqa{nYcy7?o*Eq2Hb`x7$#TcPV8Bm< zy^FC(BGi79uGBE?qO5k`S6&f4`Ddw5X4+c`O^$~?(S^)RCL>~gA*#gej1|c7;*x@D zQ`K$CbIW-M6Pm^(@sf0@>y8EjMA~AjKlip5O#Ur45?<5)`QzFEai0sMcn4Z=O@>tV zM4Mfd*zuc)*VW|w`UnSS11`f_^B+w3YI zCQRIvkcL0_H<&WJp93XC6?8%Y5&>&?4F9+Z>Czw%{B>}~m%Mwk5y|k@V_%xMmnvjD zkI~(IWWuW4E2heXE`Re2*9G(K?;{3|?|_3jiptHIo%LFw&-lU|pck`bXp z+dBH!3yY^`CMV_PW9x`YhW6`Lx;L0K`Rr`hl^VYqE6W#Xndh+ig69bLl6;2<=U0ET+3ZKCB9DD_5=~&Iwh@094Ztj6~*GB_g~g<(Vf-^Jk>s zqXcO0q=1U}s*=p51omhw9n0OOrvCHCwSFA0Cn?nBKI&YZf22FVdCo0FE0#~^7 ztvsGgK>$UguCjWkwhmS-IE#h!Xn5Fl8wTqG1IG?*ivKvo#evrA-fxR+m@sK3e#NZl z&NO$|;3}90zjOlW8V@tdE}sZst`+c z$hb(x%5D0f*8z9Bt_vF}o(iinqfwb~P;^@WQBcDOyrjdM)K&&ZA&(4?`#pHDGI^N9 z#yIDtfxn4C^^(l+FsuD5j<>b$J;Vk1?li*YMaYxJDu^RbdJo8prEi^|;3fq9>=Zh- zF_p0r$hLzE`{v4JPM4(3iUvIn&7!7dh6a{W z+cR9?HCHV7ab=F3cK(1)5iJQp#Y!2LD>jY(LxxMn5k*m4N7#|*(?#*Td)jw;$9ZRO zR|mgF{b&7VxXW1>RO}o!BJP54qU{PST|AE^@87k#k=(+<&SM&So|M1=Vp<#03t=jq7ICQ znscs=%Pp3IqDk4Maj>A*9wgm=q$a#JyAaY1;0x? zaW?Tc8Y=TdtOfF-O3p7nr&YhjIx@|9Z=qkeK$!0VBC(Wjnk!pLM7Wo!{zq zP@0trw=UFL1`LrW!03$Y^yd=U2qq<)T*kzOusukHHh^@QJzW@!!Ax&^z7o1r{;z~c z$aJ0#Te0ZGm}RcvM&#Y2_G1*jxYLRSvG?HjS_jBVa@y3FRwQ2K-(XU$_M12Jv(?9Z z4^MhxjYUy8imMpSgaDH@C{b>CHH~HHmU}*YGP<`RnK~9hoSKZb;1XTIk z%NCW@#R{xsF9pfI@nAcQk7=uT;)g54eB1?#pg8eYrFQR;uMvyS9;BvLB5 zc|<1nd-I6^g(VmF7)}pQXi=PL3$3NYb5vGDZszRm!sFs%mM&%-F)o z;2re~NS-_EJil|QTrxBrgHU?T?!ctF7dE&&(n^%Ali9xfb=)ucK~s3oLL|J$BT0M{ z_HK`a?t!t@aTmbxMF=0TZ;91=__>AjmH$q(9}9V-K!|lc1Dx?nA{Bf@7ZzucxvB0<;cMkPlHM4XcQr) zHj`unE0O_ca9XXZGY3ACfY^e1U;GFJxm_r!EUcmdqhoN))Wpmx#3Bjb;_&jrhQ^+z zJL^p0VEIRzF`~K2VH%Pv<&GP}kXZ9*{IDvY_2pY)a`^p7T)Q=ccAfS|KhiDh%F$xC zXu@Ih3c&sXV_)z~7jYC1EVp|-%BpEuV%A(XzHstUWP2P_J&X~7D%-7qim3FTW@Hnl;|EmnjBNPPWzZNjTunzxch6#CDfPBL>Wba|m2l`V|(IiR# zk%i*Q%;fb~K8qd#fmy84ulAYPcF~YrJkJh`!Xd7Br@bZ(GND>AcQq-htM$*ii1-S1 zypz4}fO~rhjypJ5mZq6;Fxz!tt%A}NfW8JPiANtrDn;$$$u-(Xvy~L3`h6E&bq44y;Mqo0JW+epK#6yKdya3Q!N1_R2jm&G&=V+|x>!zr%Q1lCqcXG=Oev5cAOa>>Q zIB2|^Av#)^;^+3Vrd2-^6sLMH`LecGI;xCPm!jA|m~5?QH19lC>rg$oUEg;g<|tAE zW6MF(bnkM{TqHCkOlRb6>ktRJuhOM9rlosxWdXYVr2eB3dEYU(p;df|i3KTRo`5;~ zS@I12XwR9%4SE~<^fvLN@tC6=gMhwye1Q`O4J%l_@MFC7RKc)BBG&CfZe4&Fgmm<~ zy854ncKo7ddh%5v&Y#dXm7{QYI2eAV+WpzjuN9PQc9&?)bpd!}vN~h1k_QJ?3dm)s zk*A>!hv>$KoT>;BHv6gm?PH1@iQ}B`Vp}Vgg9H@*QuB-teBzRDoQ>yLD^HpK+HTor zy8QBa#KFq+zsQ*X1DauEVq*Q@K+XR}&2$>OnC&33Vr{wQuD9B1 z<7&%S$J%mVthe5{*!<6R)_azHmwmU(c)RXzraFUVy{g0d`rAY)L4y0Q_EInQlm><- zdb%5cRZB6^ zR&RDSRjn4lN;%V?95B;u)NJ*2brwJtoEzNTTA3Q4udA!8zAFm5s40u!h+o#~^b|my z+WB8dOAe=ijHITxm?D$_ZAm#`JQH{(H})1_@{Y`PwJhM{YU!x}x--_lkRay%TYkX) zWk3tFA9`83=sz?77j}2IAMx~%rXXGcK_OicB}qkG0>aT^Ixq&XOu*xkKTGh=&imgX zHg?z6zcrUdh5lzP(|^wN zP^V_AcCUXI?0;i%{&vgLfEH&j{;}WY(f;`3B=mJOHDsc1eW35|nm`tp24=9$Amtsu zMvsEn)QX=N3cDXb>{O;)nSwU+H zR1HP*j||&qdBI(|=Vq0_hhkVfohX2@Nb1l<@DYURNQrPWPy)!<2?m!31My~XVJ9>r zZ$&xEkF26kF^BEFivPp&fljuW$}Ul`fkhU4a=zr%=633mX;!T3r<@>Vl$m@{tqh2^ z-ZTn|PT)AMN*b>B7qz{&+Y5Eaw3!7P4J5n;yv*Az*qu4SR=-6OItizHLvdKibuo}3};?WNA2}6<%utWe{7TOLchJU?Zu2!FHaI&N=Y3^GwgFV5WSZ8qBJOGm7&SH8Et3Mv}T1Etcd_6FX5&<$S* z7FWo_0E7FYhmH(cfp+s7Qew|det1!SVaZsE!gZ^ojdF`K)7=pqHkHtW_^|~d z&NRBDIJit>T|W$7zuW&I`KXpo!`(5>LGMAIBG_3;Tq&%B$J^E4KHVOm`Pfr81UA3rJzh)CT)#w^tx~dk+~_yxlf7BqHG}cC8T@xY5BYjO2_gvnjCuss zuF_qtNc*_Md-@ooHrg&xctK&I*^uMY7N6=WK)YEFPI`C8uZ^PLzJ>EQ0tIf(4CUp88xL zn0zqW6%?jKKyC?_kbsm8LPAQ8?8z*WZ+LKbLPn?KXH*?$rdB6VIyLAl_zi&4e~i#m z^ID3bJIyBKn$U}&fQaSX_XefFtn0gXr!8$=%(3-0DbPJYzRY1O;(>p1OHCbD#YsSerAQ({PyrbXQFllRc@8ZD1p79X?8p~X)&1L$ z8~A3#QuD2MyNG>6QP+x{!&*xe8;|p;XW(cu{lu3p{?3ykR61cIMG9b|prOf%jgNVL ziM$T-K+$%es%Wjqih@jd856$dn}+7xJlXm@-v>Gs?~#Qbn_FUR0SBcA0ph;(WYYJa z-6Eh^Fpr~v{djvBn?-$-u)-GiYg=9rcBXROJ2iTE^4>$@BU@Pmhh$IeXl?y_Ds8`# ze&NDH)L!=mo%khxR!Wn=UaOyL7zQE9)%)K;1ap&&N3=?@t;a)!U?uHqiTM!jVGU?? zJOMB%W&XX#qJl)6Lo)0g9%I^46^ePUz`|4Phk96+Vn(0J-$hvhJR<#$4~IJlSalSz0x@8c$GW_6hw*&y<*?nZKESsJ0`84k)H<9{Eo zWveoW;1+kxtyZcdjGf)>6*4)8jK>-`3Cb-$E1Pio2&xaxaok;Zsx3l9{rzA6PqY@h z_@ZLG1QuTNK*PHx%T0Q2-LxeoT)(kuuW;mqW?{#(V{H6+=09twi3{N)WQTv9Q#bPP zk_p4m%WfsHXx`Dq1RspK&Y_M`rNOs2EUu?v?bWNhuRh7;3XeP~bwhQcQIx1B`pPFLQl`H@4(WqsvRV)><}=W)Exdbp)>k zcOyP8w7xs#&P~bA;8`?X1FA91Gq9dYH@lBs%2J!r^tjsYfLAAI)basvcoBOJuB;z$ zWh!DP3QCZ2EVBvhd{NyA&5dvT(J%=aM9ClMCTx%Sqo6?;NKLi%K;iZpY=sGO^G<~SP!$|}G z4$B8^LBr*)8q2#aU4Lbi@Nc9`TO+(ftZq{)3wLU8H-ZLK%u#Q`p{CR@A;;1r;+;p) zmviU}YVZRu-$TE2Calzz{O7N8Vz!2uq^W>+V68N}~5D z0}ZD^kY7NT+3VXDR7~1zJ1qC&8=+=owJSV4ECjwl$I}Bp*>ff3?q(|B<; zXN=sFN*jy+A68r4_2Xyoz7z0wND|H`I&X$xy6({S!Dx3u1ZX{ z5G`fzj$Ie_;!~@K^m_ssxxA@w^x=0{<2O`8cu_O=CF_Y|ll88tx-r|pLhHzp^zQ{- zrD?M~cPw*ry#IvXFdLv+J%UN}h5XH7G)?9E4d$(Rm{pnkxG_y{-cy97jL$EIGw0D# ziVmuWHM`q^X3M87xR5KVHm}kc4*MdkvFiD30te69>`E8}-I$M1`fPxemPh5SmVVAa zD^Lr3f7dyubHDfX@2=EE*3i+SL~Q$?m_8Fq=BN>i;8K7?wcZv@hFup3*hDF z3y&B=lm_c_%g6lNA!EBZk#p=_qL`UB8ceGCfk+#wOO3bBWK^R1`0m%{UW}*#8j@*_T6vSn z3UK0ok3HSi(Xf_q-PbdRj0;h)u?Q<4+_>PES|d(%R;%h?^ybLw-Ik*W-(6@Mn-++w zRZ~eqG>e+4IZP`G8}nby!c9S4KKvS(bw5VoO{fosO)>dUqgJ8~tSOpN&vwDfQ zAMAeHwY&_FXxj8AKeu`lUt!v>Hzcv(b`W~X`B8Xb_c%^c>+iR%ikGExB*)+Bb~I}t z1*4&r3b_NtsD^ijYc}&a?$##ynjN2Ir8KJD_~lX?m9(rGIxf_&HuA4H%# zt(+1#?MG22TdYu+wx?L50EtZ~rEU*JvYSgZX$jTLv%>00vXIaO1|E7G`IWMhL+XLe zeFEj=OVUIpvYJ@W6UE@h2(54L^_jeRBELv||{=C4efcEdVngHEzJDArXd zha4LBTbb0Ru5uWuSbi_VVYqxSgC;fO^*E_q9<}(+U#*nU#{~Ps5Q8Ysegy`-Gep(@ z{Cf19-|JLM$_mfeol}6VPbr$0Ko{XvwkfRXIkZwvh7Vjy$U)AwJNb&`2sa1pr-b7R zJY73muhRYX<56@f^wiP^=38 zhUVT}pKC|EoGWJ}d<6Awp7r_iH$@~0p?LVwlu4Dul$2ydA%5+>_(6r9C_vL<`70?~uRu4Vdc|Uz{ zAX%C@{MC22`Lja)Zlv}zayoh~#NwIQHeP-;4S`fjs&r=R!8y<=c48TMbVOgW8=e;v z1IUIzhXh^fl9Vv-q8gUlu25cdIR>7f{$QIGx#;{nyFpEv6pm3omf5O}PUr6(RKs_! zB8=pZF?!YC+G^_@f;1iH4-YAC@eS2TohSSn8+J@KxYjF7)C7gU9tv$gT0dF(hVV3W zn1#u&1)v5yXr=qWnFQ|h`buE9j3wyOb@?MKqg=(+QYdXoS{q}|EA`Q0l|%Du8xG9E zPGvJl<*qoK+)ajrbd$~nmO&Pi{%w}Yh!FFk2(-R7vPsw}KXp58#D>9=R(Y@K2MmJ~ zXnkHq0)-g?5{c^TL|7huQiy}8PP~8{O7zer($Sv!r4Q1qH6`saloeI_#YWtVeR>L3 z*v^`_Z=bT54`bPR^%sR_oY`$hSN0YlowJ$~#1)bn-uWB*q45h~mH1XdV?)^L{zMX3 zrdQYqit&4JZpMH;^dKi}+@(VJToWEe&tLCyf6RAXf-NKbHd#w_5)@rUb;8!fpz~}s zBN)>&ktgaZtt9s8T7ji=$n3qpFVktyKslLVAJ=X~IaGzJTkS*>U{cb^fq<17%=Rpd zh0Y5WI&-l%I{OUCa*#x%#57@~a}R1KTU+7p~z}m>@U#q8Nn94@z*f zhegjV)osi2&@5HUe;KIVasOTh*nVvd$_>z+3=t4CG=5!s0#1e-g;4o%J zwe*8A?4|q+WB1p!X{V(aVQ5O(p4;C5L z79E}Yf>9sCl#QeCiQKS1Y?;0_6AC(!*Ap5(xG-tWlLs^}bLvXbo88&!>Pc z=l4U-%*IllPBiEpCE2))b8BZPoEi^VTg8*;lX2Hro2W5-V)l^l3V~8Eg}2@(WJGvSb;7UyAvs!|4!M?_)5NDNL@#5`7|s}c z>3PW}7^g9eWie%vAm_cv!Vpt119a5Ka&=N!O6;xO-1K_@M^z*lE^P%->~q<1xy6lm zwcuG8^YXdMQT?fsX7Xyh4|d65U8V@QXNb29mKOj1SD_BP2{Oar3$}fDUd?&PpKBX2 zE`m~HcyILL5W`?5jV-2|j77j{3iHM(1b>sX6u47$vCx!0!CFdC#UTLDpdBMQoQM&8 z(das-+`DzU%i{{ui5pd!qCpQN{;Ebj==X-n6Gx7IR4&VjD`j`_6GvA3ZXEa-sdd)t z!8}hU!S4{4NxF>4)iDFRX>?5L!-hU0t^+@%hIe8I__g8n47g)&>oXq#kuCbY_oh%} zxM-_c6d6ZK!fAutI>@}Sxh9W!kK%O;-n}QhJXLOc%E?Zgo88!Ml&w7at+SHC`V?wZ z7+W20q^gY>X>#J1j3i#D{Y)L<)~|>XK;W1ELOZm)>RWb{qkZ=o$<8uY&Bo``H%PB* zd^T=Lqx5kg5<}EqXIAOWOijr=JgY-FYGJ!rw(M%jmM2HuT*5tIsQD~6~Ullph>j4z`6Ud?(u@) z2os`GN3&10&Z{YN`T*blH8D&PtA$98ORGi-{~1eBv9Qnh07_Dqf%1j;cX7vmSCB^w zY<97vY~zF=GD3v@?7#z5hGMC$36)Q4OSCZphZdsbGGDE3nK)c5yGGEmiwaN4Jf_7Z z>BJ?XO|gGdrm%JsJMWhoV`}Q;#pM?vWDlKHWOocO9cb|sr)pyiSi;yXf%Sz&{JCXL zXbl1IY!KiaO-Q~En48}ULc*N1yw>5?n^jc`1yYg;d55Pql|i8OmmFC;ION5IP=5qY zHdHh3@AWa`3{Ef6SOzuu5F&eya@5L0Ta-zJezU zBy$vE)6aK%O4O6&l2`ntsaP3ypOk^M6_I5qQ_FhXga-Hmon6nSl=fWGvh%ZW<>s7b zu>Z0j%pb)~2H%8Nv`rwz6JZ*ie$yixMF z>_q~ObXQ*nr8MBPTZaLUazfIP-0S%54;Q{p4P7WCyq=-rIrDc9`>ce%bT%0MijB2=z%V|x!KYNp#b^zMBZ+8yyuPN%TR$dV2g)Slt4Rde8KSz3p!NIeP5hi~;7L;{zg>%)oieg?@5cY=xtd zC;ayfI2$Fkan=Q`hkaDDOmCWBpdg{K=ben7E*OxYRD-bxJ%hn$;-|+~IHX+_)zdpT zD5o_K^wWu&L-Ct)S3tJ(%JAzXZoKrQm2ZI(Y2R0~J;45BI7aPpHV4LT{Swt+?SJFT z<~Ozk>T&MS%E@gw2E;SmRP&B$?FgAucku3ZPhon+rh;1oT*n2C2*bS>onGgvKB@R~ zc2aw^;D2wlFr08JP{SOh7wh61ym#`KGBUd(a1Jhq?r2 zY$U`88eBO5RQ*QJ8l_+eK^L>&F|%-bcGRZG*^Sq-A>>d*;7$mv_|F^C-ua-MRGE+o zDhAg*{MfV+(sf{a=W9xryz)BL@HW;=s9A(%eCNq))9)@U#zV++>GKHz+h`@4d+Pta zkC_Fww=`eiZ{uMI?^dh|Cl;}_^F>i|*phBhnmDI1PLL2$386!Z()<% z5VDvh1}F6=%|AAF`L#jHMXM;6X(GzWBgJ;+!IvHfkA90CP|>AzU(FWd)f+!5KVyfH z_N=>8y691Hivan;>H6a`7xxXAoU^g0thfyPg2W0*Ygd=WtyPy+Y7)_J2i zCU(w)VYF}yPw6Lmab#R&Gl8m2DS`9mA-7HXffc%y56<{P2R==r@Vmg{Wv%5QxovXx zLw_18om>kOz6ius?hFVz`qHGr_-(^7L3@$-b@>=tU#sXYPx_)-Kl+jb(T;o3J+J2bdtDHi_Sa`a^fQ)l&YaA5mOB_7V#1Tr$rYU8l4w}bZ;KTlkWVr=!xA- zm2joaJYL*YG#<+JKQw>iNtOw^|g?Cl51AkhlR zuu&pke#e#$S$9?26GX@b%kgNsY!(}F)Giw32x6odOvVlsF^z({?wU!JZX}HOG7hfq zD_W+kd|jCSc=%uv(^Rtu4h<*h$O&HMr=w5FVeEz-BfX%Qghj z63A}bgp4`ESlUi#);I+GG^s$N&1K>86NajLW~@%pu@KIN@4Y&8D{cpiO>d%&>~VMEm}cr*>i4YLMVD^+}kJdlbEUg`&YmQ}V&jqDg}a z^0{1;Qe>Aw^yUJ*-jlGSENt~Q&lx5|C0FF>;E3JoMB8*g75zjU$;=ZZ*vgAQ+<^M3 z>v(wel!CU^#RK%!Fu=;$%_-6o?`5|k^ihRsTB-@1*Az*rfHgU0w(8dj8R8U#|NR)Y zd|dz&eNSlrB-DL6$NQ`)`2-zbf*T2E+~`QxS7N8k zlHS842X_7Nub%pe+qEi!SN9VS9*e;AB#-RMJ+WnO6M|;rEylCJMyEh*m!pw*{9!g6 z7EB?pOlW^d0c> zf-i}qB1h8X$6bBp)!jKEfyU&CQG-Cc`(%5JCmE;Nc@i~22MKwP^<7j7XF~g|AYeu1 z=hDQ9N3J*u^TUizzf0MKH1k}gQ1bBeuUP&I7IH<^x)&eZ#XYsxN+aex!LuyR=~w3P zaT_b<>a0wy!ddKL=6D%kSr#AA+FqrRQL&KfvWzJeKRxq%1&VEKGTO9|sDbK9M!XZ{ zxKt&%5`^~z2_dM`MpaZ&;qhHMam^7REooN?_l=)+`S+j&cQ4X`TZ>o$Mt(B5-n9_;3IWnP2LdtuXb;_u zv0in!R)#vPbP7icwgk{Ms)Qb;sl?@D^}wEAG2glTFl$?2?pIa8vQ%Lx2IX7K77bxN zg#IJxV_}_gf%v-j42xauJ9`WWqI9SX_aH@0YJ$iUPm{6`KW)zx{c~dXsN?Q^#B*3X zTp7=}`BzJAr@l}59@2=fRYifLc+eipy2Nt!WSoNlGu&COegUloyev)Vt^1+2Vgbkz z8_h^!osZ+$D0dvy+d2zcBV2|{2M8=7{0sRuo8Y%0kpOzSZXR1N50MmXyV@Rv0}e8C9KbE4neq+o zR-UnF;e*c;S(BG{S_x@4_Ii8@5okwYhvI0X^3-*$tU$h^IpU-?V5cPsdiA=g*m#@0buI#4mO08+IEfM%L0 z5!!E0Se!#?E_*kr&k%6Ec?ktMR?K$fYjy<~191N+*iy!>RdEC2=wM4z^6+6K%RqWd zkUH&PH@Tq=j~B6Afo-MKD%}F~Q9{tvaR}i-k(PVJ(>umGc zm|5u1#7?05ndnU`A9=6c1w_TJI#!OPtD-89IfiLk(-sB60XI%gTMD>%ram{GoAr+$ zpMcSQQs_$oj8*)EQW5?opewC_se6_AL%~AH!cj+6>CL{!6qFXtv()(yyTDHjt-tHR zPcskW9syTrvNeo#H?&qwlxT4Nq)VKYHM9b6HVGShCEw8*<7=6-78S1UoSuq zyAtGS4rudo(4){2XB&SH5+C{IhP!e|9fYAuKGx_&VGal3@5sVF(n~2~xq0}WMEq7V z#VG!nHd`U`-`i_X6onQ@+r?FMQsl7*3kQ?Fc2`kx8qI zSLBN`e%bq1Yynu1^02hJU;^ih;6#_InG!eKf4APhWi@+|ZYx#N8s^Gof9ZuOk0GYP zyK&IQn#=`|o#Zq_m-my@zKJoSntOe_F=xK}No(D`?LaIk0`brJNBr|Bk?jrRMG6Cw z=I9tyP8O-n?QDSTp>HmkKWHoJ_;B}hp)Q!vwNwW`jkeg8-X&YH@>$nJa%t-WZnf>w49FDCA;5qBe$yq^88ExPdKM~bJ(G^;IT24zS zsQe5%3SVl)RQIupjA)`os_VU!eam08%6`ybmaIBm7@5J_I!B z5KR*q*~QQx6Ui5Vti!050uIUWA@`n56bJKFS+1x@GYp=z9UI}t9&aJ6VR5?VUGu(} zg~<9CASQrCtq%DUE@1qcfD*V-O6f6{5k1lU)b-iIb{n_kmRT*D(#Ly6-dnrZxq(cx zUvDSJ*!NYq6X20Jx_~~o6JIqEIz$9J3aP`#J$ckOm3S!(vX`w zcI(yELfh4R%w9N)mcJqHM@icZlO-o@J)mLKx;6J@uobclBS%6$tTK$3V6 z8;ba|BsR~n{FD(vB@Gi8+_AB|#r8QPCzGy(wz*2onyL4fOOPb~+gUkKB4n%t_~$38 zn-PTJa%wp-y0i}8a%AX%=Yfl~$eppZ@D7y9~HI+kqQ)+2fZwN9uo$5Pve49mIjdb?u7cZ8H`%mB1J=PfPnLh*-k%py`H?3o zQZ4F~1Xug@4HPnZu`b9pexX>cm;^b_B-38DiW8X+eTc_EB|M%t@~XU9klbEe0O@h^yQOK*Tu+&*#C~^}e8ed?_Bp>@ z+tKVOP7Oku`Be$V zqjkBUOsxF0!cRmoJI;aa?Gg(VQv%D3RgF(Eeywm$sywL3hjJ<&o#Lyo#pZ^wL9P7U zab@PN@+KT5)_T>5oTy9~kY_OUhFwg_lDv?QVXOMumUh9?xYHhJLr*CxfCwT<_29A5 zfksY<+?6~jFwSPKEjj(>Nsxew?v^piMf)nVE}NRu*DO};LvyFg5+WCBBS`Z4+-k2) z+cag+i71wG?Z551)b$0NBDInFC~SFuQd{##o~!ga;vKuw;t{Y>dtK<(fp80JM-q@1 zsY@0(M`7fDDp|5?aOVuDnC+~`?Y}d$&T^O>Zf$Zltk8O1*VuTUp6 zQv16xdu+`ky0}}aLCM+v;SE!}>puA;j%BDaW4u|pqTkNwOg1zOIaRbnh=ykBaiNH+ z94!?{m)}_ze_pBy!B6{GlK!mHloEo{fg2VoCgq>A!{GK2-gRsI>tN`Km`H!=n(~0! zbZ^in1C>Kf?y8mIfw`0=%lZXt1Qt6NxHUrNC=~WS@H=~ak}{y9EBG8P6ZeGG+i7I#-%{eCI&|43HTLujegoH2NhRi{@xlk|;oxc^(@2qww zkk!vdjbE-V4t2EW#?*Hmzl;l9z}AxIZlIIIPwO-^+y$ooA+QN3Lhc~9n5u&xlv$uB z*S$r%Bxs-3Kd%sZV<-?(KT8+STYr#xl~w`=aj)7J`Cq)9Z$xIh-s&Tk5;t+LK9^8b zU|e)(uNTA8v!TMyPD&=GeyVblg85O7;zE_IinChB$EHa*7UdrKt{bvg0fEDSb#)?n zcJAASTG!Uy)X^(7v3#^3Os@cWjMAQJVaSPK9F#z1W${i>E>emCwr{`x!JWA?A8xK%wW2Dc zVns$iS!+kc-uq`;wW*k0yWe{Yf+jx2JLEpnA?Dd1*i_SYu`df8=sL{5qKT-_0*SVk?f@6I z|Ji=4bs=pws#k}0cVmAd+2}dDN8n55-EnFxm~D0iAK$8LRBF5nIR(L#_Vp?$pW52t z=_wDH8PC=fOpRsE+>s+rk`e~qn8`DTJ}m1Cwry4PV-hTNE+EPHxWw)U=5M6;RsRmm ze3$TEFz3C*MXs>CSuOcO>T6yGAKGY8pN{ssE=YFhwgFv6F?Uhn@F6k=3@1NnMdF1k zNgYhv94jKI>?u?q*Feps0aNJjX?qAX%^>Cu4#jAx=k55~%BCHZX02;AB&KKH6ZZ^j zZ9>31%WT5RKmI~;JFY-1Ww+=y>F$49yJp^;Q#@265j9^S`Be8oqr0%yyo-!>xT&^O zKb4>=VowYu%JJ4ed z%g&w9bu17`CcbIF@D(fy=`I)-_9s@VN6pb9R_bdofJZ3kT?&LSp+oZcA8vbVyW;;0 zQ(>h4_b`=zAzc5BUnFN}spRy-X_qBnpr`)_;o{)vM8M9$_8&1S1WZgnko12Y{|R{c zuN?0GmfCewOUD+Q4b6MGW=9JdW%uUY2oXg*tDS;%6{~L6^!!aAo~*gK-dNmW{i0^u zk-gB(SfUwA&eb2(5H?iE0q(l1^I03NFcC@eq$s!sdo|b`gJ2Rjz3Okbl=eyIM93x+d-&r(tv_pFfAxI%Z=tjZfIEbP0(LAk+ zUiFq1az6_TBRTjM(fWoL*}bHReyk3x*3mc`Rn_WYMpnI1v=7?q)->=`-IfPRVI@vI zF-T?@HtH{s%#C0ny)`$RD0Jv)o_|ldLYqgoj0opRz`xFmnW2ogFLeOvL@3}? z2poV}!6fE?^wrQJ7A1iLgVh`NdeN|!$4xb%i~ayb1NSdMHDIfUMUyn|lZT@LTlDY! za*kv$_=xLbF~QVVTr%Xo%(I2=@T17j4W?D-|EMzA9z;S<{ksL1!-ua-mRoJ5(3K`@ zHX-2bb#I_?wH;N`16Q8f@aoRPM^o`o>7nDThnr=&QQ9EzSdB+BWTDKs6Fkg`$)G_E zGKRX-`OufQ2z~p}RvIJnxOrhrTCTP?ws$lDq%+b`CR|vumuU<3vW$;pWc+|2s;D@N zRh29-6q+COm2Xax7;tz>&9q!Riv+!AKwig3j)zQzM>hr{wY()!VVBzwwPYPSw|AmP zzzLR4QzME+jqm1wY2+hLAaM4T4?@PI)*jHhYvS~PboF9DUhGT0B`IQCQ}irsY65j? zK-|nnyt=n&2M;HXLS&k-HmAu9GcsAjqltAU~x%z0OgF7LWn2r-bSQNskHa#>5@x3uY z6+=L(9t$e4FTGnN)6*or9YZ%Y{lXx=Y1Z##hzG zj>zJy7b|D=FLnjoE>4t1iO&(mtg7=pb2kO}a^Rh^k_pf(MPpYVEA$9u?Jum5>yU}`iN!oJ5 z=lcA`Dq)Qty9gT3@Pk$67-Cu>;6jXna@Mcx;0DgmJv?~7gt|}g!8Qt9wS`2%Y|1xG)gwG7tMmwICMDk1TjGPW}o^S6!MKvD%qW4=uigL4qbcc1)+ z6u6-3GO%}QH*nqE{O=5S-&>w|L<_?(0MgaveQcUZ*>%H$1fXsm*ZI=NebJg!S)VKF*Q*Y7t#N{XB|iU-r0

    ^5)W6WX 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 diff --git a/pkg/interface/package.json b/pkg/interface/package.json index 00207a538..0a2191f8b 100644 --- a/pkg/interface/package.json +++ b/pkg/interface/package.json @@ -53,6 +53,8 @@ "suncalc": "^1.8.0", "unist-util-visit": "^3.0.0", "urbit-ob": "^5.0.1", + "xterm": "^4.10.0", + "xterm-addon-fit": "^0.5.0", "workbox-core": "^6.0.2", "workbox-precaching": "^6.0.2", "workbox-recipes": "^6.0.2", diff --git a/pkg/interface/src/logic/lib/bel.js b/pkg/interface/src/logic/lib/bel.js deleted file mode 100644 index 77ee14507..000000000 --- a/pkg/interface/src/logic/lib/bel.js +++ /dev/null @@ -1 +0,0 @@ -export default new Audio('data:@file/ogg;base64,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'); diff --git a/pkg/interface/src/logic/lib/bel.ts b/pkg/interface/src/logic/lib/bel.ts new file mode 100644 index 000000000..6de9d6ee3 --- /dev/null +++ b/pkg/interface/src/logic/lib/bel.ts @@ -0,0 +1 @@ +export default 'data:@file/ogg;base64,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'; diff --git a/pkg/interface/src/logic/state/term.ts b/pkg/interface/src/logic/state/term.ts new file mode 100644 index 000000000..d0820cd87 --- /dev/null +++ b/pkg/interface/src/logic/state/term.ts @@ -0,0 +1,21 @@ +import { Terminal } from 'xterm'; +import { FitAddon } from 'xterm-addon-fit'; + +import { createState } from "./base"; + +type Session = { term: Terminal, fit: FitAddon }; +type Sessions = { [id: string]: Session; } + +export interface TermState { + sessions: Sessions, + selected: string, + slogstream: null | EventSource, +}; + +const useTermState = createState('Term', { + sessions: {}, + selected: '', // empty string is default session + slogstream: null, +}, ['sessions', 'slogstream']); //TODO consider persisting + +export default useTermState; \ No newline at end of file diff --git a/pkg/interface/src/views/apps/term/api.tsx b/pkg/interface/src/views/apps/term/api.tsx deleted file mode 100644 index 077263efc..000000000 --- a/pkg/interface/src/views/apps/term/api.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import _ from 'lodash'; - -export default class Api { - ship: any; - channel: any; - bindPaths: any[]; - constructor(ship, channel) { - this.ship = ship; - this.channel = channel; - this.bindPaths = []; - } - - bind(path, method, ship = this.ship, appl = 'herm', success, fail) { - this.bindPaths = _.uniq([...this.bindPaths, path]); - - (window as any).subscriptionId = this.channel.subscribe(ship, appl, path, - (err) => { - fail(err); - }, - (event) => { - success({ - data: event, - from: { - ship, - path - } - }); - }, - (err) => { - fail(err); - }); - } - - belt(belt) { - return this.action('herm', 'belt', belt); - } - - action(appl, mark, data) { - return new Promise((resolve, reject) => { - this.channel.poke(window.ship, appl, mark, data, - (json) => { - resolve(json); - }, - (err) => { - reject(err); - }); - }); - } -} - diff --git a/pkg/interface/src/views/apps/term/app.tsx b/pkg/interface/src/views/apps/term/app.tsx index 7db2c96a6..071aa5cc6 100644 --- a/pkg/interface/src/views/apps/term/app.tsx +++ b/pkg/interface/src/views/apps/term/app.tsx @@ -1,100 +1,444 @@ -import { Box, Col } from '@tlon/indigo-react'; -import React, { Component } from 'react'; +import React, { + useEffect, + useRef, + useCallback +} from 'react'; import Helmet from 'react-helmet'; -import { Route } from 'react-router-dom'; -import withState from '~/logic/lib/withState'; -import useHarkState from '~/logic/state/hark'; -import Api from './api'; -import { History } from './components/history'; -import { Input } from './components/input'; -import './css/custom.css'; -import Store from './store'; -import Subscription from './subscription'; -class TermApp extends Component { - store: Store; - api: any; - subscription: any; - constructor(props) { - super(props); - this.store = new Store(); - this.store.setStateHandler(this.setState.bind(this)); +import useTermState from '~/logic/state/term'; +import { useDark } from '~/logic/state/join'; - this.state = this.store.state; - } +import { Terminal, ITerminalOptions, ITheme } from 'xterm'; +import { FitAddon } from 'xterm-addon-fit'; +import { saveAs } from 'file-saver'; - resetControllers() { - this.api = null; - this.subscription = null; - } +import { Box, Col } from '@tlon/indigo-react'; - componentDidMount() { - this.resetControllers(); - // eslint-disable-next-line new-cap - const channel = new (window as any).channel(); - this.api = new Api(this.props.ship, channel); - this.store.api = this.api; +import '../../../../node_modules/xterm/css/xterm.css'; +import api from '~/logic/api/index'; +import { + Belt, Blit, Stye, Stub, Tint, Deco, + pokeTask, pokeBelt +} from '@urbit/api/term'; - this.subscription = new Subscription(this.store, this.api, channel); - this.subscription.start(); - } +import bel from '~/logic/lib/bel'; - componentWillUnmount() { - this.subscription.delete(); - this.store.clear(); - this.resetControllers(); - } - - render() { - return ( - <> - - { this.props.notificationsCount ? `(${String(this.props.notificationsCount) }) `: '' }Landscape - - - { - return ( - - - {/* @ts-ignore declare props in later pass */} - - - - - ); - }} - /> - - - ); - } +type TermAppProps = { + ship: string; + notificationsCount: number; } -export default withState(TermApp, [[useHarkState]]); +const makeTheme = (dark: boolean): ITheme => { + let fg, bg: string; + if (dark) { + fg = 'white'; + bg = 'black'; + } else { + fg = 'black'; + bg = 'white'; + } + // TODO indigo colors. + // we can't pluck these from ThemeContext because they have transparency. + // technically xterm supports transparency, but it degrades performance. + return { + foreground: fg, + background: bg, + brightBlack: '#7f7f7f', // NOTE slogs + cursor: fg + }; +}; + +const termConfig: ITerminalOptions = { + logLevel: 'warn', + // + convertEol: true, + // + rows: 24, + cols: 80, + scrollback: 10000, + // + fontFamily: '"Source Code Pro","Roboto mono","Courier New",monospace', + // NOTE theme colors configured dynamically + // + bellStyle: 'sound', + bellSound: bel, + // + // allows text selection by holding modifier (option, or shift) + macOptionClickForcesSelection: true +}; + +const csi = (cmd: string, ...args: number[]) => { + return '\x1b[' + args.join(';') + cmd; +}; + +const tint = (t: Tint) => { + switch (t) { + case null: return '9'; + case 'k': return '0'; + case 'r': return '1'; + case 'g': return '2'; + case 'y': return '3'; + case 'b': return '4'; + case 'm': return '5'; + case 'c': return '6'; + case 'w': return '7'; + default: return `8;2;${t.r%256};${t.g%256};${t.b%256}`; + } +}; + +const stye = (s: Stye) => { + let out = ''; + + // text decorations + // + if (s.deco.length > 0) { + out += s.deco.reduce((decs: number[], deco: Deco) => { + /* eslint-disable max-statements-per-line */ + switch (deco) { + case null: decs.push(0); return decs; + case 'br': decs.push(1); return decs; + case 'un': decs.push(4); return decs; + case 'bl': decs.push(5); return decs; + default: console.log('weird deco', deco); return decs; + } + }, []).join(';'); + } + + // background color + // + if (s.back !== null) { + if (out !== '') { + out += ';'; + } + out += '4'; + out += tint(s.back); + } + + // foreground color + // + if (s.fore !== null) { + if (out !== '') { + out += ';'; + } + out += '3'; + out += tint(s.fore); + } + + if (out === '') { + return out; + } + return '\x1b[' + out + 'm'; +}; + +const showBlit = (term: Terminal, blit: Blit) => { + let out = ''; + + if ('bel' in blit) { + out += '\x07'; + } else if ('clr' in blit) { + term.clear(); + out += csi('u'); + } else if ('hop' in blit) { + if (typeof blit.hop === 'number') { + out += csi('H', term.rows, blit.hop + 1); + } else { + out += csi('H', term.rows - blit.hop.r, blit.hop.c + 1); + } + out += csi('s'); // save cursor position + } else if ('put' in blit) { + out += blit.put.join(''); + out += csi('u'); + } else if ('klr' in blit) { + out += blit.klr.reduce((lin: string, p: Stub) => { + lin += stye(p.stye); + lin += p.text.join(''); + lin += csi('m', 0); + return lin; + }, ''); + out += csi('u'); + } else if ('nel' in blit) { + out += '\n'; + } else if ('sag' in blit || 'sav' in blit) { + const sav = ('sag' in blit) ? blit.sag : blit.sav; + const name = sav.path.split('/').slice(-2).join('.'); + const buff = Buffer.from(sav.file, 'base64'); + const blob = new Blob([buff], { type: 'application/octet-stream' }); + saveAs(blob, name); + } else if ('url' in blit) { + window.open(blit.url); + } else if ('wyp' in blit) { + out += '\r' + csi('K'); + out += csi('u'); + } else { + console.log('weird blit', blit); + } + + term.write(out); +}; + +// NOTE should generally only be passed the default terminal session +const showSlog = (term: Terminal, slog: string) => { + // set scroll region to exclude the bottom line, + // scroll up one line, + // move cursor to start of the newly created whitespace, + // set text to grey, + // print the slog, + // restore color, scroll region, and cursor. + // + term.write(csi('r', 1, term.rows - 1) + + csi('S', 1) + + csi('H', term.rows - 1, 1) + + csi('m', 90) + + slog + + csi('m', 0) + + csi('r') + + csi('u')); +}; + +const readInput = (term: Terminal, e: string): Belt[] => { + const belts: Belt[] = []; + let strap = ''; + + while (e.length > 0) { + let c = e.charCodeAt(0); + + // text input + // + if (c >= 32 && c !== 127) { + strap += e[0]; + e = e.slice(1); + continue; + } else if ('' !== strap) { + belts.push({ txt: strap.split('') }); + strap = ''; + } + + // special keys/characters + // + if (0 === c) { + term.write('\x07'); // bel + } else if (8 === c || 127 === c) { + belts.push({ bac: null }); + } else if (13 === c) { + belts.push({ ret: null }); + } else if (c <= 26) { + belts.push({ mod: { mod: 'ctl', key: String.fromCharCode(96 + c) } }); + } + + // escape sequences + // + if (27 === c) { // ESC + e = e.slice(1); + c = e.charCodeAt(0); + if (91 === c || 79 === c) { // [ or O + e = e.slice(1); + c = e.charCodeAt(0); + /* eslint-disable max-statements-per-line */ + switch (c) { + case 65: belts.push({ aro: 'u' }); break; + case 66: belts.push({ aro: 'd' }); break; + case 67: belts.push({ aro: 'r' }); break; + case 68: belts.push({ aro: 'l' }); break; + // + case 77: { + const m = e.charCodeAt(1) - 31; + if (1 === m) { + const c = e.charCodeAt(2) - 32; + const r = e.charCodeAt(3) - 32; + belts.push({ hit: { r: term.rows - r, c: c - 1 } }); + } + e = e.slice(3); + break; + } + // + default: term.write('\x07'); break; // bel + } + } else if (c >= 97 && c <= 122) { // a <= c <= z + belts.push({ mod: { mod: 'met', key: e[0] } }); + } else if (c === 46) { // . + belts.push({ mod: { mod: 'met', key: '.' } }); + } else if (c === 8 || c === 127) { + belts.push({ mod: { mod: 'met', key: { bac: null } } }); + } else { + term.write('\x07'); break; // bel + } + } + + e = e.slice(1); + } + if ('' !== strap) { + belts.push({ txt: strap.split('') }); + strap = ''; + } + return belts; +}; + +export default function TermApp(props: TermAppProps) { + const container = useRef(null); + // TODO allow switching of selected + const { sessions, selected, slogstream, set } = useTermState(); + const session = sessions[selected]; + const dark = useDark(); + + const setupSlog = useCallback(() => { + console.log('slog: setting up...'); + let available = false; + const slog = new EventSource('/~_~/slog', { withCredentials: true }); + + slog.onopen = (e) => { + console.log('slog: opened stream'); + available = true; + }; + + slog.onmessage = (e) => { + const session = useTermState.getState().sessions['']; + if (!session) { + console.log('default session mia!', 'slog:', slog); + return; + } + showSlog(session.term, e.data); + }; + + slog.onerror = (e) => { + console.error('slog: eventsource error:', e); + if (available) { + window.setTimeout(() => { + if (slog.readyState !== EventSource.CLOSED) { + return; + } + console.log('slog: reconnecting...'); + setupSlog(); + }, 10000); + } + }; + + set((state) => { + state.slogstream = slog; +}); + }, [sessions]); + + const onInput = useCallback((ses: string, e: string) => { + const term = useTermState.getState().sessions[ses].term; + const belts = readInput(term, e); + belts.map((b) => { // NOTE passing api.poke(pokeBelt makes `this` undefined! + api.poke(pokeBelt(ses, b)); + }); + }, [sessions]); + + const onResize = useCallback(() => { + // TODO debounce, if it ever becomes a problem + session?.fit.fit(); + }, [session]); + + // on-init, open slogstream + // + useEffect(() => { + if (!slogstream) { + setupSlog(); + } + window.addEventListener('resize', onResize); + return () => { + // TODO clean up subs? + window.removeEventListener('resize', onResize); + }; + }, [onResize, setupSlog]); + + // on dark mode change, change terminals' theme + // + useEffect(() => { + const theme = makeTheme(dark); + for (const ses in sessions) { + sessions[ses].term.setOption('theme', theme); + } + if (container.current) { + container.current.style.backgroundColor = theme.background || ''; + } + }, [dark, sessions]); + + // on selected change, maybe setup the term, or put it into the container + // + useEffect(() => { + let ses = session; + // initialize terminal + // + if (!ses) { + // set up terminal + // + const term = new Terminal(termConfig); + term.setOption('theme', makeTheme(dark)); + const fit = new FitAddon(); + term.loadAddon(fit); + + // start mouse reporting + // + term.write(csi('?9h')); + + // set up event handlers + // + term.onData(e => onInput(selected, e)); + term.onBinary(e => onInput(selected, e)); + term.onResize((e) => { + api.poke(pokeTask(selected, { blew: { w: e.cols, h: e.rows } })); + }); + + ses = { term, fit }; + + // open subscription + // + api.subscribe({ app: 'herm', path: '/session/'+selected, + event: (e) => { + const ses = useTermState.getState().sessions[selected]; + if (!ses) { + console.log('on blit: no such session', selected, sessions, useTermState.getState().sessions); + return; + } + showBlit(ses.term, e); + }, + quit: () => { // quit + // TODO show user a message + } + }); + } + + if (container.current && !container.current.contains(ses.term.element || null)) { + ses.term.open(container.current); + ses.fit.fit(); + ses.term.focus(); + } + + set((state) => { + state.sessions[selected] = ses; + }); + + return () => { + // TODO unload term from container + // but term.dispose is too powerful? maybe just empty the container? + }; + }, [set, session, container]); + + return ( + <> + + { props.notificationsCount ? `(${String(props.notificationsCount) }) `: '' }Landscape + + + + + + + ); +} diff --git a/pkg/interface/src/views/apps/term/components/history.tsx b/pkg/interface/src/views/apps/term/components/history.tsx deleted file mode 100644 index 814d417dc..000000000 --- a/pkg/interface/src/views/apps/term/components/history.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Box } from '@tlon/indigo-react'; -import React, { Component } from 'react'; -import Line from './line'; - -export class History extends Component { - constructor(props) { - super(props); - } - - render() { - return ( - - - {/* @ts-ignore declare props in later pass */} - {this.props.log.map((line, i) => { - // @ts-ignore react memo not passing props - return ; - })} - - - ); - } - } - -export default History; diff --git a/pkg/interface/src/views/apps/term/components/line.tsx b/pkg/interface/src/views/apps/term/components/line.tsx deleted file mode 100644 index 5f8f5c131..000000000 --- a/pkg/interface/src/views/apps/term/components/line.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { Text } from '@tlon/indigo-react'; -import React from 'react'; -// @ts-ignore line isn't in props? -export default React.memo(({ line }) => { - // line body to jsx - // NOTE lines are lists of characters that might span multiple codepoints - // - let text = ''; - if (line.lin) { - text = line.lin.join(''); - } else if (line.klr) { - text = line.klr.map((part, i) => { - const prop = part.stye.deco.reduce((prop, deco) => { - switch (deco) { - case null: return prop; - case 'br': return { bold: true, ...prop }; - case 'bl': return { className: 'blink', ...prop }; - case 'un': return { style: { textDecoration: 'underline' }, ...prop }; - default: console.log('weird deco', deco); return prop; - } - }, {}); - switch (part.stye.fore) { - case null: break; - case 'r': prop.color = 'red'; break; - case 'g': prop.color = 'green'; break; - case 'b': prop.color = 'blue'; break; - case 'c': prop.color = 'cyan'; break; - case 'm': prop.color = 'purple'; break; - case 'y': prop.color = 'yellow'; break; - case 'k': prop.color = 'black'; break; - case 'w': prop.color = 'white'; break; - default: prop.color = '#' + part.stye.fore; - } - switch (part.stye.back) { - case null: break; - case 'r': prop.backgroundColor = 'red'; break; - case 'g': prop.backgroundColor = 'green'; break; - case 'b': prop.backgroundColor = 'blue'; break; - case 'c': prop.backgroundColor = 'cyan'; break; - case 'm': prop.backgroundColor = 'purple'; break; - case 'y': prop.backgroundColor = 'yellow'; break; - case 'k': prop.backgroundColor = 'black'; break; - case 'w': prop.backgroundColor = 'white'; break; - default: prop.backgroundColor = '#' + part.stye.back; - } - if (Object.keys(prop).length === 0) { - return part.text; - } else { - return ( - {part.text.join('')} - ); - } - }); - } - - // render line - // - return ( - - {text} - - ); -}); diff --git a/pkg/interface/src/views/apps/term/css/custom.css b/pkg/interface/src/views/apps/term/css/custom.css deleted file mode 100644 index b25bcdbd9..000000000 --- a/pkg/interface/src/views/apps/term/css/custom.css +++ /dev/null @@ -1,16 +0,0 @@ -input#term { - background-color: inherit; - color: inherit; -} - -.blink { - animation: 4s ease-in-out infinite opacity_blink; -} - -@keyframes opacity_blink { - 0% { opacity: 0; } - 10% { opacity: 1; } - 80% { opacity: 1; } - 90% { opacity: 0; } - 100% { opacity: 0; } -} diff --git a/pkg/interface/src/views/apps/term/store.tsx b/pkg/interface/src/views/apps/term/store.tsx deleted file mode 100644 index d2166083a..000000000 --- a/pkg/interface/src/views/apps/term/store.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { saveAs } from 'file-saver'; -import bel from '../../../logic/lib/bel'; - -export default class Store { - state: any; - api: any; - setState: any; - constructor() { - this.state = this.initialState(); - } - - initialState() { - return { - lines: [''], - cursor: 0 - }; - } - - clear() { - this.setState(this.initialState()); - } - - handleEvent(data) { - // process slogs - // - if (data.slog) { - this.state.lines.splice(this.state.lines.length-1, 0, { lin: [data.slog] }); - this.setState({ lines: this.state.lines }); - return; - } - - // process blits - // - const blit = data.data; - switch (Object.keys(blit)[0]) { - case 'bel': - bel.play(); - break; - case 'clr': - this.state.lines = this.state.lines.slice(-1); - this.setState({ lines: this.state.lines }); - break; - case 'hop': - // since lines are lists of characters that might span multiple - // codepoints, we need to calculate the byte-wise cursor position - // to avoid incorrect cursor rendering. - // - const line = this.state.lines[this.state.lines.length - 1]; - let hops; - if (line.lin) { - hops = line.lin.slice(0, blit.hop); - } else if (line.klr) { - hops = line.klr.reduce((h, p) => { - if (h.length >= blit.hop) -return h; - return [...h, ...p.text.slice(0, blit.hop - h.length)]; - }, []); - } - this.setState({ cursor: hops.join('').length }); - break; - case 'lin': - this.state.lines[this.state.lines.length - 1] = blit; - this.setState({ lines: this.state.lines }); - break; - case 'klr': - this.state.lines[this.state.lines.length - 1] = blit; - this.setState({ lines: this.state.lines }); - break; - case 'mor': - this.state.lines.push(''); - this.setState({ lines: this.state.lines }); - break; - case 'sag': - blit.sav = blit.sag; - break; - case 'sav': - const name = blit.sav.path.split('/').slice(-2).join('.'); - const buff = new Buffer(blit.sav.file, 'base64'); - const blob = new Blob([buff], { type: 'application/octet-stream' }); - saveAs(blob, name); - break; - case 'url': - // TODO too invasive? just print as ? - window.open(blit.url); - break; - default: console.log('weird blit', blit); - } - } - - setStateHandler(setState) { - this.setState = setState; - } -} - diff --git a/pkg/interface/src/views/apps/term/subscription.tsx b/pkg/interface/src/views/apps/term/subscription.tsx deleted file mode 100644 index 178246e43..000000000 --- a/pkg/interface/src/views/apps/term/subscription.tsx +++ /dev/null @@ -1,87 +0,0 @@ -export default class Subscription { - store: any; - api: any; - channel: any; - firstRoundComplete: boolean; - constructor(store, api, channel) { - this.store = store; - this.api = api; - this.channel = channel; - - this.channel.setOnChannelError(this.onChannelError.bind(this)); - this.firstRoundComplete = false; - } - - start() { - if (this.api.ship) { - this.firstRound(); - } else { - console.error('~~~ ERROR: Must set api.ship before operation ~~~'); - } - this.setupSlog(); - } - - setupSlog() { - let available = false; - const slog = new EventSource('/~_~/slog', { withCredentials: true }); - - slog.onopen = (e) => { - console.log('slog: opened stream'); - available = true; - }; - - slog.onmessage = (e) => { - this.handleEvent({ slog: e.data }); - }; - - slog.onerror = (e) => { - console.error('slog: eventsource error:', e); - if (available) { - window.setTimeout(() => { - if (slog.readyState !== EventSource.CLOSED) -return; - console.log('slog: reconnecting...'); - this.setupSlog(); - }, 10000); - } - }; - } - - delete() { - this.channel.delete(); - } - - onChannelError(err) { - console.error('event source error: ', err); - console.log('initiating new channel'); - this.firstRoundComplete = false; - setTimeout(() => { - this.store.handleEvent({ - data: { clear : true } - }); - - this.start(); - }, 2000); - } - - subscribe(path, app) { - this.api.bind(path, 'PUT', this.api.ship, app, - this.handleEvent.bind(this), - (err) => { - console.log(err); - this.subscribe(path, app); - }, - () => { - this.subscribe(path, app); - }); - } - - firstRound() { - this.subscribe('/session/', 'herm'); - } - - handleEvent(diff) { - this.store.handleEvent(diff); - } -} - diff --git a/pkg/npm/api/term/index.ts b/pkg/npm/api/term/index.ts new file mode 100644 index 000000000..341e81711 --- /dev/null +++ b/pkg/npm/api/term/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; \ No newline at end of file diff --git a/pkg/npm/api/term/lib.ts b/pkg/npm/api/term/lib.ts new file mode 100644 index 000000000..e6ae877ea --- /dev/null +++ b/pkg/npm/api/term/lib.ts @@ -0,0 +1,22 @@ +import _ from 'lodash'; + +import { Scry } from '../lib' +import { Poke } from '../lib/types'; +import { Belt, Task, SessionTask } from './types'; + +export const pokeTask = (session: string, task: Task): Poke => ({ + app: 'herm', + mark: 'herm-task', + json: { session, ...task } +}); + +export const pokeBelt = ( + session: string, + belt: Belt +): Poke => pokeTask(session, { belt }); + +//NOTE scry will return string[] +export const scrySessions = (): Scry => ({ + app: 'herm', + path: `/sessions` +}); diff --git a/pkg/npm/api/term/types.ts b/pkg/npm/api/term/types.ts new file mode 100644 index 000000000..8bcdd302f --- /dev/null +++ b/pkg/npm/api/term/types.ts @@ -0,0 +1,60 @@ +// outputs +// + +export type TermUpdate = + | Blit; + +export type Tint = + | null + | 'r' | 'g' | 'b' | 'c' | 'm' | 'y' | 'k' | 'w' + | { r: number, g: number, b: number }; + +export type Deco = null | 'br' | 'un' | 'bl'; + +export type Stye = { + deco: Deco[], + back: Tint, + fore: Tint +}; + +export type Stub = { + stye: Stye, + text: string[] +} + +export type Blit = + | { bel: null } // make a noise + | { clr: null } // clear the screen + | { hop: number | { r: number, c: number } } // set cursor col/pos + | { klr: Stub[] } // put styled + | { put: string[] } // put text at cursor + | { nel: null } // newline + | { sag: { path: string, file: string } } // save to jamfile + | { sav: { path: string, file: string } } // save to file + | { url: string } // activate url + | { wyp: null } // wipe cursor line + +// inputs +// + +export type Bolt = + | string + | { aro: 'd' | 'l' | 'r' | 'u' } + | { bac: null } + | { del: null } + | { hit: { r: number, c: number } } + | { ret: null } + +export type Belt = + | Bolt + | { mod: { mod: 'ctl' | 'met' | 'hyp', key: Bolt } } + | { txt: Array }; + +export type Task = + | { belt: Belt } + | { blew: { w: number, h: number } } + | { flow: { term: string, apps: Array<{ who: string, app: string }> } } + | { hail: null } + | { hook: null } + +export type SessionTask = { session: string } & Task diff --git a/pkg/urbit/compat/posix/ptty.c b/pkg/urbit/compat/posix/ptty.c index ff42abff9..7c1a17f00 100644 --- a/pkg/urbit/compat/posix/ptty.c +++ b/pkg/urbit/compat/posix/ptty.c @@ -167,6 +167,9 @@ u3_ptty_init(uv_loop_t* lup_u, const c3_c** err_c) // Construct raw termios configuration. // + // makes input available per-character, does not echo input, + // disables special input pre-processing, output post-processing. + // { pty_u->raw_u = pty_u->bak_u; diff --git a/pkg/urbit/configure b/pkg/urbit/configure index ab5b3a3df..138f52a85 100755 --- a/pkg/urbit/configure +++ b/pkg/urbit/configure @@ -195,7 +195,7 @@ for citem in $compat; do done cat >config.mk <cax.har_p); @@ -31,7 +31,7 @@ u3qe_jam(u3_atom a) u3a_print_memory(stderr, "total", tot_w); u3a_print_memory(stderr, "memoization cache", mem_w); u3h_root* har_u = u3to(u3h_root, u3R->cax.har_p); - u3l_log("memoization entries: %d\r\n", har_u->use_w); + u3l_log("memoization entries: %d", har_u->use_w); u3a_print_memory(stderr, "unused free", u3a_open(u3R)); return tot_w; } diff --git a/pkg/urbit/jets/e/rub.c b/pkg/urbit/jets/e/rub.c index 641e53035..48a1116b3 100644 --- a/pkg/urbit/jets/e/rub.c +++ b/pkg/urbit/jets/e/rub.c @@ -31,7 +31,7 @@ // Sanity check: crash if decoding more bits than available if ( c3y == u3qa_gth(x, m)) { - // u3l_log("[%%rub-hard %d %d %d]\r\n", a, x, m); + // u3l_log("[%%rub-hard %d %d %d]", a, x, m); return u3m_bail(c3__exit); } diff --git a/pkg/urbit/jets/e/secp.c b/pkg/urbit/jets/e/secp.c index 6a4c6ce63..537606adf 100644 --- a/pkg/urbit/jets/e/secp.c +++ b/pkg/urbit/jets/e/secp.c @@ -16,7 +16,7 @@ u3je_secp_init() sec_u = malloc(urcrypt_secp_prealloc_size()); if ( 0 != urcrypt_secp_init(sec_u, ent_y) ) { - u3l_log("u3e_secp_init failed\r\n"); + u3l_log("u3e_secp_init failed"); abort(); } } diff --git a/pkg/urbit/jets/f/core.c b/pkg/urbit/jets/f/core.c index 753ea74de..5d7ef8015 100644 --- a/pkg/urbit/jets/f/core.c +++ b/pkg/urbit/jets/f/core.c @@ -22,7 +22,7 @@ (u3_nul == u3h(hr_con)) && (u3_nul == u3t(hr_con)) ) { - u3l_log("old core\r\n"); + u3l_log("old core"); abort(); } } diff --git a/pkg/urbit/jets/f/look.c b/pkg/urbit/jets/f/look.c index e54091b0b..038f7a522 100644 --- a/pkg/urbit/jets/f/look.c +++ b/pkg/urbit/jets/f/look.c @@ -20,7 +20,7 @@ u3r_trel(dab, &n_dab, &l_dab, &r_dab); if ( c3n == u3du(n_dab) ) { // return u3m_bail(c3__fail); - u3l_log("bad look\r\n"); + u3l_log("bad look"); return u3m_bail(c3__exit) ; } else { diff --git a/pkg/urbit/noun/allocate.c b/pkg/urbit/noun/allocate.c index 4536069a6..1737890be 100644 --- a/pkg/urbit/noun/allocate.c +++ b/pkg/urbit/noun/allocate.c @@ -433,7 +433,7 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) sel_w += 1; } - // u3l_log("walloc %d: *pfr_p %x\n", len_w, u3R->all.fre_p[sel_w]); + // u3l_log("walloc %d: *pfr_p %x", len_w, u3R->all.fre_p[sel_w]); while ( 1 ) { u3p(u3a_fbox) *pfr_p = &u3R->all.fre_p[sel_w]; @@ -568,7 +568,7 @@ u3a_walloc(c3_w len_w) u3a_botox(ptr_v) == (u3a_box*)(void *)0x200dfe3e4 ) { static int xuc_i; - u3l_log("xuc_i %d\r\n", xuc_i); + u3l_log("xuc_i %d", xuc_i); if ( 1 == xuc_i ) { u3a_box* box_u = u3a_botox(ptr_v); @@ -684,7 +684,7 @@ u3a_malloc(size_t len_i) if ( u3a_botox(out_w) == (u3a_box*)(void *)0x3bdd1c80) { static int xuc_i = 0; - u3l_log("xuc_i %d\r\n", xuc_i); + u3l_log("xuc_i %d", xuc_i); // if ( 1 == xuc_i ) { abort(); } xuc_i++; } @@ -917,7 +917,7 @@ u3a_free(void* tox_v) c3_w pad_w = tox_w[-1]; c3_w* org_w = tox_w - (pad_w + 1); - // u3l_log("free %p %p\r\n", org_w, tox_w); + // u3l_log("free %p %p", org_w, tox_w); u3a_wfree(org_w); } @@ -1065,7 +1065,7 @@ _ca_take_atom(u3a_atom* old_u) u3_noun new = u3a_to_pug(u3a_outa(new_u)); #ifdef VERBOSE_TAKE - u3l_log("%s: atom %p to %p\r\n", ( c3y == u3a_is_north(u3R) ) + u3l_log("%s: atom %p to %p", ( c3y == u3a_is_north(u3R) ) ? "north" : "south", old_u, @@ -1103,7 +1103,7 @@ _ca_take_cell(u3a_cell* old_u, u3_noun hed, u3_noun tel) u3_cell new = u3a_to_pom(u3a_outa(new_u)); #ifdef VERBOSE_TAKE - u3l_log("%s: cell %p to %p\r\n", ( c3y == u3a_is_north(u3R) ) + u3l_log("%s: cell %p to %p", ( c3y == u3a_is_north(u3R) ) ? "north" : "south", old_u, @@ -1162,7 +1162,7 @@ _ca_take_next_north(u3a_pile* pil_u, u3_noun veb) c3_assert( c3y == u3a_north_is_normal(u3R, nov) ); #ifdef VERBOSE_TAKE - u3l_log("north: %p is already %p\r\n", veb_u, u3a_to_ptr(nov)); + u3l_log("north: %p is already %p", veb_u, u3a_to_ptr(nov)); #endif _me_gain_use(nov); // bypass branches in u3k() @@ -1218,7 +1218,7 @@ _ca_take_next_south(u3a_pile* pil_u, u3_noun veb) c3_assert( c3y == u3a_south_is_normal(u3R, nov) ); #ifdef VERBOSE_TAKE - u3l_log("south: %p is already %p\r\n", veb_u, u3a_to_ptr(nov)); + u3l_log("south: %p is already %p", veb_u, u3a_to_ptr(nov)); #endif _me_gain_use(nov); // bypass branches in u3k() diff --git a/pkg/urbit/noun/events.c b/pkg/urbit/noun/events.c index 224eb86d9..92b94edec 100644 --- a/pkg/urbit/noun/events.c +++ b/pkg/urbit/noun/events.c @@ -63,7 +63,7 @@ u3e_check(c3_c* cap_c) } sum_w += mug_w; } - u3l_log("%s: sum %x (%x, %x)\r\n", cap_c, sum_w, nor_w, sou_w); + u3l_log("%s: sum %x (%x, %x)", cap_c, sum_w, nor_w, sou_w); } } @@ -136,7 +136,7 @@ u3e_fault(void* adr_v, c3_i ser_i) #if 0 if ( pag_w == 131041 ) { - u3l_log("dirty page %d (at %p); unprotecting %p to %p\r\n", + u3l_log("dirty page %d (at %p); unprotecting %p to %p", pag_w, adr_v, (u3_Loom + (pag_w << u3a_page)), @@ -341,7 +341,7 @@ _ce_patch_verify(u3_ce_patch* pat_u) } #if 0 else { - u3l_log("verify: patch %d/%d, %x\r\n", pag_w, i_w, mug_w); + u3l_log("verify: patch %d/%d, %x", pag_w, i_w, mug_w); } #endif } @@ -458,7 +458,7 @@ _ce_patch_save_page(u3_ce_patch* pat_u, (1 << u3a_page)); #if 0 - u3l_log("protect a: page %d\r\n", pag_w); + u3l_log("protect a: page %d", pag_w); #endif _ce_patch_write_page(pat_u, pgc_w, mem_w); @@ -484,7 +484,7 @@ _ce_patch_junk_page(u3_ce_patch* pat_u, c3_w blk_w = (pag_w >> 5); c3_w bit_w = (pag_w & 31); - // u3l_log("protect b: page %d\r\n", pag_w); + // u3l_log("protect b: page %d", pag_w); if ( -1 == mprotect(u3_Loom + (pag_w << u3a_page), (1 << (u3a_page + 2)), PROT_READ) ) @@ -688,7 +688,7 @@ _ce_patch_apply(u3_ce_patch* pat_u) } } #if 0 - u3l_log("apply: %d, %x\n", pag_w, u3r_mug_words(mem_w, (1 << u3a_page))); + u3l_log("apply: %d, %x", pag_w, u3r_mug_words(mem_w, (1 << u3a_page))); #endif } } @@ -713,7 +713,7 @@ _ce_image_blit(u3e_image* img_u, c3_w off_w = (ptr_w - u3_Loom); c3_w pag_w = (off_w >> u3a_page); - u3l_log("blit: page %d, mug %x\r\n", pag_w, + u3l_log("blit: page %d, mug %x", pag_w, u3r_mug_words(ptr_w, (1 << u3a_page))); } #endif @@ -868,17 +868,17 @@ u3e_live(c3_o nuu_o, c3_c* dir_c) -(1 << u3a_page)); if ( 0 != mprotect((void *)u3_Loom, u3a_bytes, PROT_READ) ) { - u3l_log("loom: live mprotect: %s\r\n", strerror(errno)); + u3l_log("loom: live mprotect: %s", strerror(errno)); c3_assert(0); } - u3l_log("boot: protected loom\r\n"); + u3l_log("boot: protected loom"); } /* If the images were empty, we are logically booting. */ if ( (0 == u3P.nor_u.pgs_w) && (0 == u3P.sou_u.pgs_w) ) { - u3l_log("live: logical boot\r\n"); + u3l_log("live: logical boot"); nuu_o = c3y; } else { diff --git a/pkg/urbit/noun/jets.c b/pkg/urbit/noun/jets.c index 357e94bd8..c60badf5d 100644 --- a/pkg/urbit/noun/jets.c +++ b/pkg/urbit/noun/jets.c @@ -75,7 +75,7 @@ _cj_hash(c3_c* has_c) { c3_w i_w, len_w = strlen(has_c); if ( 64 != len_w ) { - u3l_log("bash not 64 characters: %s\r\n", has_c); + u3l_log("bash not 64 characters: %s", has_c); c3_assert(0); } c3_assert( 64 == len_w ); @@ -236,18 +236,18 @@ _cj_axis(u3_noun fol) (0 != p_fol) || (!_(u3a_is_cat(q_fol))) ) { - u3l_log("axis: bad a\r\n"); + u3l_log("axis: bad a"); return 0; } return q_fol; } else { if ( 9 != p_fol ) - { u3l_log("axis: bad b\r\n"); return 0; } + { u3l_log("axis: bad b"); return 0; } if ( !_(u3a_is_cat(q_fol)) ) - { u3l_log("axis: bad c\r\n"); return 0; } + { u3l_log("axis: bad c"); return 0; } if ( !_(u3du(r_fol)) || (0 != u3h(r_fol)) || (1 != u3t(r_fol)) ) - { u3l_log("axis: bad d\r\n"); return 0; } + { u3l_log("axis: bad d"); return 0; } return q_fol; } @@ -278,7 +278,7 @@ _cj_warm_hump(c3_l jax_l, u3_noun huc) ((1 << 31) & (axe_l = (c3_w)axe_d)) || (axe_l < 2) ) { - u3l_log("jets: activate: bad fcs %s\r\n", jet_u->fcs_c); + u3l_log("jets: activate: bad fcs %s", jet_u->fcs_c); } } else { @@ -286,7 +286,7 @@ _cj_warm_hump(c3_l jax_l, u3_noun huc) u3_noun fol = u3kdb_get(u3k(huc), nam); if ( u3_none == fol ) { - u3l_log("jets: activate: bad fcs %s\r\n", jet_u->fcs_c); + u3l_log("jets: activate: bad fcs %s", jet_u->fcs_c); } else { axe_l = _cj_axis(fol); @@ -781,7 +781,7 @@ _cj_hot_mean(c3_l par_l, u3_noun nam) while ( (cop_u = &dev_u[i_l])->cos_c ) { if ( _(u3r_sing_c(cop_u->cos_c, nam)) ) { #if 0 - u3l_log("hot: bound jet %d/%s/%s/\r\n", + u3l_log("hot: bound jet %d/%s/%s/", cop_u->jax_l, cop_u->cos_c, par_u ? par_u->cos_c : "~"); @@ -893,7 +893,7 @@ _cj_kick_z(u3_noun cor, u3j_core* cop_u, u3j_harm* ham_u, u3_atom axe) ham_u->liv = c3y; if ( c3n == u3r_sing(ame, pro) ) { - u3l_log("test: %s %s: mismatch: good %x, bad %x\r\n", + u3l_log("test: %s %s: mismatch: good %x, bad %x", cop_u->cos_c, (!strcmp(".2", ham_u->fcs_c)) ? "$" : ham_u->fcs_c, u3r_mug(ame), @@ -905,7 +905,7 @@ _cj_kick_z(u3_noun cor, u3j_core* cop_u, u3j_harm* ham_u, u3_atom axe) else { #if 0 - u3l_log("test: %s %s\r\n", + u3l_log("test: %s %s", cop_u->cos_c, (!strcmp(".2", ham_u->fcs_c)) ? "$" : ham_u->fcs_c); #endif @@ -928,13 +928,13 @@ _cj_hook_in(u3_noun cor, u3_noun roc, tem, got, pat, nam, huc; if ( c3n == u3du(cor) ) { - u3l_log("_cj_hook_in failure: c3n == u3du(cor)\r\n"); + u3l_log("_cj_hook_in failure: c3n == u3du(cor)"); return u3m_bail(c3__fail); } loc = _cj_spot(cor, NULL); if ( u3_none == loc ) { - u3l_log("_cj_hook_in failure: u3_none == loc\r\n"); + u3l_log("_cj_hook_in failure: u3_none == loc"); return u3m_bail(c3__fail); } @@ -999,7 +999,7 @@ _cj_hook_in(u3_noun cor, else { u3_noun sat = u3t(pat); if ( c3y == u3h(sat) ) { - u3l_log("_cj_hook_in failure: c3y == u3h(sat)\r\n"); + u3l_log("_cj_hook_in failure: c3y == u3h(sat)"); return u3m_bail(c3__fail); } else { @@ -1687,7 +1687,7 @@ u3j_gate_prep(u3j_site* sit_u, u3_noun cor) pay = u3qc_cap(pax), pam = u3qc_mas(pax); if ( 3 != pay || 2 == pam || (3 != pam && 3 != u3qc_cap(pam)) ) { - u3l_log("u3j_gate_prep(): parent axis includes sample\r\n"); + u3l_log("u3j_gate_prep(): parent axis includes sample"); u3m_p("axis", pax); u3_weak act = _cj_find_warm(loc); c3_assert( u3_none != act ); @@ -1758,12 +1758,12 @@ _cj_minx(u3_noun cey, u3_noun cor) par = u3r_at(axe, cor); if ( u3_none == par || c3n == u3du(par) ) { - u3l_log("fund: %s is bogus\r\n", u3r_string(nam)); + u3l_log("fund: %s is bogus", u3r_string(nam)); return u3_none; } pel = _cj_spot(par, NULL); if ( u3_none == pel ) { - u3l_log("fund: in %s, parent %x not found at %d\r\n", + u3l_log("fund: in %s, parent %x not found at %d", u3r_string(nam), u3r_mug(u3h(par)), axe); @@ -1822,7 +1822,7 @@ _cj_mine(u3_noun cey, u3_noun cor, u3_noun bas) jax_l = _cj_hot_mean(par_l, nam); #if 0 u3m_p("new jet", bal); - u3l_log(" bat %x, jax %d\r\n", u3r_mug(bat), jax_l); + u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l); #endif if ( !(u3C.wag_w & u3o_hashless) ) { @@ -1840,7 +1840,7 @@ _cj_mine(u3_noun cey, u3_noun cor, u3_noun bas) for ( i_w = 32; i_w > 0; ) { u3l_log("%02x", dig_y[--i_w]); } - u3l_log("\r\n"); + u3l_log(""); } } @@ -1870,7 +1870,7 @@ _cj_mine(u3_noun cey, u3_noun cor, u3_noun bas) if ( c3n == hav_o ) { u3m_p("unregistered battery", bal); - u3l_log("hash: %x\r\n", bas); + u3l_log("hash: %x", bas); } u3z(bas); } @@ -2093,7 +2093,7 @@ _cj_ream(u3_noun all) act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat)); #if 0 u3m_p("old jet", bal); - u3l_log(" bat %x, jax %d\r\n", u3r_mug(bat), jax_l); + u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l); #endif u3h_put(u3R->jed.war_p, loc, act); } @@ -2132,7 +2132,7 @@ _cj_ream(u3_noun all) act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat)); #if 0 u3m_p("old jet", bal); - u3l_log(" bat %x, jax %d\r\n", u3r_mug(bat), jax_l); + u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l); #endif u3h_put(u3R->jed.war_p, loc, act); } diff --git a/pkg/urbit/noun/log.c b/pkg/urbit/noun/log.c index 866a7430e..f1a7c1b38 100644 --- a/pkg/urbit/noun/log.c +++ b/pkg/urbit/noun/log.c @@ -22,6 +22,8 @@ u3l_log(const char* format, ...) // this process did not set a logging function, fallback to stderr // vfprintf(stderr, format, myargs); + fprintf(stderr, "\r\n"); + fflush(stderr); } va_end(myargs); diff --git a/pkg/urbit/noun/manage.c b/pkg/urbit/noun/manage.c index f6e692824..14f83c852 100644 --- a/pkg/urbit/noun/manage.c +++ b/pkg/urbit/noun/manage.c @@ -318,7 +318,7 @@ _cm_signal_recover(c3_l sig_l, u3_noun arg) while ( rod_u->kid_p ) { #if 0 - u3l_log("collecting %d frames\r\n", + u3l_log("collecting %d frames", u3kb_lent((u3to(u3_road, rod_u->kid_p)->bug.tax)); #endif tax = u3kb_weld(_cm_stack_recover(u3to(u3_road, rod_u->kid_p)), tax); @@ -372,7 +372,7 @@ _cm_signal_deep(c3_w mil_w) itm_u.it_value.tv_usec = 1000 * (mil_w % 1000); if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) { - u3l_log("loom: set timer failed %s\r\n", strerror(errno)); + u3l_log("loom: set timer failed %s", strerror(errno)); } else { rsignal_install_handler(SIGVTALRM, _cm_signal_handle_alrm); @@ -405,7 +405,7 @@ _cm_signal_done() timerclear(&itm_u.it_value); if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) { - u3l_log("loom: clear timer failed %s\r\n", strerror(errno)); + u3l_log("loom: clear timer failed %s", strerror(errno)); } } @@ -437,7 +437,7 @@ u3m_file(c3_c* pas_c) c3_y* pad_y; if ( (fid_i < 0) || (fstat(fid_i, &buf_b) < 0) ) { - u3l_log("%s: %s\r\n", pas_c, strerror(errno)); + u3l_log("%s: %s", pas_c, strerror(errno)); return u3m_bail(c3__fail); } fln_w = buf_b.st_size; @@ -632,7 +632,7 @@ u3m_dump(void) fre_u = fre_u->nex_u; } } - u3l_log("dump: hat_w %x, fre_w %x, allocated %x\n", + u3l_log("dump: hat_w %x, fre_w %x, allocated %x", hat_w, fre_w, (hat_w - fre_w)); if ( 0 != (hat_w - fre_w) ) { @@ -644,14 +644,14 @@ u3m_dump(void) if ( 0 != box_u->use_w ) { #ifdef U3_MEMORY_DEBUG - // u3l_log("live %d words, code %x\n", box_u->siz_w, box_u->cod_w); + // u3l_log("live %d words, code %x", box_u->siz_w, box_u->cod_w); #endif mem_w += box_u->siz_w; } box_w += box_u->siz_w; } - u3l_log("second count: %x\n", mem_w); + u3l_log("second count: %x", mem_w); } } #endif @@ -1548,7 +1548,7 @@ u3m_p(const c3_c* cap_c, u3_noun som) { c3_c* pre_c = u3m_pretty(som); - u3l_log("%s: %s\r\n", cap_c, pre_c); + u3l_log("%s: %s", cap_c, pre_c); c3_free(pre_c); } @@ -1609,7 +1609,7 @@ _cm_limits(void) rlm.rlim_cur = c3_min(rlm.rlim_max, (65536 << 10)); if ( 0 != setrlimit(RLIMIT_STACK, &rlm) ) { - u3l_log("boot: stack size: %s\r\n", strerror(errno)); + u3l_log("boot: stack size: %s", strerror(errno)); exit(1); } } @@ -1628,7 +1628,7 @@ _cm_limits(void) // no exit, not a critical limit // if ( 0 != setrlimit(RLIMIT_NOFILE, &rlm) ) { - u3l_log("boot: open file limit: %s\r\n", strerror(errno)); + u3l_log("boot: open file limit: %s", strerror(errno)); } } @@ -1642,7 +1642,7 @@ _cm_limits(void) // no exit, not a critical limit // if ( 0 != setrlimit(RLIMIT_CORE, &rlm) ) { - u3l_log("boot: core limit: %s\r\n", strerror(errno)); + u3l_log("boot: core limit: %s", strerror(errno)); } } # endif @@ -1665,7 +1665,7 @@ _cm_signals(void) // access and stack overflow exceptions. It calls u3e_fault directly. # else if ( 0 != sigsegv_install_handler(u3e_fault) ) { - u3l_log("boot: sigsegv install failed\n"); + u3l_log("boot: sigsegv install failed"); exit(1); } # endif @@ -1681,7 +1681,7 @@ _cm_signals(void) sigaddset(&set, SIGPROF); if ( 0 != pthread_sigmask(SIG_BLOCK, &set, NULL) ) { - u3l_log("boot: thread mask SIGPROF: %s\r\n", strerror(errno)); + u3l_log("boot: thread mask SIGPROF: %s", strerror(errno)); exit(1); } } @@ -1737,17 +1737,17 @@ u3m_init(void) MAP_ANON | MAP_PRIVATE, -1, 0); - u3l_log("boot: mapping %dMB failed\r\n", (len_w / (1024 * 1024))); + u3l_log("boot: mapping %dMB failed", (len_w / (1024 * 1024))); u3l_log("see urbit.org/using/install/#about-swap-space" " for adding swap space\r\n"); - if ( -1 != (c3_ps)dyn_v ) { - u3l_log("if porting to a new platform, try U3_OS_LoomBase %p\r\n", + if ( -1 != (c3_ps)map_v ) { + u3l_log("if porting to a new platform, try U3_OS_LoomBase %p", dyn_v); } exit(1); } - u3l_log("loom: mapped %dMB\r\n", len_w >> 20); + u3l_log("loom: mapped %dMB", len_w >> 20); } } @@ -1788,7 +1788,7 @@ u3m_boot(c3_c* dir_c) */ { c3_w len_w = u3j_boot(nuu_o); - u3l_log("boot: installed %d jets\r\n", len_w); + u3l_log("boot: installed %d jets", len_w); } /* Reactivate jets on old kernel. diff --git a/pkg/urbit/noun/nock.c b/pkg/urbit/noun/nock.c index bc41e5ddd..22e08e1db 100644 --- a/pkg/urbit/noun/nock.c +++ b/pkg/urbit/noun/nock.c @@ -44,7 +44,7 @@ _n_hint(u3_noun zep, low_i = 1; if ( 0 == (u3R->pro.nox_d % 65536ULL) ) { if ( c3__spot == zep ) { - u3l_log("spot %d/%d : %d/%d\r\n", + u3l_log("spot %d/%d : %d/%d", u3h(u3h(u3t(hod))), u3t(u3h(u3t(hod))), u3h(u3t(u3t(hod))), diff --git a/pkg/urbit/noun/trace.c b/pkg/urbit/noun/trace.c index 1ee8168c7..5d93db13d 100644 --- a/pkg/urbit/noun/trace.c +++ b/pkg/urbit/noun/trace.c @@ -167,7 +167,7 @@ _t_samp_process(u3_road* rod_u) pef = t_pef; } - // u3l_log("sample: stack length %d\r\n", u3kb_lent(u3k(pal))); + // u3l_log("sample: stack length %d", u3kb_lent(u3k(pal))); return pal; } } @@ -540,7 +540,7 @@ u3t_boot(void) sigemptyset(&set); sigaddset(&set, SIGPROF); if ( 0 != pthread_sigmask(SIG_UNBLOCK, &set, NULL) ) { - u3l_log("trace: thread mask SIGPROF: %s\r\n", strerror(errno)); + u3l_log("trace: thread mask SIGPROF: %s", strerror(errno)); } } @@ -569,7 +569,7 @@ u3t_boff(void) sigemptyset(&set); sigaddset(&set, SIGPROF); if ( 0 != pthread_sigmask(SIG_BLOCK, &set, NULL) ) { - u3l_log("trace: thread mask SIGPROF: %s\r\n", strerror(errno)); + u3l_log("trace: thread mask SIGPROF: %s", strerror(errno)); } } diff --git a/pkg/urbit/noun/vortex.c b/pkg/urbit/noun/vortex.c index acf7eea9d..820216b2f 100644 --- a/pkg/urbit/noun/vortex.c +++ b/pkg/urbit/noun/vortex.c @@ -60,9 +60,9 @@ _cv_lite(u3_noun pil) eve = tal; } - u3l_log("lite: arvo formula %x\r\n", u3r_mug(pil)); + u3l_log("lite: arvo formula %x", u3r_mug(pil)); pro = u3v_life(u3k(eve)); - u3l_log("lite: core %x\r\n", u3r_mug(pro)); + u3l_log("lite: core %x", u3r_mug(pro)); u3z(pil); return pro; @@ -89,7 +89,7 @@ u3v_boot_lite(u3_noun pil) u3z(pro); } - u3l_log("lite: final state %x\r\n", u3r_mug(u3A->roc)); + u3l_log("lite: final state %x", u3r_mug(u3A->roc)); return c3y; } @@ -209,7 +209,7 @@ _cv_mole(u3_noun fot, (0 != q_uco) || (c3n == u3r_sing(fot, r_uco)) ) { - u3l_log("strange mole %s\n", u3r_string(san))); + u3l_log("strange mole %s", u3r_string(san))); u3z(fot); u3z(uco); return c3n; } diff --git a/pkg/urbit/vere/auto.c b/pkg/urbit/vere/auto.c index 5a56d22bc..c02d7aabe 100644 --- a/pkg/urbit/vere/auto.c +++ b/pkg/urbit/vere/auto.c @@ -91,7 +91,7 @@ u3_auto_bail_slog(u3_ovum* egg_u, u3_noun lud) c3_w len_w = 1; while ( u3_nul != dul ) { - u3l_log("%s: bail %u\r\n", car_c, len_w++); + u3l_log("%s: bail %u", car_c, len_w++); u3_pier_punt_goof(car_c, u3k(u3h(dul))); dul = u3t(dul); @@ -240,7 +240,7 @@ _auto_kick_lost(u3_noun pax, u3_noun fav) c3_c* tag_c = u3r_string(u3h(fav)); c3_c* pax_c = u3r_string(tox); - u3l_log("kick: lost %%%s on %s\n", tag_c, pax_c); + u3l_log("kick: lost %%%s on %s", tag_c, pax_c); c3_free(pax_c); c3_free(tag_c); @@ -360,12 +360,12 @@ u3_auto_info(u3_auto* car_u) { u3_auto* nex_u; - u3l_log(" drivers:\n"); + u3l_log(" drivers:"); while ( car_u ) { nex_u = car_u->nex_u; - u3l_log(" %.*s: live=%s, queue=%u\n", + u3l_log(" %.*s: live=%s, queue=%u", u3r_met(3, car_u->nam_m), (c3_c*)&car_u->nam_m, ( c3y == car_u->liv_o ) ? "&" : "|", diff --git a/pkg/urbit/vere/dawn.c b/pkg/urbit/vere/dawn.c index 9c4cd9959..f11b3c608 100644 --- a/pkg/urbit/vere/dawn.c +++ b/pkg/urbit/vere/dawn.c @@ -71,7 +71,7 @@ _dawn_post_json(c3_c* url_c, uv_buf_t lod_u) uv_buf_t buf_u = uv_buf_init(c3_malloc(1), 0); if ( !(curl = curl_easy_init()) ) { - u3l_log("failed to initialize libcurl\n"); + u3l_log("failed to initialize libcurl"); exit(1); } @@ -95,12 +95,12 @@ _dawn_post_json(c3_c* url_c, uv_buf_t lod_u) // XX retry? if ( CURLE_OK != result ) { - u3l_log("failed to fetch %s: %s\n", + u3l_log("failed to fetch %s: %s", url_c, curl_easy_strerror(result)); exit(1); } if ( 300 <= cod_l ) { - u3l_log("error fetching %s: HTTP %ld\n", url_c, cod_l); + u3l_log("error fetching %s: HTTP %ld", url_c, cod_l); exit(1); } @@ -122,7 +122,7 @@ _dawn_get_jam(c3_c* url_c) uv_buf_t buf_u = uv_buf_init(c3_malloc(1), 0); if ( !(curl = curl_easy_init()) ) { - u3l_log("failed to initialize libcurl\n"); + u3l_log("failed to initialize libcurl"); exit(1); } @@ -138,12 +138,12 @@ _dawn_get_jam(c3_c* url_c) // XX retry? if ( CURLE_OK != result ) { - u3l_log("failed to fetch %s: %s\n", + u3l_log("failed to fetch %s: %s", url_c, curl_easy_strerror(result)); exit(1); } if ( 300 <= cod_l ) { - u3l_log("error fetching %s: HTTP %ld\n", url_c, cod_l); + u3l_log("error fetching %s: HTTP %ld", url_c, cod_l); exit(1); } @@ -207,7 +207,7 @@ _dawn_fail(u3_noun who, u3_noun rac, u3_noun sas) } } - u3l_log("boot: invalid keys for %s '%s'\r\n", rac_c, how_c); + u3l_log("boot: invalid keys for %s '%s'", rac_c, how_c); // XX deconstruct sas, print helpful error messages while ( u3_nul != sas ) { @@ -226,7 +226,7 @@ static u3_noun _dawn_need_unit(u3_noun nit, c3_c* msg_c) { if ( u3_nul == nit ) { - u3l_log("%s\r\n", msg_c); + u3l_log("%s", msg_c); exit(1); } else { @@ -245,7 +245,7 @@ _dawn_purl(u3_noun rac) if ( 0 == u3_Host.ops_u.eth_c ) { if ( c3__czar == rac ) { - u3l_log("boot: galaxy requires ethereum gateway via -e\r\n"); + u3l_log("boot: galaxy requires ethereum gateway via -e"); exit(1); } @@ -260,7 +260,7 @@ _dawn_purl(u3_noun rac) if ( u3_nul == rul ) { if ( c3__czar == rac ) { - u3l_log("boot: galaxy requires ethereum gateway via -e\r\n"); + u3l_log("boot: galaxy requires ethereum gateway via -e"); exit(1); } @@ -292,11 +292,11 @@ _dawn_turf(c3_c* dns_c) u3_noun rul = u3dc("rush", u3k(dns), u3k(par)); if ( (u3_nul == rul) || (c3n == u3h(u3t(rul))) ) { - u3l_log("boot: invalid domain specified with -H %s\r\n", dns_c); + u3l_log("boot: invalid domain specified with -H %s", dns_c); exit(1); } else { - u3l_log("boot: overriding network domains with %s\r\n", dns_c); + u3l_log("boot: overriding network domains with %s", dns_c); u3_noun dom = u3t(u3t(rul)); tuf = u3nc(u3k(dom), u3_nul); } @@ -345,7 +345,7 @@ u3_dawn_vent(u3_noun ship, u3_noun feed) // pin block number // { - u3l_log("boot: retrieving latest block\r\n"); + u3l_log("boot: retrieving latest block"); u3_noun oct = u3v_wish("bloq:give:dawn"); u3_noun kob = _dawn_eth_rpc(url_c, u3k(oct)); @@ -369,7 +369,7 @@ u3_dawn_vent(u3_noun ship, u3_noun feed) pot = u3v_wish("*point:azimuth"); } else { - u3l_log("boot: retrieving %s's public keys\r\n", + u3l_log("boot: retrieving %s's public keys", u3_Host.ops_u.who_c); { @@ -388,7 +388,7 @@ u3_dawn_vent(u3_noun ship, u3_noun feed) u3_noun liv = u3_nul; // u3_noun liv = _dawn_get_json(parent, /some/url) - u3l_log("boot: verifying keys\r\n"); + u3l_log("boot: verifying keys"); // (each seed (lest error=@tas)) // @@ -400,7 +400,7 @@ u3_dawn_vent(u3_noun ship, u3_noun feed) return u3_none; } - u3l_log("boot: getting sponsor\r\n"); + u3l_log("boot: getting sponsor"); pos = _dawn_sponsor(u3k(ship), u3k(rank), u3k(pot)); u3z(pot); u3z(liv); } @@ -409,7 +409,7 @@ u3_dawn_vent(u3_noun ship, u3_noun feed) // (map ship [=life =pass]): galaxy table // { - u3l_log("boot: retrieving galaxy table\r\n"); + u3l_log("boot: retrieving galaxy table"); u3_noun oct = u3do("czar:give:dawn", u3k(bok)); u3_noun raz = _dawn_eth_rpc(url_c, u3k(oct)); @@ -425,7 +425,7 @@ u3_dawn_vent(u3_noun ship, u3_noun feed) tuf = _dawn_turf(u3_Host.ops_u.dns_c); } else { - u3l_log("boot: retrieving network domains\r\n"); + u3l_log("boot: retrieving network domains"); u3_noun oct = u3do("turf:give:dawn", u3k(bok)); u3_noun fut = _dawn_eth_rpc(url_c, u3k(oct)); @@ -443,7 +443,7 @@ u3_dawn_vent(u3_noun ship, u3_noun feed) { u3_noun who = u3dc("scot", 'p', u3k(pos)); c3_c* who_c = u3r_string(who); - u3l_log("boot: retrieving keys for sponsor %s\r\n", who_c); + u3l_log("boot: retrieving keys for sponsor %s", who_c); u3z(who); c3_free(who_c); } @@ -495,8 +495,8 @@ _dawn_come(u3_noun stars) c3_rand(eny_w); eny = u3i_words(16, eny_w); - u3l_log("boot: mining a comet. May take up to an hour.\r\n"); - u3l_log("If you want to boot faster, get an Urbit identity.\r\n"); + u3l_log("boot: mining a comet. May take up to an hour."); + u3l_log("If you want to boot faster, get an Urbit identity."); seed = u3dc("come:dawn", u3k(stars), u3k(eny)); u3z(eny); @@ -506,7 +506,7 @@ _dawn_come(u3_noun stars) u3_noun who = u3dc("scot", 'p', u3k(u3h(seed))); c3_c* who_c = u3r_string(who); - u3l_log("boot: found comet %s\r\n", who_c); + u3l_log("boot: found comet %s", who_c); // enable to print and save comet private key for future reuse // @@ -515,7 +515,7 @@ _dawn_come(u3_noun stars) u3_noun key = u3dc("scot", c3__uw, u3qe_jam(seed)); c3_c* key_c = u3r_string(key); - u3l_log("boot: comet private key\n %s\n", key_c); + u3l_log("boot: comet private key\n %s", key_c); { c3_c pat_c[64]; diff --git a/pkg/urbit/vere/disk.c b/pkg/urbit/vere/disk.c index 6f8240daa..5d308ae4d 100644 --- a/pkg/urbit/vere/disk.c +++ b/pkg/urbit/vere/disk.c @@ -242,7 +242,7 @@ u3_disk_plan(u3_disk* log_u, u3_fact* tac_u) { c3_assert( (1ULL + log_u->sen_d) == tac_u->eve_d ); log_u->sen_d++; - + if ( !log_u->put_u.ent_u ) { c3_assert( !log_u->put_u.ext_u ); log_u->put_u.ent_u = log_u->put_u.ext_u = tac_u; @@ -649,7 +649,7 @@ u3_disk_exit(u3_disk* log_u) void u3_disk_info(u3_disk* log_u) { - u3l_log(" disk: live=%s, event=%" PRIu64 "\n", + u3l_log(" disk: live=%s, event=%" PRIu64, ( c3y == log_u->liv_o ) ? "&" : "|", log_u->dun_d); @@ -657,7 +657,7 @@ u3_disk_info(u3_disk* log_u) u3_read* red_u = log_u->red_u; while ( red_u ) { - u3l_log(" read: %" PRIu64 "-%" PRIu64 "\n", + u3l_log(" read: %" PRIu64 "-%" PRIu64, red_u->eve_d, (red_u->eve_d + red_u->len_d) - 1); } @@ -665,12 +665,12 @@ u3_disk_info(u3_disk* log_u) if ( log_u->put_u.ext_u ) { if ( log_u->put_u.ext_u != log_u->put_u.ent_u ) { - u3l_log(" save: %" PRIu64 "-%" PRIu64 "\n", + u3l_log(" save: %" PRIu64 "-%" PRIu64, log_u->put_u.ext_u->eve_d, log_u->put_u.ent_u->eve_d); } else { - u3l_log(" save: %" PRIu64 "\n", log_u->put_u.ext_u->eve_d); + u3l_log(" save: %" PRIu64, log_u->put_u.ext_u->eve_d); } } } diff --git a/pkg/urbit/vere/foil.c b/pkg/urbit/vere/foil.c index 1d844f5d4..186c8fdec 100644 --- a/pkg/urbit/vere/foil.c +++ b/pkg/urbit/vere/foil.c @@ -36,10 +36,10 @@ static void _foil_fail(const c3_c* why_c, c3_i err_i) { if ( err_i ) { - u3l_log("%s: error: %s\r\n", why_c, uv_strerror(err_i)); + u3l_log("%s: error: %s", why_c, uv_strerror(err_i)); c3_assert(0); } else { - u3l_log("%s: file error\r\n", why_c); + u3l_log("%s: file error", why_c); } exit(1); } diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 1773e02ed..79c5beb9e 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -340,7 +340,7 @@ _ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) u3_ames* sam_u = pac_u->sam_u; if ( sas_i && (c3y == sam_u->fig_u.net_o) ) { - u3l_log("ames: send fail: %s\n", uv_strerror(sas_i)); + u3l_log("ames: send fail: %s", uv_strerror(sas_i)); sam_u->fig_u.net_o = c3n; } else { @@ -379,7 +379,7 @@ _ames_send(u3_pact* pac_u) if ( sas_i ) { if ( c3y == sam_u->fig_u.net_o ) { - u3l_log("ames: send fail: %s\n", uv_strerror(sas_i)); + u3l_log("ames: send fail: %s", uv_strerror(sas_i)); sam_u->fig_u.net_o = c3n; } @@ -516,7 +516,7 @@ _ames_czar_gone(u3_pact* pac_u, time_t now) u3_ames* sam_u = pac_u->sam_u; if ( c3y == sam_u->imp_o[pac_u->imp_y] ) { - u3l_log("ames: czar at %s: not found (b)\n", pac_u->dns_c); + u3l_log("ames: czar at %s: not found (b)", pac_u->dns_c); sam_u->imp_o[pac_u->imp_y] = c3n; } @@ -546,7 +546,7 @@ _ames_czar_here(u3_pact* pac_u, time_t now, struct sockaddr_in* add_u) u3_noun nam = u3dc("scot", c3__if, u3i_word(pip_w)); c3_c* nam_c = u3r_string(nam); - u3l_log("ames: czar %s: ip %s\n", pac_u->dns_c, nam_c); + u3l_log("ames: czar %s: ip %s", pac_u->dns_c, nam_c); c3_free(nam_c); u3z(nam); @@ -611,7 +611,7 @@ _ames_czar(u3_pact* pac_u) if ( !sam_u->dns_c ) { u3_noun nam = u3dc("scot", 'p', pac_u->imp_y); c3_c* nam_c = u3r_string(nam); - u3l_log("ames: no galaxy domain for %s, no-op\r\n", nam_c); + u3l_log("ames: no galaxy domain for %s, no-op", nam_c); c3_free(nam_c); u3z(nam); @@ -656,7 +656,7 @@ _ames_czar(u3_pact* pac_u) } if ( 255 <= sas_i ) { - u3l_log("ames: czar: galaxy domain %s truncated\n", sam_u->dns_c); + u3l_log("ames: czar: galaxy domain %s truncated", sam_u->dns_c); _ames_pact_free(pac_u); return; } @@ -669,7 +669,7 @@ _ames_czar(u3_pact* pac_u) _ames_czar_cb, pac_u->dns_c, 0, 0)) ) { - u3l_log("ames: %s\n", uv_strerror(sas_i)); + u3l_log("ames: %s", uv_strerror(sas_i)); _ames_czar_gone(pac_u, now); return; } @@ -684,7 +684,7 @@ static void _ames_ef_send(u3_ames* sam_u, u3_noun lan, u3_noun pac) { if ( c3n == sam_u->car_u.liv_o ) { - u3l_log("ames: not yet live, dropping outbound\r\n"); + u3l_log("ames: not yet live, dropping outbound"); u3z(lan); u3z(pac); return; } @@ -754,7 +754,7 @@ _ames_cap_queue(u3_ames* sam_u) sam_u->sat_u.dop_d++; if ( u3C.wag_w & u3o_verbose ) { - u3l_log("ames: packet dropped (%" PRIu64 " total)\n", sam_u->sat_u.dop_d); + u3l_log("ames: packet dropped (%" PRIu64 " total)", sam_u->sat_u.dop_d); } } @@ -764,7 +764,7 @@ _ames_cap_queue(u3_ames* sam_u) if ( (sam_u->sat_u.dop_d && (0 == (sam_u->sat_u.dop_d % 1000))) && !(u3C.wag_w & u3o_verbose) ) { - u3l_log("ames: packet dropped (%" PRIu64 " total)\n", sam_u->sat_u.dop_d); + u3l_log("ames: packet dropped (%" PRIu64 " total)", sam_u->sat_u.dop_d); } } @@ -782,7 +782,7 @@ _ames_punt_goof(u3_noun lud) c3_w len_w = 1; while ( u3_nul != dul ) { - u3l_log("ames: bail %u\r\n", len_w++); + u3l_log("ames: bail %u", len_w++); u3_pier_punt_goof("ames", u3k(u3h(dul))); dul = u3t(dul); } @@ -803,13 +803,13 @@ _ames_hear_bail(u3_ovum* egg_u, u3_noun lud) || (0 == (sam_u->sat_u.fal_d % 1000)) ) { _ames_punt_goof(lud); - u3l_log("ames: packet failed (%" PRIu64 " total)\n\n", sam_u->sat_u.fal_d); + u3l_log("ames: packet failed (%" PRIu64 " total)", sam_u->sat_u.fal_d); } else { u3z(lud); if ( 0 == (sam_u->sat_u.fal_d % 1000) ) { - u3l_log("ames: packet failed (%" PRIu64 " total)\n\n", sam_u->sat_u.fal_d); + u3l_log("ames: packet failed (%" PRIu64 " total)", sam_u->sat_u.fal_d); } } @@ -843,7 +843,7 @@ _ames_forward(u3_panc* pac_u, u3_noun las) sam_u->sat_u.fow_d++; if ( 0 == (sam_u->sat_u.fow_d % 1000000) ) { - u3l_log("ames: forwarded %" PRIu64 " total\n", sam_u->sat_u.fow_d); + u3l_log("ames: forwarded %" PRIu64 " total", sam_u->sat_u.fow_d); } if ( u3C.wag_w & u3o_verbose ) { @@ -853,7 +853,7 @@ _ames_forward(u3_panc* pac_u, u3_noun las) c3_c* rec_c = u3r_string(rec); c3_y* pip_y = (c3_y*)&pac_u->ore_u.pip_w; - u3l_log("ames: forwarding for %s to %s from %d.%d.%d.%d:%d\n", + u3l_log("ames: forwarding for %s to %s from %d.%d.%d.%d:%d", sen_c, rec_c, pip_y[0], pip_y[1], pip_y[2], pip_y[3], pac_u->ore_u.por_s); @@ -872,7 +872,7 @@ _ames_forward(u3_panc* pac_u, u3_noun las) // validate lane and skip self if galaxy // if ( c3n == u3r_cell(lan, &tag, &dat) ) { - u3l_log("ames: bogus lane\n"); + u3l_log("ames: bogus lane"); u3m_p("lan", lan); } else { @@ -887,7 +887,7 @@ _ames_forward(u3_panc* pac_u, u3_noun las) { sen_o = c3n; if ( u3C.wag_w & u3o_verbose ) { - u3l_log("ames: forward skipping self\n"); + u3l_log("ames: forward skipping self"); } } } @@ -920,7 +920,7 @@ _ames_lane_scry_cb(void* vod_p, u3_noun nun) // if ( u3_none == las ) { if ( 5 < ++sam_u->sat_u.saw_d ) { - u3l_log("ames: giving up scry\n"); + u3l_log("ames: giving up scry"); sam_u->fig_u.see_o = c3n; } _ames_put_packet(sam_u, _ames_serialize_packet(pac_u, c3n), pac_u->ore_u); @@ -984,7 +984,7 @@ _ames_try_forward(u3_ames* sam_u, if ( (u3_none == lac) && (1000 < sam_u->sat_u.foq_d) ) { sam_u->sat_u.fod_d++; if ( 0 == (sam_u->sat_u.fod_d % 10000) ) { - u3l_log("ames: dropped %" PRIu64 " forwards total\n", + u3l_log("ames: dropped %" PRIu64 " forwards total", sam_u->sat_u.fod_d); } @@ -1088,7 +1088,7 @@ _ames_hear(u3_ames* sam_u, { sam_u->sat_u.hed_d++; if ( 0 == (sam_u->sat_u.hed_d % 100000) ) { - u3l_log("ames: %" PRIu64 " dropped, failed to read header\n", + u3l_log("ames: %" PRIu64 " dropped, failed to read header", sam_u->sat_u.hed_d); } @@ -1105,7 +1105,7 @@ _ames_hear(u3_ames* sam_u, { sam_u->sat_u.vet_d++; if ( 0 == (sam_u->sat_u.vet_d % 100000) ) { - u3l_log("ames: %" PRIu64 " dropped for version mismatch\n", + u3l_log("ames: %" PRIu64 " dropped for version mismatch", sam_u->sat_u.vet_d); } @@ -1122,7 +1122,7 @@ _ames_hear(u3_ames* sam_u, if ( (c3n == _ames_sift_body(&hed_u, &bod_u, bod_w, bod_y)) ) { sam_u->sat_u.bod_d++; if ( 0 == (sam_u->sat_u.bod_d % 100) ) { - u3l_log("ames: %" PRIu64 " dropped, failed to read body\n", + u3l_log("ames: %" PRIu64 " dropped, failed to read body", sam_u->sat_u.bod_d); } @@ -1135,7 +1135,7 @@ _ames_hear(u3_ames* sam_u, if ( bod_u.mug_l != hed_u.mug_l ) { sam_u->sat_u.mut_d++; if ( 0 == (sam_u->sat_u.mut_d % 100000) ) { - u3l_log("ames: %" PRIu64 " dropped for invalid mug\n", + u3l_log("ames: %" PRIu64 " dropped for invalid mug", sam_u->sat_u.mut_d); } @@ -1183,7 +1183,7 @@ _ames_recv_cb(uv_udp_t* wax_u, { if ( 0 > nrd_i ) { if ( u3C.wag_w & u3o_verbose ) { - u3l_log("ames: recv: fail: %s\n", uv_strerror(nrd_i)); + u3l_log("ames: recv: fail: %s", uv_strerror(nrd_i)); } c3_free(buf_u->base); } @@ -1192,7 +1192,7 @@ _ames_recv_cb(uv_udp_t* wax_u, } else if ( flg_i & UV_UDP_PARTIAL ) { if ( u3C.wag_w & u3o_verbose ) { - u3l_log("ames: recv: fail: message truncated\n"); + u3l_log("ames: recv: fail: message truncated"); } c3_free(buf_u->base); } @@ -1228,8 +1228,8 @@ _ames_io_start(u3_ames* sam_u) por_s = zar_s; } else if ( por_s != zar_s ) { - u3l_log("ames: czar: overriding port %d with -p %d\n", zar_s, por_s); - u3l_log("ames: czar: WARNING: %d required for discoverability\n", zar_s); + u3l_log("ames: czar: overriding port %d with -p %d", zar_s, por_s); + u3l_log("ames: czar: WARNING: %d required for discoverability", zar_s); } } @@ -1248,12 +1248,12 @@ _ames_io_start(u3_ames* sam_u) if ( (ret_i = uv_udp_bind(&sam_u->wax_u, (const struct sockaddr*)&add_u, 0)) != 0 ) { - u3l_log("ames: bind: %s\n", uv_strerror(ret_i)); + u3l_log("ames: bind: %s", uv_strerror(ret_i)); if ( (c3__czar == rac) && (UV_EADDRINUSE == ret_i) ) { - u3l_log(" ...perhaps you've got two copies of vere running?\n"); + u3l_log(" ...perhaps you've got two copies of vere running?"); } // XX revise @@ -1268,10 +1268,10 @@ _ames_io_start(u3_ames* sam_u) } if ( c3y == u3_Host.ops_u.net ) { - u3l_log("ames: live on %d\n", sam_u->pir_u->por_s); + u3l_log("ames: live on %d", sam_u->pir_u->por_s); } else { - u3l_log("ames: live on %d (localhost only)\n", sam_u->pir_u->por_s); + u3l_log("ames: live on %d (localhost only)", sam_u->pir_u->por_s); } uv_udp_recv_start(&sam_u->wax_u, _ames_alloc, _ames_recv_cb); @@ -1302,7 +1302,7 @@ _ames_ef_turf(u3_ames* sam_u, u3_noun tuf) u3z(tuf); } else if ( (c3n == sam_u->pir_u->fak_o) && (0 == sam_u->dns_c) ) { - u3l_log("ames: turf: no domains\n"); + u3l_log("ames: turf: no domains"); } // XX is this ever necessary? @@ -1446,7 +1446,7 @@ _ames_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) ret_o = c3n; } else { - u3l_log("kick: strange send\r\n"); + u3l_log("kick: strange send"); ret_o = _ames_kick_newt(sam_u, u3k(tag), u3k(dat)); } } break; @@ -1497,21 +1497,21 @@ _ames_io_info(u3_auto* car_u) # define FLAG(a) ( (c3y == a) ? "&" : "|" ) - u3l_log(" config:\n"); - u3l_log(" filtering: %s\n", FLAG(sam_u->fig_u.fit_o)); - u3l_log(" can send: %s\n", FLAG(sam_u->fig_u.net_o)); - u3l_log(" can scry: %s\n", FLAG(sam_u->fig_u.see_o)); - u3l_log(" counters:\n"); - u3l_log(" dropped: %" PRIu64 "\n", sam_u->sat_u.dop_d); - u3l_log(" forwards dropped: %" PRIu64 "\n", sam_u->sat_u.fod_d); - u3l_log(" forwards pending: %" PRIu64 "\n", sam_u->sat_u.foq_d); - u3l_log(" forwarded: %" PRIu64 "\n", sam_u->sat_u.fow_d); - u3l_log(" filtered (hed): %" PRIu64 "\n", sam_u->sat_u.hed_d); - u3l_log(" filtered (ver): %" PRIu64 "\n", sam_u->sat_u.vet_d); - u3l_log(" filtered (mug): %" PRIu64 "\n", sam_u->sat_u.mut_d); - u3l_log(" filtered (bod): %" PRIu64 "\n", sam_u->sat_u.bod_d); - u3l_log(" crashed: %" PRIu64 "\n", sam_u->sat_u.fal_d); - u3l_log(" cached lanes: %u\n", u3h_wyt(sam_u->lax_p)); + u3l_log(" config:"); + u3l_log(" filtering: %s", FLAG(sam_u->fig_u.fit_o)); + u3l_log(" can send: %s", FLAG(sam_u->fig_u.net_o)); + u3l_log(" can scry: %s", FLAG(sam_u->fig_u.see_o)); + u3l_log(" counters:"); + u3l_log(" dropped: %" PRIu64, sam_u->sat_u.dop_d); + u3l_log(" forwards dropped: %" PRIu64, sam_u->sat_u.fod_d); + u3l_log(" forwards pending: %" PRIu64, sam_u->sat_u.foq_d); + u3l_log(" forwarded: %" PRIu64, sam_u->sat_u.fow_d); + u3l_log(" filtered (hed): %" PRIu64, sam_u->sat_u.hed_d); + u3l_log(" filtered (ver): %" PRIu64, sam_u->sat_u.vet_d); + u3l_log(" filtered (mug): %" PRIu64, sam_u->sat_u.mut_d); + u3l_log(" filtered (bod): %" PRIu64, sam_u->sat_u.bod_d); + u3l_log(" crashed: %" PRIu64, sam_u->sat_u.fal_d); + u3l_log(" cached lanes: %u", u3h_wyt(sam_u->lax_p)); } /* u3_ames_io_init(): initialize ames I/O. diff --git a/pkg/urbit/vere/io/behn.c b/pkg/urbit/vere/io/behn.c index c9394564e..a4f6a5618 100644 --- a/pkg/urbit/vere/io/behn.c +++ b/pkg/urbit/vere/io/behn.c @@ -48,7 +48,7 @@ _behn_wake_bail(u3_ovum* egg_u, u3_noun lud) u3_auto_bail_slog(egg_u, lud); u3_ovum_free(egg_u); - u3l_log("behn: timer failed; queue blocked\n"); + u3l_log("behn: timer failed; queue blocked"); // XX review, add flag to continue? // @@ -149,7 +149,7 @@ _behn_born_bail(u3_ovum* egg_u, u3_noun lud) u3_auto_bail_slog(egg_u, lud); u3_ovum_free(egg_u); - u3l_log("behn: initialization failed\n"); + u3l_log("behn: initialization failed"); // XX review, add flag to continue? // diff --git a/pkg/urbit/vere/io/cttp.c b/pkg/urbit/vere/io/cttp.c index 1f19c3e41..76c1dd396 100644 --- a/pkg/urbit/vere/io/cttp.c +++ b/pkg/urbit/vere/io/cttp.c @@ -558,7 +558,7 @@ _cttp_creq_new(u3_cttp* ctp_u, c3_l num_l, u3_noun hes) if ( c3n == u3r_du(unit_pul) ) { c3_c* url_c = u3r_string(url); - u3l_log("cttp: unable to parse url:\n %s\n", url_c); + u3l_log("cttp: unable to parse url:\n %s", url_c); c3_free(url_c); u3z(hes); return 0; @@ -735,7 +735,7 @@ _cttp_creq_fail(u3_creq* ceq_u, const c3_c* err_c) // XX anything other than a 504? c3_w cod_w = 504; - u3l_log("http: fail (%d, %d): %s\r\n", ceq_u->num_l, cod_w, err_c); + u3l_log("http: fail (%d, %d): %s", ceq_u->num_l, cod_w, err_c); // XX include err_c as response body? _cttp_http_client_receive(ceq_u, cod_w, u3_nul, u3_nul); @@ -1003,7 +1003,7 @@ _cttp_ef_http_client(u3_cttp* ctp_u, u3_noun tag, u3_noun dat) if ( (c3n == u3r_cell(dat, &num, &req)) || (c3n == u3r_safe_word(num, &num_l)) ) { - u3l_log("cttp: strange request\n"); + u3l_log("cttp: strange request"); ret_o = c3n; } else if ( (ceq_u = _cttp_creq_new(ctp_u, num_l, u3k(req))) ) { @@ -1018,7 +1018,7 @@ _cttp_ef_http_client(u3_cttp* ctp_u, u3_noun tag, u3_noun dat) c3_l num_l; if ( c3n == u3r_safe_word(dat, &num_l) ) { - u3l_log("cttp: strange cancel-request\n"); + u3l_log("cttp: strange cancel-request"); ret_o = c3n; } else if ( (ceq_u =_cttp_creq_find(ctp_u, num_l)) ) { @@ -1032,7 +1032,7 @@ _cttp_ef_http_client(u3_cttp* ctp_u, u3_noun tag, u3_noun dat) } } else { - u3l_log("cttp: strange effect (unknown type)\n"); + u3l_log("cttp: strange effect (unknown type)"); ret_o = c3n; } diff --git a/pkg/urbit/vere/io/fore.c b/pkg/urbit/vere/io/fore.c index 81476d92a..4582cab46 100644 --- a/pkg/urbit/vere/io/fore.c +++ b/pkg/urbit/vere/io/fore.c @@ -10,7 +10,7 @@ static void _fore_inject_bail(u3_ovum* egg_u, u3_noun lud) { u3_auto_bail_slog(egg_u, lud); - u3l_log("pier: injected event failed\n"); + u3l_log("pier: injected event failed"); u3_ovum_free(egg_u); } @@ -21,7 +21,7 @@ static void _fore_import_bail(u3_ovum* egg_u, u3_noun lud) { u3_auto_bail_slog(egg_u, lud); - u3l_log("pier: import failed\n"); + u3l_log("pier: import failed"); u3_ovum_free(egg_u); } @@ -37,20 +37,20 @@ _fore_inject(u3_auto* car_u, c3_c* pax_c) u3_noun riw, cad, tar, wir; if ( c3n == u3r_cell(ovo, &riw, &cad) ) { - u3l_log("pier: invalid ovum in -I\n"); + u3l_log("pier: invalid ovum in -I"); } else if ( (c3n == u3a_is_cell(cad)) || (c3n == u3a_is_atom(u3h(cad))) ) { - u3l_log("pier: invalid card in -I ovum\n"); + u3l_log("pier: invalid card in -I ovum"); } else if ( c3n == u3r_cell(riw, &tar, &wir) ) { - u3l_log("pier: invalid wire in -I ovum\n"); + u3l_log("pier: invalid wire in -I ovum"); } else if ( (c3n == u3a_is_atom(tar)) || (1 < u3r_met(3, tar)) ) { - u3l_log("pier: invalid target in -I wire\n"); + u3l_log("pier: invalid target in -I wire"); } else { { @@ -58,7 +58,7 @@ _fore_inject(u3_auto* car_u, c3_c* pax_c) u3_noun ser = u3do("spat", u3k(riw)); c3_c* wir_c = u3r_string(ser); - u3l_log("pier: injecting %%%s event on %s\n", tag_c, wir_c); + u3l_log("pier: injecting %%%s event on %s", tag_c, wir_c); c3_free(tag_c); c3_free(wir_c); diff --git a/pkg/urbit/vere/io/hind.c b/pkg/urbit/vere/io/hind.c index b0d207e83..d15534806 100644 --- a/pkg/urbit/vere/io/hind.c +++ b/pkg/urbit/vere/io/hind.c @@ -30,7 +30,7 @@ _hind_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) case c3__exit: { ret_o = c3y; - u3l_log("<<>>\n"); + u3l_log("<<>>"); u3_pier_exit(car_u->pir_u); } break; @@ -44,7 +44,7 @@ _hind_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) case c3__vega: { ret_o = c3y; - u3l_log("<<>>\n"); + u3l_log("<<>>"); } break; // NB: startup explicitly handled in pier.c diff --git a/pkg/urbit/vere/io/http.c b/pkg/urbit/vere/io/http.c index f0d2f0ea2..d53bff384 100644 --- a/pkg/urbit/vere/io/http.c +++ b/pkg/urbit/vere/io/http.c @@ -33,7 +33,7 @@ typedef struct _u3_h2o_serv { void* gen_u; // response generator struct _u3_hcon* hon_u; // connection backlink struct _u3_hreq* nex_u; // next in connection's list - struct _u3_hreq* pre_u; // next in connection's list + struct _u3_hreq* pre_u; // prev in connection's list } u3_hreq; /* u3_hcon: incoming http connection. @@ -48,7 +48,7 @@ typedef struct _u3_h2o_serv { struct _u3_http* htp_u; // server backlink struct _u3_hreq* req_u; // request list struct _u3_hcon* nex_u; // next in server's list - struct _u3_hcon* pre_u; // next in server's list + struct _u3_hcon* pre_u; // prev in server's list } u3_hcon; /* u3_http: http server. @@ -639,10 +639,10 @@ _http_start_respond(u3_hreq* req_u, u3_noun data, u3_noun complete) { - // u3l_log("start\n"); + // u3l_log("start"); if ( u3_rsat_plan != req_u->sat_e ) { - //u3l_log("duplicate response\n"); + //u3l_log("duplicate response"); return; } @@ -715,14 +715,14 @@ _http_continue_respond(u3_hreq* req_u, u3_noun data, u3_noun complete) { - // u3l_log("continue\n"); + // u3l_log("continue"); // XX add sequence numbers for %continue effects? // Arvo does not (currently) guarantee effect idempotence!! // response has not yet been started if ( u3_rsat_ripe != req_u->sat_e ) { - // u3l_log("duplicate response\n"); + // u3l_log("duplicate response"); return; } @@ -855,7 +855,7 @@ _http_seq_continue(void* vod_p, u3_noun nun) _http_start_respond(req_u, 403, u3_nul, u3_nul, c3y); } else if ( u3_none == aut ) { - u3l_log("http: authentication scry failed\n"); + u3l_log("http: authentication scry failed"); _http_start_respond(req_u, 500, u3_nul, u3_nul, c3y); } else { @@ -917,7 +917,7 @@ _http_rec_accept(h2o_handler_t* han_u, h2o_req_t* rec_u) if ( u3_none == req ) { if ( (u3C.wag_w & u3o_verbose) ) { - u3l_log("strange %.*s request\n", (int)rec_u->method.len, + u3l_log("strange %.*s request", (int)rec_u->method.len, rec_u->method.base); } c3_c* msg_c = "bad request"; @@ -1007,7 +1007,7 @@ _http_conn_free(uv_handle_t* han_t) noh_u = noh_u->nex_u; } - u3l_log("http conn free %d of %u server %d\n", hon_u->coq_l, len_w, htp_u->sev_l); + u3l_log("http conn free %d of %u server %d", hon_u->coq_l, len_w, htp_u->sev_l); } #endif @@ -1024,13 +1024,13 @@ _http_conn_free(uv_handle_t* han_t) noh_u = noh_u->nex_u; } - u3l_log("http conn free %u remaining\n", len_w); + u3l_log("http conn free %u remaining", len_w); } #endif if ( (0 == htp_u->hon_u) && (0 != h2o_u->ctx_u.shutdown_requested) ) { #if 0 - u3l_log("http conn free %d free server %d\n", hon_u->coq_l, htp_u->sev_l); + u3l_log("http conn free %d free server %d", hon_u->coq_l, htp_u->sev_l); #endif _http_serv_free(htp_u); } @@ -1054,7 +1054,7 @@ _http_conn_new(u3_http* htp_u) _http_conn_link(htp_u, hon_u); #if 0 - u3l_log("http conn neww %d server %d\n", hon_u->coq_l, htp_u->sev_l); + u3l_log("http conn neww %d server %d", hon_u->coq_l, htp_u->sev_l); #endif return hon_u; @@ -1104,7 +1104,7 @@ _http_serv_unlink(u3_http* htp_u) { // XX link elsewhere initially, relink on start? #if 0 - u3l_log("http serv unlink %d\n", htp_u->sev_l); + u3l_log("http serv unlink %d", htp_u->sev_l); #endif u3_http* pre_u = htp_u->htd_u->htp_u; @@ -1213,7 +1213,7 @@ http_serv_free_cb(uv_timer_t* tim_u) u3_http* htp_u = tim_u->data; #if 0 - u3l_log("http serv free cb %d\n", htp_u->sev_l); + u3l_log("http serv free cb %d", htp_u->sev_l); #endif _http_serv_really_free(htp_u); @@ -1227,7 +1227,7 @@ static void _http_serv_free(u3_http* htp_u) { #if 0 - u3l_log("http serv free %d\n", htp_u->sev_l); + u3l_log("http serv free %d", htp_u->sev_l); #endif c3_assert( 0 == htp_u->hon_u ); @@ -1297,7 +1297,7 @@ _http_serv_close(u3_http* htp_u) h2o_context_request_shutdown(&h2o_u->ctx_u); #if 0 - u3l_log("http serv close %d %p\n", htp_u->sev_l, &htp_u->wax_u); + u3l_log("http serv close %d %p", htp_u->sev_l, &htp_u->wax_u); #endif uv_close((uv_handle_t*)&htp_u->wax_u, _http_serv_close_cb); @@ -1338,7 +1338,7 @@ _http_serv_accept(u3_http* htp_u) if ( 0 != (sas_i = uv_accept((uv_stream_t*)&htp_u->wax_u, (uv_stream_t*)&hon_u->wax_u)) ) { if ( (u3C.wag_w & u3o_verbose) ) { - u3l_log("http: accept: %s\n", uv_strerror(sas_i)); + u3l_log("http: accept: %s", uv_strerror(sas_i)); } uv_close((uv_handle_t*)&hon_u->wax_u, _http_conn_free); @@ -1367,7 +1367,7 @@ _http_serv_listen_cb(uv_stream_t* str_u, c3_i sas_i) u3_http* htp_u = (u3_http*)str_u; if ( 0 != sas_i ) { - u3l_log("http: listen_cb: %s\n", uv_strerror(sas_i)); + u3l_log("http: listen_cb: %s", uv_strerror(sas_i)); } else { _http_serv_accept(htp_u); @@ -1493,13 +1493,13 @@ _http_serv_start(u3_http* htp_u) continue; } - u3l_log("http: listen: %s\n", uv_strerror(sas_i)); + u3l_log("http: listen: %s", uv_strerror(sas_i)); _http_serv_free(htp_u); return; } - u3l_log("http: %s live on %s://localhost:%d\n", + u3l_log("http: %s live on %s://localhost:%d", (c3y == htp_u->lop) ? "loopback" : "web interface", (c3y == htp_u->sec) ? "https" : "http", htp_u->por_s); @@ -1557,9 +1557,10 @@ _http_init_tls(uv_buf_t key_u, uv_buf_t cer_u) BIO_free(bio_u); if( 0 == sas_i ) { - u3l_log("http: load private key failed:\n"); - ERR_print_errors_fp(u3_term_io_hija()); - u3_term_io_loja(1); + u3l_log("http: load private key failed:"); + FILE* fil_u = u3_term_io_hija(); + ERR_print_errors_fp(fil_u); + u3_term_io_loja(1, fil_u); SSL_CTX_free(tls_u); @@ -1575,9 +1576,10 @@ _http_init_tls(uv_buf_t key_u, uv_buf_t cer_u) X509_free(xer_u); if( 0 == sas_i ) { - u3l_log("http: load certificate failed:\n"); - ERR_print_errors_fp(u3_term_io_hija()); - u3_term_io_loja(1); + u3l_log("http: load certificate failed:"); + FILE* fil_u = u3_term_io_hija(); + ERR_print_errors_fp(fil_u); + u3_term_io_loja(1,fil_u); BIO_free(bio_u); SSL_CTX_free(tls_u); @@ -1656,19 +1658,19 @@ _http_search_req(u3_httd* htd_u, if ( !(htp_u = _http_serv_find(htd_u, sev_l)) ) { if ( bug_w ) { - u3l_log("http: server not found: %x\r\n", sev_l); + u3l_log("http: server not found: %x", sev_l); } return 0; } else if ( !(hon_u = _http_conn_find(htp_u, coq_l)) ) { if ( bug_w ) { - u3l_log("http: connection not found: %x/%d\r\n", sev_l, coq_l); + u3l_log("http: connection not found: %x/%d", sev_l, coq_l); } return 0; } else if ( !(req_u = _http_req_find(hon_u, seq_l)) ) { if ( bug_w ) { - u3l_log("http: request not found: %x/%d/%d\r\n", + u3l_log("http: request not found: %x/%d/%d", sev_l, coq_l, seq_l); } return 0; @@ -1760,7 +1762,7 @@ _http_serv_restart(u3_httd* htd_u) _http_serv_start_all(htd_u); } else { - u3l_log("http: restarting servers to apply configuration\n"); + u3l_log("http: restarting servers to apply configuration"); while ( 0 != htp_u ) { if ( c3y == htp_u->liv ) { @@ -1812,7 +1814,7 @@ u3_http_ef_form(u3_httd* htd_u, u3_noun fig) !( c3y == pro || c3n == pro ) || !( c3y == log || c3n == log ) || !( c3y == red || c3n == red ) ) { - u3l_log("http: form: invalid card\n"); + u3l_log("http: form: invalid card"); u3z(fig); return; } @@ -1907,14 +1909,14 @@ _http_ef_http_server(u3_httd* htd_u, _http_continue_respond(req_u, u3k(data), u3k(complete)); } else if (c3y == u3r_sing_c("cancel", u3h(response))) { - u3l_log("http: %%cancel not handled yet\n"); + u3l_log("http: %%cancel not handled yet"); } else { - u3l_log("http: strange response\n"); + u3l_log("http: strange response"); } } else { - u3l_log("http: strange response\n"); + u3l_log("http: strange response"); } } @@ -2028,7 +2030,7 @@ _reck_mole(u3_noun fot, if ( (c3n == u3r_cell(uco, &p_uco, &q_uco)) || (u3_nul != p_uco) ) { - u3l_log("strange mole %s\n", u3r_string(san)); + u3l_log("strange mole %s", u3r_string(san)); u3z(fot); u3z(uco); return c3n; } @@ -2166,7 +2168,7 @@ _http_io_info(u3_auto* car_u) sec_y++; seq_u = seq_u->nex_u; } - u3l_log(" open slogstreams: %d\n", sec_y); + u3l_log(" open slogstreams: %d", sec_y); } /* u3_http_io_init(): initialize http I/O. diff --git a/pkg/urbit/vere/io/term.c b/pkg/urbit/vere/io/term.c index fcccf748a..e2b6376ca 100644 --- a/pkg/urbit/vere/io/term.c +++ b/pkg/urbit/vere/io/term.c @@ -16,6 +16,7 @@ static u3_utty* _term_main(); static void _term_read_cb(uv_stream_t* tcp_u, ssize_t siz_i, const uv_buf_t* buf_u); +static void _term_it_send_stub(u3_utty* uty_u, u3_noun tub); /* u3_write_fd(): retry interrupts, continue partial writes, assert errors. */ @@ -85,39 +86,6 @@ _term_alloc(uv_handle_t* had_u, *buf = uv_buf_init(ptr_v, 123); } -// XX unused, but %hook is in %zuse. -// implement or remove -// -#if 0 -/* _term_close_cb(): free terminal. -*/ -static void -_term_close_cb(uv_handle_t* han_t) -{ - u3_utty* tty_u = (void*) han_t; - if ( u3_Host.uty_u == tty_u ) { - u3_Host.uty_u = tty_u->nex_u; - } - else { - u3_utty* uty_u; - for (uty_u = u3_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; - } - } - } - - { - u3_noun tid = u3dc("scot", c3__ud, tty_u->tid_l); - u3_noun pax = u3nq(u3_blip, c3__term, tid, u3_nul); - u3_pier_plan(u3k(pax), u3nc(c3__hook, u3_nul)); - u3z(pax); - } - c3_free(tty_u); -} -#endif - /* u3_term_log_init(): initialize terminal for logging */ void @@ -149,41 +117,33 @@ u3_term_log_init(void) // and simply use constant sequences. // { - uty_u->ufo_u.out.clear_u = TERM_LIT_BUF("\033[H\033[2J"); - uty_u->ufo_u.out.el_u = TERM_LIT_BUF("\033[K"); - // uty_u->ufo_u.out.el1_u = TERM_LIT_BUF("\033[1K"); - uty_u->ufo_u.out.ed_u = TERM_LIT_BUF("\033[J"); - uty_u->ufo_u.out.bel_u = TERM_LIT_BUF("\x7"); - uty_u->ufo_u.out.cub1_u = TERM_LIT_BUF("\x8"); - uty_u->ufo_u.out.cuf1_u = TERM_LIT_BUF("\033[C"); - uty_u->ufo_u.out.cuu1_u = TERM_LIT_BUF("\033[A"); - uty_u->ufo_u.out.cud1_u = TERM_LIT_BUF("\xa"); - // uty_u->ufo_u.out.cub_u = TERM_LIT_BUF("\033[%p1%dD"); - // uty_u->ufo_u.out.cuf_u = TERM_LIT_BUF("\033[%p1%dC"); - } + uty_u->ufo_u.mon_u = TERM_LIT_BUF("\033[?9h"); + uty_u->ufo_u.mof_u = TERM_LIT_BUF("\033[?9l"); - // configure input escape sequences - // - // NB: terminfo reports the wrong sequence for arrow keys on xterms. - // disabled, currently unused - // { - // uty_u->ufo_u.inn.kcuu1_u = TERM_LIT_BUF("\033[A"); // terminfo reports "\033OA" - // uty_u->ufo_u.inn.kcud1_u = TERM_LIT_BUF("\033[B"); // terminfo reports "\033OB" - // uty_u->ufo_u.inn.kcuf1_u = TERM_LIT_BUF("\033[C"); // terminfo reports "\033OC" - // uty_u->ufo_u.inn.kcub1_u = TERM_LIT_BUF("\033[D"); // terminfo reports "\033OD" - // } + uty_u->ufo_u.reg_u = TERM_LIT_BUF("\033[r"); + + uty_u->ufo_u.suc_u = TERM_LIT_BUF("\033[s"); + uty_u->ufo_u.ruc_u = TERM_LIT_BUF("\033[u"); + uty_u->ufo_u.cub_u = TERM_LIT_BUF("\x8"); + + uty_u->ufo_u.clr_u = TERM_LIT_BUF("\033[H\033[2J"); + uty_u->ufo_u.cel_u = TERM_LIT_BUF("\033[K"); + + uty_u->ufo_u.bel_u = TERM_LIT_BUF("\x7"); + } // Initialize mirror and accumulator state. // { - uty_u->tat_u.mir.lin_y = 0; - uty_u->tat_u.mir.byt_w = 0; - uty_u->tat_u.mir.wor_w = 0; - uty_u->tat_u.mir.sap_w = 0; + uty_u->tat_u.mir.lin = u3_nul; + uty_u->tat_u.mir.rus_w = 0; uty_u->tat_u.mir.cus_w = 0; uty_u->tat_u.esc.ape = c3n; uty_u->tat_u.esc.bra = c3n; + uty_u->tat_u.esc.mou = c3n; + uty_u->tat_u.esc.ton_y = 0; + uty_u->tat_u.esc.col_y = 0; uty_u->tat_u.fut.len_w = 0; uty_u->tat_u.fut.wid_w = 0; @@ -193,7 +153,7 @@ u3_term_log_init(void) // { uty_u->tat_u.siz.col_l = 80; - uty_u->tat_u.siz.row_l = 24; + uty_u->tat_u.siz.row_l = 0; } // initialize spinner state @@ -273,7 +233,7 @@ _term_it_write_cb(uv_write_t* wri_u, c3_i sas_i) // write failure is logged, but otherwise ignored. // if ( 0 != sas_i ) { - u3l_log("term: write: %s\n", uv_strerror(sas_i)); + u3l_log("term: write: %s", uv_strerror(sas_i)); } c3_free(wri_u->data); @@ -325,7 +285,7 @@ _term_it_write(u3_utty* uty_u, // synchronous write failure is logged, but otherwise ignored // if ( ret_i < 0 ) { - u3l_log("term: write: %s\n", uv_strerror(ret_i)); + u3l_log("term: write: %s", uv_strerror(ret_i)); } c3_free(ptr_v); @@ -370,32 +330,62 @@ _term_it_send(u3_utty* uty_u, } } -/* _term_it_send_cord(): write a cord. +/* _term_it_send_csi(): send csi escape sequence */ static void -_term_it_send_cord(u3_utty* uty_u, - u3_atom txt) +_term_it_send_csi(u3_utty *uty_u, c3_c cmd_c, c3_w num_w, ...) { - c3_w len_w = u3r_met(3, txt); - c3_y* hun_y = c3_malloc(len_w); - u3r_bytes(0, len_w, hun_y, txt); + va_list ap; + va_start(ap, num_w); - _term_it_send(uty_u, len_w, hun_y); + // allocate for escape sequence (2), command char (1), + // argument digits (5 per arg) and separators (1 per arg, minus 1). + // freed via _term_it_write. + // + c3_c* pas_c = c3_malloc( 2 + num_w * 6 ); + c3_y len_y = 0; - u3z(txt); + pas_c[len_y++] = '\033'; + pas_c[len_y++] = '['; + + while ( num_w-- ) { + c3_w par_w = va_arg(ap, c3_w); + len_y += sprintf(pas_c+len_y, "%d", par_w); + + if ( num_w ) { + pas_c[len_y++] = ';'; + } + } + + pas_c[len_y++] = cmd_c; + + _term_it_send(uty_u, len_y, (c3_y*)pas_c); + + va_end(ap); } -/* _term_it_show_clear(): clear to the beginning of the current line. +/* _term_it_free_line(): wipe line stored by _term_it_save_stub */ static void -_term_it_show_clear(u3_utty* uty_u) +_term_it_free_line(u3_utty* uty_u) { - if ( uty_u->tat_u.siz.col_l ) { - _term_it_dump(uty_u, TERM_LIT("\r")); - _term_it_dump_buf(uty_u, &uty_u->ufo_u.out.el_u); + u3z(uty_u->tat_u.mir.lin); + uty_u->tat_u.mir.lin = u3_nul; +} - uty_u->tat_u.mir.wor_w = 0; - uty_u->tat_u.mir.cus_w = 0; +/* _term_it_clear_line(): clear line of cursor +*/ +static void +_term_it_clear_line(u3_utty* uty_u) +{ + _term_it_dump(uty_u, TERM_LIT("\r")); + _term_it_dump_buf(uty_u, &uty_u->ufo_u.cel_u); + _term_it_dump_buf(uty_u, &uty_u->ufo_u.ruc_u); + + // if we're clearing the bottom line, clear our mirror of it too + // + if ( 0 == uty_u->tat_u.mir.rus_w ) { + _term_it_free_line(uty_u); } } @@ -404,87 +394,35 @@ _term_it_show_clear(u3_utty* uty_u) static void _term_it_show_blank(u3_utty* uty_u) { - _term_it_dump_buf(uty_u, &uty_u->ufo_u.out.clear_u); + _term_it_dump_buf(uty_u, &uty_u->ufo_u.clr_u); + _term_it_dump_buf(uty_u, &uty_u->ufo_u.ruc_u); } -/* _term_it_show_cursor(): set current line, transferring pointer. -*/ +/* _term_it_move_cursor(): move cursor to row & column + * + * row 0 is at the bottom, col 0 is to the left. + * if the given position exceeds the known window size, + * it is clipped to stay within the window. + */ static void -_term_it_show_cursor(u3_utty* uty_u, c3_w cur_w) +_term_it_move_cursor(u3_utty* uty_u, c3_w row_w, c3_w col_w) { - c3_w cus_w = uty_u->tat_u.mir.cus_w; - c3_w dif_w; + c3_l row_l = uty_u->tat_u.siz.row_l; + c3_l col_l = uty_u->tat_u.siz.col_l; + if ( row_w >= row_l ) { row_w = row_l - 1; } + if ( col_w >= col_l ) { col_w = col_l - 1; } - //NOTE assumes all styled text precedes the cursor. drum enforces this. - // - cur_w += uty_u->tat_u.mir.sap_w; + _term_it_send_csi(uty_u, 'H', 2, row_l - row_w, col_w + 1); + _term_it_dump_buf(uty_u, &uty_u->ufo_u.suc_u); - if ( cur_w < cus_w ) { - dif_w = cus_w - cur_w; - - while ( dif_w-- ) { - _term_it_dump_buf(uty_u, &uty_u->ufo_u.out.cub1_u); - } - } - else if ( cur_w > cus_w ) { - dif_w = cur_w - cus_w; - - while ( dif_w-- ) { - _term_it_dump_buf(uty_u, &uty_u->ufo_u.out.cuf1_u); - } - } - - uty_u->tat_u.mir.cus_w = cur_w; + uty_u->tat_u.mir.rus_w = row_w; + uty_u->tat_u.mir.cus_w = col_w; } -/* _term_it_show_line(): render current line. +/* _term_it_show_line(): print at cursor */ static void -_term_it_show_line(u3_utty* uty_u, c3_w wor_w, c3_w sap_w) -{ - u3_utat* tat_u = &uty_u->tat_u; - - // we have to reallocate the current line on write, - // or we have a data race if a) the write is async, - // and b) a new output line arrives before the write completes. - // - { - c3_w len_w = tat_u->mir.byt_w; - c3_y* hun_y = c3_malloc(len_w); - memcpy(hun_y, tat_u->mir.lin_y, len_w); - - _term_it_send(uty_u, len_w, hun_y); - } - - // XX refactor to avoid updating state - // - tat_u->mir.cus_w += wor_w; - tat_u->mir.wor_w = wor_w; - tat_u->mir.sap_w = sap_w; -} - -/* _term_it_refresh_line(): refresh current line. -*/ -static void -_term_it_refresh_line(u3_utty* uty_u) -{ - u3_utat* tat_u = &uty_u->tat_u; - c3_w wor_w = tat_u->mir.wor_w; - c3_w sap_w = tat_u->mir.sap_w; - c3_w cus_w = tat_u->mir.cus_w; - - _term_it_show_clear(uty_u); - _term_it_show_line(uty_u, wor_w, sap_w); - _term_it_show_cursor(uty_u, cus_w); -} - -/* _term_it_set_line(): set current line. -*/ -static void -_term_it_set_line(u3_utty* uty_u, - c3_w* lin_w, - c3_w wor_w, - c3_w sap_w) +_term_it_show_line(u3_utty* uty_u, c3_w* lin_w, c3_w wor_w) { u3_utat* tat_u = &uty_u->tat_u; c3_y* hun_y = (c3_y*)lin_w; @@ -522,28 +460,66 @@ _term_it_set_line(u3_utty* uty_u, } } - c3_free(tat_u->mir.lin_y); - tat_u->mir.lin_y = hun_y; - tat_u->mir.byt_w = byt_w; - tat_u->mir.wor_w = wor_w; - tat_u->mir.sap_w = sap_w; - - _term_it_show_line(uty_u, wor_w, sap_w); + //NOTE lin_w freed through hun_y by _send + _term_it_send(uty_u, byt_w, hun_y); + _term_it_dump_buf(uty_u, &uty_u->ufo_u.ruc_u); } -/* _term_it_show_more(): new current line. +/* _term_it_restore_line(): re-render original line at bottom of screen */ static void -_term_it_show_more(u3_utty* uty_u) +_term_it_restore_line(u3_utty* uty_u) +{ + u3_utat* tat_u = &uty_u->tat_u; + + _term_it_send_csi(uty_u, 'H', 2, tat_u->siz.row_l, 0); + _term_it_dump_buf(uty_u, &uty_u->ufo_u.cel_u); + _term_it_send_stub(uty_u, u3k(tat_u->mir.lin)); + //NOTE send_stub restores cursor position +} + +/* _term_it_save_stub(): store line if relevant to internal logic + */ +static void +_term_it_save_stub(u3_utty* uty_u, u3_noun tub) +{ + u3_utat* tat_u = &uty_u->tat_u; + u3_noun lin = tat_u->mir.lin; + + // keep track of changes to bottom-most line, to aid spinner drawing logic. + // -t mode doesn't need this logic, because it doesn't render the spinner. + // + if ( (0 == tat_u->mir.rus_w) && (c3n == u3_Host.ops_u.tem)) { + lin = u3dq("wail:klr:format", lin, tat_u->mir.cus_w, u3k(tub), ' '); + lin = u3do("pact:klr:format", lin); + } + + tat_u->mir.lin = lin; + u3z(tub); +} + +/* _term_it_show_nel(): render newline, moving cursor down +*/ +static void +_term_it_show_nel(u3_utty* uty_u) { if ( c3y == u3_Host.ops_u.tem ) { _term_it_dump(uty_u, TERM_LIT("\n")); } else { _term_it_dump(uty_u, TERM_LIT("\r\n")); + _term_it_dump_buf(uty_u, &uty_u->ufo_u.suc_u); } uty_u->tat_u.mir.cus_w = 0; + if ( uty_u->tat_u.mir.rus_w > 0 ) { + uty_u->tat_u.mir.rus_w--; + } + else { + // newline at bottom of screen, so bottom line is now empty + // + _term_it_free_line(uty_u); + } } /* _term_it_path(): path for console file. @@ -667,32 +643,37 @@ _term_io_suck_char(u3_utty* uty_u, c3_y cay_y) { u3_utat* tat_u = &uty_u->tat_u; + // escape sequences + // if ( c3y == tat_u->esc.ape ) { if ( c3y == tat_u->esc.bra ) { switch ( cay_y ) { default: { - _term_it_dump_buf(uty_u, &uty_u->ufo_u.out.bel_u); + _term_it_dump_buf(uty_u, &uty_u->ufo_u.bel_u); break; } case 'A': _term_io_belt(uty_u, u3nc(c3__aro, 'u')); break; case 'B': _term_io_belt(uty_u, u3nc(c3__aro, 'd')); break; case 'C': _term_io_belt(uty_u, u3nc(c3__aro, 'r')); break; case 'D': _term_io_belt(uty_u, u3nc(c3__aro, 'l')); break; + // + case 'M': tat_u->esc.mou = c3y; break; } tat_u->esc.ape = tat_u->esc.bra = c3n; } else { if ( (cay_y >= 'a') && (cay_y <= 'z') ) { tat_u->esc.ape = c3n; - _term_io_belt(uty_u, u3nc(c3__met, cay_y)); - } - else if ( '.' == cay_y ) { - tat_u->esc.ape = c3n; - _term_io_belt(uty_u, u3nc(c3__met, c3__dot)); + // XX for backwards compatibility, check kelvin version + // and fallback to [%met @c] + // + _term_io_belt(uty_u, u3nt(c3__mod, c3__met, cay_y)); } else if ( 8 == cay_y || 127 == cay_y ) { tat_u->esc.ape = c3n; - _term_io_belt(uty_u, u3nc(c3__met, c3__bac)); + // XX backwards compatibility [%met @c] + // + _term_io_belt(uty_u, u3nq(c3__mod, c3__met, c3__bac, u3_nul)); } else if ( ('[' == cay_y) || ('O' == cay_y) ) { tat_u->esc.bra = c3y; @@ -700,10 +681,31 @@ _term_io_suck_char(u3_utty* uty_u, c3_y cay_y) else { tat_u->esc.ape = c3n; - _term_it_dump_buf(uty_u, &uty_u->ufo_u.out.bel_u); + _term_it_dump_buf(uty_u, &uty_u->ufo_u.bel_u); } } } + // mouse input + // + else if ( c3y == tat_u->esc.mou ) { + if ( 0 == tat_u->esc.ton_y ) { + tat_u->esc.ton_y = cay_y - 31; + } + else if ( 0 == tat_u->esc.col_y ) { + tat_u->esc.col_y = cay_y - 32; + } + else { + c3_y row_y = cay_y - 32; + // only acknowledge button 1 presses within our window + if ( 1 != tat_u->esc.ton_y && row_y <= tat_u->siz.row_l ) { + _term_io_belt(uty_u, u3nt(c3__hit, tat_u->siz.row_l - row_y, tat_u->esc.col_y - 1)); + } + tat_u->esc.mou = c3n; + tat_u->esc.ton_y = tat_u->esc.col_y = 0; + } + } + // unicode inputs + // else if ( 0 != tat_u->fut.wid_w ) { tat_u->fut.syb_y[tat_u->fut.len_w++] = cay_y; @@ -719,26 +721,25 @@ _term_io_suck_char(u3_utty* uty_u, c3_y cay_y) _term_io_belt(uty_u, u3nt(c3__txt, wug, u3_nul)); } } + // individual characters + // else { - if ( (cay_y >= 32) && (cay_y < 127) ) { + if ( (cay_y >= 32) && (cay_y < 127) ) { // visual ascii _term_io_belt(uty_u, u3nt(c3__txt, cay_y, u3_nul)); } - else if ( 0 == cay_y ) { - _term_it_dump_buf(uty_u, &uty_u->ufo_u.out.bel_u); + else if ( 0 == cay_y ) { // null + _term_it_dump_buf(uty_u, &uty_u->ufo_u.bel_u); } - else if ( 8 == cay_y || 127 == cay_y ) { + else if ( 8 == cay_y || 127 == cay_y ) { // backspace & delete _term_io_belt(uty_u, u3nc(c3__bac, u3_nul)); } - else if ( 13 == cay_y || 10 == cay_y ) { + else if ( 10 == cay_y || 13 == cay_y ) { // newline & carriage return _term_io_belt(uty_u, u3nc(c3__ret, u3_nul)); } -#if 0 - else if ( 6 == cay_y ) { - _term_io_flow(uty_u); // XX hack - } -#endif else if ( cay_y <= 26 ) { - _term_io_belt(uty_u, u3nc(c3__ctl, ('a' + (cay_y - 1)))); + // XX backwards compatibility [%ctl @c] + // + _term_io_belt(uty_u, u3nt(c3__mod, c3__ctl, ('a' + (cay_y - 1)))); } else if ( 27 == cay_y ) { tat_u->esc.ape = c3y; @@ -781,14 +782,14 @@ _term_suck(u3_utty* uty_u, const c3_y* buf, ssize_t siz_i) // The process hangs if we do nothing (and ctrl-z // then corrupts the event log), so we force shutdown. // - u3l_log("term: hangup (EOF)\r\n"); + u3l_log("term: hangup (EOF)"); // XX revise // u3_pier_bail(u3_king_stub()); } else if ( siz_i < 0 ) { - u3l_log("term %d: read: %s\n", uty_u->tid_l, uv_strerror(siz_i)); + u3l_log("term %d: read: %s", uty_u->tid_l, uv_strerror(siz_i)); } else { c3_i i; @@ -874,14 +875,20 @@ _term_spin_step(u3_utty* uty_u) // NB: we simply bail out if anything goes wrong // { - uv_buf_t lef_u = uty_u->ufo_u.out.cub1_u; + uv_buf_t lef_u = uty_u->ufo_u.cub_u; c3_i fid_i = uty_u->fid_i; // One-time cursor backoff. // if ( c3n == tat_u->sun_u.diz_o ) { - c3_w i_w; + // if we know where the bottom line is, and the cursor is not on it, + // move it to the bottom left + // + if ( tat_u->siz.row_l && tat_u->mir.rus_w > 0 ) { + _term_it_send_csi(uty_u, 'H', 2, tat_u->siz.row_l, 0); + } + c3_w i_w; for ( i_w = bac_w; i_w < sol_w; i_w++ ) { if ( lef_u.len != write(fid_i, lef_u.base, lef_u.len) ) { return; @@ -917,6 +924,7 @@ _term_spin_timer_cb(uv_timer_t* tim_u) _term_spin_step(uty_u); } +#define _SPIN_FAST_US 100UL // spinner activation delay when expected #define _SPIN_COOL_US 500UL // spinner activation delay when cool #define _SPIN_WARM_US 50UL // spinner activation delay when warm #define _SPIN_RATE_US 250UL // spinner rate (ms/frame) @@ -941,7 +949,7 @@ u3_term_start_spinner(u3_atom say, c3_o del_o) { c3_d now_d = _term_msc_out_host(); c3_d end_d = tat_u->sun_u.end_d; - c3_d wen_d = (c3n == del_o) ? 0UL : + c3_d wen_d = (c3n == del_o) ? _SPIN_FAST_US : (now_d - end_d < _SPIN_IDLE_US) ? _SPIN_WARM_US : _SPIN_COOL_US; @@ -966,7 +974,7 @@ u3_term_stop_spinner(void) uv_timer_stop(&tat_u->sun_u.tim_u); if ( c3y == tat_u->sun_u.diz_o ) { - _term_it_refresh_line(uty_u); + _term_it_restore_line(uty_u); tat_u->sun_u.end_d = _term_msc_out_host(); tat_u->sun_u.diz_o = c3n; } @@ -1057,15 +1065,13 @@ u3_term_ef_ctlc(void) { u3_noun wir = u3nt(c3__term, '1', u3_nul); - u3_noun cad = u3nt(c3__belt, c3__ctl, 'c'); + u3_noun cad = u3nq(c3__belt, c3__mod, c3__ctl, 'c'); c3_assert( 1 == uty_u->tid_l ); c3_assert( uty_u->car_u ); _term_ovum_plan(uty_u->car_u, wir, cad); } - - _term_it_refresh_line(uty_u); } /* _term_it_put_value(): put numeric color value on lin_w. @@ -1152,10 +1158,10 @@ _term_it_put_deco(c3_w* lin_w, } } -/* _term_it_show_stub(): send styled text to terminal as ansi escape sequences +/* _term_it_send_stub(): send styled text, without saving */ static void -_term_it_show_stub(u3_utty* uty_u, +_term_it_send_stub(u3_utty* uty_u, u3_noun tub) { c3_w tuc_w = u3qb_lent(tub); @@ -1174,17 +1180,16 @@ _term_it_show_stub(u3_utty* uty_u, // allocate enough memory for every display character, plus styles // - //NOTE we use max 31 characters per styl for escape codes: - // 3 for opening, 4 for decorations, 15 for colors, 4 for closing, - // and 5 as separators between decorations and colors. + //NOTE we use max 48 characters per styl for escape codes: + // 2 for opening, 7 for decorations, 2x16 for colors, 4 for closing, + // and 3 as separators between decorations and colors. // - c3_w* lin_w = c3_malloc( sizeof(c3_w) * (lec_w + (31 * tuc_w)) ); + c3_w* lin_w = c3_malloc( sizeof(c3_w) * (lec_w + (48 * tuc_w)) ); // write the contents to the buffer, // tracking total and escape characters written // c3_w i_w = 0; - c3_w sap_w = 0; { u3_noun nub = tub; while ( u3_nul != nub ) { @@ -1204,7 +1209,6 @@ _term_it_show_stub(u3_utty* uty_u, c3_o mor_o = c3n; lin_w[i_w++] = 27; lin_w[i_w++] = '['; - sap_w += 2; // text decorations // @@ -1214,10 +1218,8 @@ _term_it_show_stub(u3_utty* uty_u, while ( u3_nul != des ) { if ( c3y == mor_o ) { lin_w[i_w++] = ';'; - sap_w++; } _term_it_put_deco(&lin_w[i_w++], u3h(des)); - sap_w++; mor_o = c3y; des = u3t(des); } @@ -1229,12 +1231,10 @@ _term_it_show_stub(u3_utty* uty_u, if ( u3_nul != bag ) { if ( c3y == mor_o ) { lin_w[i_w++] = ';'; - sap_w++; } lin_w[i_w++] = '4'; c3_w put_w = _term_it_put_tint(&lin_w[i_w], bag); i_w += put_w; - sap_w += ++put_w; mor_o = c3y; } @@ -1243,17 +1243,14 @@ _term_it_show_stub(u3_utty* uty_u, if ( u3_nul != fog ) { if ( c3y == mor_o ) { lin_w[i_w++] = ';'; - sap_w++; } lin_w[i_w++] = '3'; c3_w put_w = _term_it_put_tint(&lin_w[i_w], fog); i_w += put_w; - sap_w += ++put_w; mor_o = c3y; } lin_w[i_w++] = 'm'; - sap_w++; } // write the text itself @@ -1269,18 +1266,27 @@ _term_it_show_stub(u3_utty* uty_u, lin_w[i_w++] = '['; lin_w[i_w++] = '0'; lin_w[i_w++] = 'm'; - sap_w += 4; } nub = u3t(nub); } } - _term_it_set_line(uty_u, lin_w, i_w, sap_w); + _term_it_show_line(uty_u, lin_w, i_w); u3z(tub); } +/* _term_it_send_stub(): send styled text to terminal as ansi escape sequences +*/ +static void +_term_it_show_stub(u3_utty* uty_u, + u3_noun tub) +{ + _term_it_send_stub(uty_u, u3k(tub)); + _term_it_save_stub(uty_u, tub); +} + /* _term_it_show_tour(): send utf32 to terminal. */ static void @@ -1298,9 +1304,14 @@ _term_it_show_tour(u3_utty* uty_u, } } - _term_it_set_line(uty_u, lin_w, len_w, 0); + _term_it_show_line(uty_u, lin_w, len_w); - u3z(lin); + { + u3_noun tub = u3i_list(u3nc(u3nt(u3_nul, u3_nul, u3_nul), lin), u3_none); + _term_it_save_stub(uty_u, tub); + } + + //NOTE lin transferred to tub above } /* _term_ef_blit(): send blit to terminal. @@ -1313,40 +1324,38 @@ _term_ef_blit(u3_utty* uty_u, default: break; case c3__bel: { - if ( c3n == u3_Host.ops_u.tem ) { - _term_it_dump_buf(uty_u, &uty_u->ufo_u.out.bel_u); - } + _term_it_dump_buf(uty_u, &uty_u->ufo_u.bel_u); } break; case c3__clr: { - if ( c3n == u3_Host.ops_u.tem ) { - _term_it_show_blank(uty_u); - _term_it_refresh_line(uty_u); - } + _term_it_show_blank(uty_u); } break; case c3__hop: { - if ( c3n == u3_Host.ops_u.tem ) { - _term_it_show_cursor(uty_u, u3t(blt)); + u3_noun pos = u3t(blt); + if ( c3y == u3r_ud(pos) ) { + _term_it_move_cursor(uty_u, 0, pos); + } + else { + _term_it_move_cursor(uty_u, u3h(pos), u3t(pos)); } } break; case c3__klr: { - if ( c3n == u3_Host.ops_u.tem ) { - _term_it_show_clear(uty_u); - } _term_it_show_stub(uty_u, u3k(u3t(blt))); } break; - case c3__lin: { - if ( c3n == u3_Host.ops_u.tem ) { - _term_it_show_clear(uty_u); - } + case c3__lin: { //TMP backwards compatibility + _term_it_move_cursor(uty_u, 0, 0); + _term_it_clear_line(uty_u); + } // + case c3__put: { _term_it_show_tour(uty_u, u3k(u3t(blt))); } break; - case c3__mor: { - _term_it_show_more(uty_u); + case c3__mor: //TMP backwards compatibility + case c3__nel: { + _term_it_show_nel(uty_u); } break; case c3__sav: { @@ -1364,20 +1373,50 @@ _term_ef_blit(u3_utty* uty_u, } break; case c3__url: { - u3_noun txt = u3t(blt); + // platform-agnostically opening the default web browser from within a + // c program is an unsolved problem. + } break; - // XX check u3_Host.ops_u.tem ? - // XX this looks to be broken, - // multiple calls to _show_clear will discard the mirror state - // - if ( c3y == u3a_is_atom(txt) ) { - _term_it_show_clear(uty_u); + case c3__wyp: { + _term_it_clear_line(uty_u); + } break; + } - _term_it_send_cord(uty_u, u3k(txt)); + u3z(blt); +} - _term_it_show_more(uty_u); - _term_it_refresh_line(uty_u); - } +/* _term_ef_blit_lame(): simplified output handling for -t +*/ +static void +_term_ef_blit_lame(u3_utty* uty_u, + u3_noun blt) +{ + switch ( u3h(blt) ) { + default: break; + + case c3__klr: { + _term_it_show_stub(uty_u, u3k(u3t(blt))); + _term_it_show_nel(uty_u); + } break; + + case c3__lin: //TMP backwards compatibility + case c3__put: { + _term_it_show_tour(uty_u, u3k(u3t(blt))); + _term_it_show_nel(uty_u); + } break; + + case c3__sav: { + u3_noun pax, dat; + u3x_cell(u3t(blt), &pax, &dat); + + _term_it_save(u3k(pax), u3k(dat)); + } break; + + case c3__sag: { + u3_noun pax, dat; + u3x_cell(u3t(blt), &pax, &dat); + + _term_it_save(u3k(pax), u3qe_jam(dat)); } break; } @@ -1391,7 +1430,7 @@ u3_term_io_hija(void) { u3_utty* uty_u = _term_main(); - if ( uty_u ) { + if ( uty_u && uty_u->tat_u.siz.row_l ) { if ( uty_u->fid_i > 2 ) { // We *should* in fact, produce some kind of fake FILE* for // non-console terminals. If we use this interface enough... @@ -1403,11 +1442,14 @@ u3_term_io_hija(void) if ( c3y != uty_u->hij_f(uty_u) ) { c3_assert(!"hija-tcsetattr"); } - u3_write_fd(uty_u->fid_i, "\r", 1); - { - uv_buf_t* buf_u = &uty_u->ufo_u.out.el_u; - u3_write_fd(uty_u->fid_i, buf_u->base, buf_u->len); - } + + // set scroll region to exclude the prompt, + // scroll up one line to make space, + // and move the cursor onto that space. + // + _term_it_send_csi(uty_u, 'r', 2, 1, uty_u->tat_u.siz.row_l - 1); + _term_it_send_csi(uty_u, 'S', 1, 1); + _term_it_send_csi(uty_u, 'H', 2, uty_u->tat_u.siz.row_l - 1, 1); } } } @@ -1417,11 +1459,11 @@ u3_term_io_hija(void) /* u3_term_io_loja(): release console from fprintf. */ void -u3_term_io_loja(int x) +u3_term_io_loja(int x, FILE* f) { u3_utty* uty_u = _term_main(); - if ( uty_u ) { + if ( uty_u && uty_u->tat_u.siz.row_l ) { if ( uty_u->fid_i > 2 ) { // We *should* in fact, produce some kind of fake FILE* for // non-console terminals. If we use this interface enough... @@ -1430,15 +1472,25 @@ u3_term_io_loja(int x) } else { if ( c3y == u3_Host.ops_u.tem ) { - fflush(stdout); - } else { + fprintf(f, "\n"); + fflush(f); + } + else { if ( c3y != uty_u->loj_f(uty_u) ) { c3_assert(!"loja-tcsetattr"); } - _term_it_refresh_line(uty_u); + + // clear the scrolling region we set previously, + // and restore cursor to its original position. + // + _term_it_dump_buf(uty_u, &uty_u->ufo_u.reg_u); + _term_it_dump_buf(uty_u, &uty_u->ufo_u.ruc_u); } } } + else { + fprintf(f, "\r\n"); + } } /* u3_term_it_log(): writes a log message @@ -1447,7 +1499,9 @@ void u3_term_io_log(c3_c* line) { FILE* stream = u3_term_io_hija(); - u3_term_io_loja(fprintf(stream, "%s", line)); + int x = fprintf(stream, "%s", line); + fflush(stream); + u3_term_io_loja(x, stream); //TODO remove arg? unused... } /* u3_term_tape_to(): dump a tape to a file. @@ -1479,7 +1533,7 @@ u3_term_tape(u3_noun tep) u3_term_tape_to(fil_f, tep); - u3_term_io_loja(0); + u3_term_io_loja(0, fil_f); } /* u3_term_wall(): dump a wall to stdout. @@ -1498,7 +1552,7 @@ u3_term_wall(u3_noun wol) wal = u3t(wal); } - u3_term_io_loja(0); + u3_term_io_loja(0, fil_f); u3z(wol); } @@ -1511,12 +1565,16 @@ _term_io_talk(u3_auto* car_u) if ( c3n == u3_Host.ops_u.tem ) { u3_utty* uty_u = _term_main(); + // start mouse handling + // + _term_it_dump_buf(uty_u, &uty_u->ufo_u.mon_u); + uv_read_start((uv_stream_t*)&(uty_u->pin_u), _term_alloc, _term_read_cb); } - // XX groace hardcoded terminal number + //TODO reevaluate wrt dill sessions // u3_noun wir = u3nt(c3__term, '1', u3_nul); u3_noun cad; @@ -1528,10 +1586,6 @@ _term_io_talk(u3_auto* car_u) _term_ovum_plan(car_u, u3k(wir), cad); } - // NB, term.c used to also start :dojo - // - // u3nq(c3__flow, c3__seat, c3__dojo, u3_nul) - // refresh terminal state // { @@ -1584,7 +1638,7 @@ _term_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) || (u3_nul != q_pud) || (c3n == _reck_orchid(c3__ud, u3k(p_pud), &tid_l)) ) { - u3l_log("term: bad tire\n"); + u3l_log("term: bad tire"); ret_o = c3n; } else { @@ -1593,26 +1647,25 @@ _term_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) ret_o = c3n; } break; - // XX review, accepted and ignored - // - case c3__bbye: { - ret_o = c3y; - } break; - case c3__blit: { ret_o = c3y; { u3_utty* uty_u = _term_ef_get(tid_l); if ( 0 == uty_u ) { - // u3l_log("no terminal %d\n", tid_l); - // u3l_log("uty_u %p\n", u3_Host.uty_u); + // u3l_log("no terminal %d", tid_l); + // u3l_log("uty_u %p", u3_Host.uty_u); } else { u3_noun bis = dat; while ( c3y == u3du(bis) ) { - _term_ef_blit(uty_u, u3k(u3h(bis))); + if (c3n == u3_Host.ops_u.tem) { + _term_ef_blit(uty_u, u3k(u3h(bis))); + } + else { + _term_ef_blit_lame(uty_u, u3k(u3h(bis))); + } bis = u3t(bis); } } @@ -1673,6 +1726,10 @@ _term_io_exit(u3_auto* car_u) u3_utty* uty_u = _term_main(); if ( c3n == u3_Host.ops_u.tem ) { + // stop mouse handling + // + _term_it_dump_buf(uty_u, &uty_u->ufo_u.mof_u); + // NB, closed in u3_term_log_exit() // uv_read_stop((uv_stream_t*)&(uty_u->pin_u)); diff --git a/pkg/urbit/vere/io/unix.c b/pkg/urbit/vere/io/unix.c index 4526298bc..e38ac6b15 100644 --- a/pkg/urbit/vere/io/unix.c +++ b/pkg/urbit/vere/io/unix.c @@ -162,35 +162,35 @@ _unix_rm_r_cb(const c3_c* pax_c, { switch ( typeflag ) { default: - u3l_log("bad file type in rm_r: %s\r\n", pax_c); + u3l_log("bad file type in rm_r: %s", pax_c); break; case FTW_F: if ( 0 != unlink(pax_c) && ENOENT != errno ) { - u3l_log("error unlinking (in rm_r) %s: %s\n", + u3l_log("error unlinking (in rm_r) %s: %s", pax_c, strerror(errno)); c3_assert(0); } break; case FTW_D: - u3l_log("shouldn't have gotten pure directory: %s\r\n", pax_c); + u3l_log("shouldn't have gotten pure directory: %s", pax_c); break; case FTW_DNR: - u3l_log("couldn't read directory: %s\r\n", pax_c); + u3l_log("couldn't read directory: %s", pax_c); break; case FTW_NS: - u3l_log("couldn't stat path: %s\r\n", pax_c); + u3l_log("couldn't stat path: %s", pax_c); break; case FTW_DP: if ( 0 != rmdir(pax_c) && ENOENT != errno ) { - u3l_log("error rmdiring %s: %s\n", pax_c, strerror(errno)); + u3l_log("error rmdiring %s: %s", pax_c, strerror(errno)); c3_assert(0); } break; case FTW_SL: - u3l_log("got symbolic link: %s\r\n", pax_c); + u3l_log("got symbolic link: %s", pax_c); break; case FTW_SLN: - u3l_log("got nonexistent symbolic link: %s\r\n", pax_c); + u3l_log("got nonexistent symbolic link: %s", pax_c); break; } @@ -204,7 +204,7 @@ _unix_rm_r(c3_c* pax_c) { if ( 0 > nftw(pax_c, _unix_rm_r_cb, 100, FTW_DEPTH | FTW_PHYS ) && ENOENT != errno) { - u3l_log("rm_r error on %s: %s\r\n", pax_c, strerror(errno)); + u3l_log("rm_r error on %s: %s", pax_c, strerror(errno)); } } @@ -214,7 +214,7 @@ static void _unix_mkdir(c3_c* pax_c) { if ( 0 != mkdir(pax_c, 0755) && EEXIST != errno) { - u3l_log("error mkdiring %s: %s\n", pax_c, strerror(errno)); + u3l_log("error mkdiring %s: %s", pax_c, strerror(errno)); c3_assert(0); } } @@ -231,7 +231,7 @@ _unix_write_file_hard(c3_c* pax_c, u3_noun mim) u3_noun dat = u3t(u3t(mim)); if ( fid_i < 0 ) { - u3l_log("error opening %s for writing: %s\r\n", + u3l_log("error opening %s for writing: %s", pax_c, strerror(errno)); u3z(mim); return 0; @@ -247,7 +247,7 @@ _unix_write_file_hard(c3_c* pax_c, u3_noun mim) rit_w = write(fid_i, dat_y, siz_w); if ( rit_w != siz_w ) { - u3l_log("error writing %s: %s\r\n", + u3l_log("error writing %s: %s", pax_c, strerror(errno)); mug_w = 0; } @@ -277,7 +277,7 @@ _unix_write_file_soft(u3_ufil* fil_u, u3_noun mim) goto _unix_write_file_soft_go; } else { - u3l_log("error opening file (soft) %s: %s\r\n", + u3l_log("error opening file (soft) %s: %s", fil_u->pax_c, strerror(errno)); u3z(mim); return; @@ -290,17 +290,17 @@ _unix_write_file_soft(u3_ufil* fil_u, u3_noun mim) red_ws = read(fid_i, old_y, len_ws); if ( close(fid_i) < 0 ) { - u3l_log("error closing file (soft) %s: %s\r\n", + u3l_log("error closing file (soft) %s: %s", fil_u->pax_c, strerror(errno)); } if ( len_ws != red_ws ) { if ( red_ws < 0 ) { - u3l_log("error reading file (soft) %s: %s\r\n", + u3l_log("error reading file (soft) %s: %s", fil_u->pax_c, strerror(errno)); } else { - u3l_log("wrong # of bytes read in file %s: %d %d\r\n", + u3l_log("wrong # of bytes read in file %s: %d %d", fil_u->pax_c, len_ws, red_ws); } c3_free(old_y); @@ -376,7 +376,7 @@ _unix_scan_mount_point(u3_unix* unx_u, u3_umon* mon_u) { DIR* rid_u = opendir(mon_u->dir_u.pax_c); if ( !rid_u ) { - u3l_log("error opening pier directory: %s: %s\r\n", + u3l_log("error opening pier directory: %s: %s", mon_u->dir_u.pax_c, strerror(errno)); return; } @@ -389,7 +389,7 @@ _unix_scan_mount_point(u3_unix* unx_u, u3_umon* mon_u) c3_w err_w; if ( 0 != (err_w = u3_readdir_r(rid_u, &ent_u, &out_u)) ) { - u3l_log("erroring loading pier directory %s: %s\r\n", + u3l_log("erroring loading pier directory %s: %s", mon_u->dir_u.pax_c, strerror(errno)); c3_assert(0); @@ -409,7 +409,7 @@ _unix_scan_mount_point(u3_unix* unx_u, u3_umon* mon_u) struct stat buf_u; if ( 0 != stat(pax_c, &buf_u) ) { - u3l_log("can't stat pier directory %s: %s\r\n", + u3l_log("can't stat pier directory %s: %s", mon_u->dir_u.pax_c, strerror(errno)); c3_free(pax_c); continue; @@ -453,7 +453,7 @@ static void _unix_free_file(u3_ufil *fil_u) { if ( 0 != unlink(fil_u->pax_c) && ENOENT != errno ) { - u3l_log("error unlinking %s: %s\n", fil_u->pax_c, strerror(errno)); + u3l_log("error unlinking %s: %s", fil_u->pax_c, strerror(errno)); c3_assert(0); } @@ -565,7 +565,7 @@ _unix_delete_mount_point(u3_unix* unx_u, u3_noun mon) mon_u = unx_u->mon_u; if ( !mon_u ) { - u3l_log("mount point already gone: %s\r\n", nam_c); + u3l_log("mount point already gone: %s", nam_c); goto _delete_mount_point_out; } if ( 0 == strcmp(nam_c, mon_u->nam_c) ) { @@ -581,7 +581,7 @@ _unix_delete_mount_point(u3_unix* unx_u, u3_noun mon) } if ( !mon_u->nex_u ) { - u3l_log("mount point already gone: %s\r\n", nam_c); + u3l_log("mount point already gone: %s", nam_c); goto _delete_mount_point_out; } @@ -699,7 +699,7 @@ _unix_update_file(u3_unix* unx_u, u3_ufil* fil_u) return u3nc(u3nc(_unix_string_to_path(unx_u, fil_u->pax_c), u3_nul), u3_nul); } else { - u3l_log("error opening file %s: %s\r\n", + u3l_log("error opening file %s: %s", fil_u->pax_c, strerror(errno)); return u3_nul; } @@ -711,17 +711,17 @@ _unix_update_file(u3_unix* unx_u, u3_ufil* fil_u) red_ws = read(fid_i, dat_y, len_ws); if ( close(fid_i) < 0 ) { - u3l_log("error closing file %s: %s\r\n", + u3l_log("error closing file %s: %s", fil_u->pax_c, strerror(errno)); } if ( len_ws != red_ws ) { if ( red_ws < 0 ) { - u3l_log("error reading file %s: %s\r\n", + u3l_log("error reading file %s: %s", fil_u->pax_c, strerror(errno)); } else { - u3l_log("wrong # of bytes read in file %s: %d %d\r\n", + u3l_log("wrong # of bytes read in file %s: %d %d", fil_u->pax_c, len_ws, red_ws); } c3_free(dat_y); @@ -790,7 +790,7 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u) if ( (fid_i < 0) || (fstat(fid_i, &buf_u) < 0) ) { if ( ENOENT != errno ) { - u3l_log("_unix_update_dir: error opening file %s: %s\r\n", + u3l_log("_unix_update_dir: error opening file %s: %s", nod_u->pax_c, strerror(errno)); } @@ -800,7 +800,7 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u) } else { if ( close(fid_i) < 0 ) { - u3l_log("_unix_update_dir: error closing file %s: %s\r\n", + u3l_log("_unix_update_dir: error closing file %s: %s", nod_u->pax_c, strerror(errno)); } @@ -815,7 +815,7 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u) DIR* rid_u = opendir(dir_u->pax_c); if ( !rid_u ) { - u3l_log("error opening directory %s: %s\r\n", + u3l_log("error opening directory %s: %s", dir_u->pax_c, strerror(errno)); c3_assert(0); } @@ -827,7 +827,7 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u) if ( (err_w = u3_readdir_r(rid_u, &ent_u, &out_u)) != 0 ) { - u3l_log("error loading directory %s: %s\r\n", + u3l_log("error loading directory %s: %s", dir_u->pax_c, strerror(err_w)); c3_assert(0); } @@ -843,7 +843,7 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u) struct stat buf_u; if ( 0 != stat(pax_c, &buf_u) ) { - u3l_log("can't stat %s: %s\r\n", pax_c, strerror(errno)); + u3l_log("can't stat %s: %s", pax_c, strerror(errno)); c3_free(pax_c); continue; } @@ -853,13 +853,13 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u) if ( 0 == strcmp(pax_c, nod_u->pax_c) ) { if ( S_ISDIR(buf_u.st_mode) ) { if ( c3n == nod_u->dir ) { - u3l_log("not a directory: %s\r\n", nod_u->pax_c); + u3l_log("not a directory: %s", nod_u->pax_c); c3_assert(0); } } else { if ( c3y == nod_u->dir ) { - u3l_log("not a file: %s\r\n", nod_u->pax_c); + u3l_log("not a file: %s", nod_u->pax_c); c3_assert(0); } } @@ -894,7 +894,7 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u) } if ( closedir(rid_u) < 0 ) { - u3l_log("error closing directory %s: %s\r\n", + u3l_log("error closing directory %s: %s", dir_u->pax_c, strerror(errno)); } @@ -965,7 +965,7 @@ _unix_initial_update_file(c3_c* pax_c, c3_c* bas_c) return u3_nul; } else { - u3l_log("error opening initial file %s: %s\r\n", + u3l_log("error opening initial file %s: %s", pax_c, strerror(errno)); return u3_nul; } @@ -977,17 +977,17 @@ _unix_initial_update_file(c3_c* pax_c, c3_c* bas_c) red_ws = read(fid_i, dat_y, len_ws); if ( close(fid_i) < 0 ) { - u3l_log("error closing initial file %s: %s\r\n", + u3l_log("error closing initial file %s: %s", pax_c, strerror(errno)); } if ( len_ws != red_ws ) { if ( red_ws < 0 ) { - u3l_log("error reading initial file %s: %s\r\n", + u3l_log("error reading initial file %s: %s", pax_c, strerror(errno)); } else { - u3l_log("wrong # of bytes read in initial file %s: %d %d\r\n", + u3l_log("wrong # of bytes read in initial file %s: %d %d", pax_c, len_ws, red_ws); } c3_free(dat_y); @@ -1015,7 +1015,7 @@ _unix_initial_update_dir(c3_c* pax_c, c3_c* bas_c) DIR* rid_u = opendir(pax_c); if ( !rid_u ) { - u3l_log("error opening initial directory: %s: %s\r\n", + u3l_log("error opening initial directory: %s: %s", pax_c, strerror(errno)); return u3_nul; } @@ -1026,7 +1026,7 @@ _unix_initial_update_dir(c3_c* pax_c, c3_c* bas_c) c3_w err_w; if ( 0 != (err_w = u3_readdir_r(rid_u, &ent_u, &out_u)) ) { - u3l_log("error loading initial directory %s: %s\r\n", + u3l_log("error loading initial directory %s: %s", pax_c, strerror(errno)); c3_assert(0); @@ -1043,7 +1043,7 @@ _unix_initial_update_dir(c3_c* pax_c, c3_c* bas_c) struct stat buf_u; if ( 0 != stat(pox_c, &buf_u) ) { - u3l_log("initial can't stat %s: %s\r\n", + u3l_log("initial can't stat %s: %s", pox_c, strerror(errno)); c3_free(pox_c); continue; @@ -1061,7 +1061,7 @@ _unix_initial_update_dir(c3_c* pax_c, c3_c* bas_c) } if ( closedir(rid_u) < 0 ) { - u3l_log("error closing initial directory %s: %s\r\n", + u3l_log("error closing initial directory %s: %s", pax_c, strerror(errno)); } @@ -1152,16 +1152,16 @@ _unix_sync_change(u3_unix* unx_u, u3_udir* dir_u, u3_noun pax, u3_noun mim) if ( c3n == u3du(pax) ) { if ( u3_nul == pax ) { - u3l_log("can't sync out file as top-level, strange\r\n"); + u3l_log("can't sync out file as top-level, strange"); } else { - u3l_log("sync out: bad path\r\n"); + u3l_log("sync out: bad path"); } u3z(pax); u3z(mim); return; } else if ( c3n == u3du(u3t(pax)) ) { - u3l_log("can't sync out file as top-level, strangely\r\n"); + u3l_log("can't sync out file as top-level, strangely"); u3z(pax); u3z(mim); } else { @@ -1191,7 +1191,7 @@ _unix_sync_change(u3_unix* unx_u, u3_udir* dir_u, u3_noun pax, u3_noun mim) } if ( c3n == nod_u->dir ) { - u3l_log("weird, we got a file when we weren't expecting to\r\n"); + u3l_log("weird, we got a file when we weren't expecting to"); c3_assert(0); } @@ -1274,7 +1274,7 @@ u3_unix_acquire(c3_c* pax_c) if ( NULL != (loq_u = fopen(paf_c, "r")) ) { if ( 1 != fscanf(loq_u, "%" SCNu32, &pid_w) ) { - u3l_log("lockfile %s is corrupt!\n", paf_c); + u3l_log("lockfile %s is corrupt!", paf_c); kill(getpid(), SIGTERM); sleep(1); c3_assert(0); } @@ -1282,7 +1282,7 @@ u3_unix_acquire(c3_c* pax_c) c3_w i_w; if ( -1 != kill(pid_w, SIGTERM) ) { - u3l_log("unix: stopping process %d, live in %s...\n", + u3l_log("unix: stopping process %d, live in %s...", pid_w, pax_c); for ( i_w = 0; i_w < 16; i_w++ ) { @@ -1300,10 +1300,10 @@ u3_unix_acquire(c3_c* pax_c) } } if ( 16 == i_w ) { - u3l_log("unix: process %d seems unkillable!\n", pid_w); + u3l_log("unix: process %d seems unkillable!", pid_w); c3_assert(0); } - u3l_log("unix: stopped old process %u\n", pid_w); + u3l_log("unix: stopped old process %u", pid_w); } } fclose(loq_u); @@ -1311,7 +1311,7 @@ u3_unix_acquire(c3_c* pax_c) } if ( NULL == (loq_u = fopen(paf_c, "w")) ) { - u3l_log("unix: unable to open %s\n", paf_c); + u3l_log("unix: unable to open %s", paf_c); c3_assert(0); } diff --git a/pkg/urbit/vere/king.c b/pkg/urbit/vere/king.c index e857d6040..c9587fad2 100644 --- a/pkg/urbit/vere/king.c +++ b/pkg/urbit/vere/king.c @@ -245,7 +245,7 @@ _king_get_atom(c3_c* url_c) uv_buf_t buf_u = uv_buf_init(c3_malloc(1), 0); if ( !(curl = curl_easy_init()) ) { - u3l_log("failed to initialize libcurl\n"); + u3l_log("failed to initialize libcurl"); exit(1); } @@ -260,13 +260,13 @@ _king_get_atom(c3_c* url_c) // XX retry? // if ( CURLE_OK != result ) { - u3l_log("failed to fetch %s: %s\n", + u3l_log("failed to fetch %s: %s", url_c, curl_easy_strerror(result)); u3_king_bail(); exit(1); } if ( 300 <= cod_l ) { - u3l_log("error fetching %s: HTTP %ld\n", url_c, cod_l); + u3l_log("error fetching %s: HTTP %ld", url_c, cod_l); u3_king_bail(); exit(1); } @@ -292,12 +292,12 @@ _get_cmd_output(c3_c *cmd_c, c3_c *out_c, c3_w len_c) { FILE *fp = popen(cmd_c, "r"); if ( NULL == fp ) { - u3l_log("'%s' failed\n", cmd_c); + u3l_log("'%s' failed", cmd_c); exit(1); } if ( NULL == fgets(out_c, len_c, fp) ) { - u3l_log("'%s' produced no output\n", cmd_c); + u3l_log("'%s' produced no output", cmd_c); exit(1); } @@ -330,7 +330,7 @@ _git_pill_url(c3_c *out_c, c3_c *arv_c) assert(NULL != arv_c); if ( 0 != system("which git >> /dev/null") ) { - u3l_log("boot: could not find git executable\r\n"); + u3l_log("boot: could not find git executable"); exit(1); } @@ -347,7 +347,7 @@ _boothack_pill(void) u3_noun pil; if ( 0 != u3_Host.ops_u.pil_c ) { - u3l_log("boot: loading pill %s\r\n", u3_Host.ops_u.pil_c); + u3l_log("boot: loading pill %s", u3_Host.ops_u.pil_c); pil = u3m_file(u3_Host.ops_u.pil_c); } else { @@ -363,12 +363,12 @@ _boothack_pill(void) strcpy(url_c, u3_Host.ops_u.url_c); } - u3l_log("boot: downloading pill %s\r\n", url_c); + u3l_log("boot: downloading pill %s", url_c); pil = _king_get_atom(url_c); } if ( 0 != u3_Host.ops_u.arv_c ) { - u3l_log("boot: preparing filesystem from %s\r\n", + u3l_log("boot: preparing filesystem from %s", u3_Host.ops_u.arv_c); arv = u3nc(u3_nul, u3_unix_initial_into_card(u3_Host.ops_u.arv_c)); } @@ -389,7 +389,7 @@ _boothack_key(u3_noun kef) if ( u3_nul == des ) { c3_c* kef_c = u3r_string(kef); - u3l_log("dawn: invalid private keys: %s\r\n", kef_c); + u3l_log("dawn: invalid private keys: %s", kef_c); c3_free(kef_c); exit(1); } @@ -398,7 +398,7 @@ _boothack_key(u3_noun kef) // u3_noun pro = u3m_soft(0, u3ke_cue, u3k(u3t(des))); if ( u3_blip != u3h(pro) ) { - u3l_log("dawn: unable to cue keyfile\r\n"); + u3l_log("dawn: unable to cue keyfile"); exit(1); } seed = u3k(u3t(pro)); @@ -421,7 +421,7 @@ _boothack_key(u3_noun kef) u3_noun whu = u3dc("slaw", 'p', u3k(woh)); if ( u3_nul == whu ) { - u3l_log("dawn: invalid ship specified with -w %s\r\n", + u3l_log("dawn: invalid ship specified with -w %s", u3_Host.ops_u.who_c); exit(1); } @@ -431,7 +431,7 @@ _boothack_key(u3_noun kef) { u3_noun how = u3dc("scot", 'p', u3k(ship)); c3_c* how_c = u3r_string(u3k(how)); - u3l_log("dawn: mismatch between -w %s and -K %s\r\n", + u3l_log("dawn: mismatch between -w %s and -K %s", u3_Host.ops_u.who_c, how_c); u3z(how); @@ -462,7 +462,7 @@ _boothack_doom(void) u3_noun whu = u3dc("slaw", 'p', u3k(fak)); if ( u3_nul == whu ) { - u3l_log("boot: malformed -F ship %s\r\n", u3_Host.ops_u.fak_c); + u3l_log("boot: malformed -F ship %s", u3_Host.ops_u.fak_c); exit(1); } @@ -496,7 +496,7 @@ _boothack_doom(void) kef = u3i_string(u3_Host.ops_u.gen_c); } else { - u3l_log("boot: must specify a key with -k or -G\r\n"); + u3l_log("boot: must specify a key with -k or -G"); exit(1); } @@ -591,7 +591,7 @@ _king_sign_cb(uv_signal_t* sil_u, c3_i num_i) { switch ( num_i ) { default: { - u3l_log("\r\nmysterious signal %d\r\n", num_i); + u3l_log("\r\nmysterious signal %d", num_i); break; } @@ -601,7 +601,7 @@ _king_sign_cb(uv_signal_t* sil_u, c3_i num_i) } case SIGINT: { - u3l_log("\r\ninterrupt\r\n"); + u3l_log("\r\ninterrupt"); u3_term_ef_ctlc(); #if defined(U3_OS_mingw) @@ -704,7 +704,7 @@ _king_boot_ivory(void) if ( u3_Host.ops_u.lit_c ) { if ( c3n == u3u_mmap_read("lite", u3_Host.ops_u.lit_c, &len_d, &byt_y) ) { - u3l_log("lite: unable to load ivory pill at %s\n", + u3l_log("lite: unable to load ivory pill at %s", u3_Host.ops_u.lit_c); exit(1); } @@ -719,21 +719,21 @@ _king_boot_ivory(void) u3_weak pil; if ( u3_none == (pil = u3s_cue_xeno_with(sil_u, len_d, byt_y)) ) { - u3l_log("lite: unable to cue ivory pill\r\n"); + u3l_log("lite: unable to cue ivory pill"); exit(1); } u3s_cue_xeno_done(sil_u); if ( c3n == u3v_boot_lite(pil)) { - u3l_log("lite: boot failed\r\n"); + u3l_log("lite: boot failed"); exit(1); } } if ( u3_Host.ops_u.lit_c ) { if ( c3n == u3u_munmap(len_d, byt_y) ) { - u3l_log("lite: unable to unmap ivory pill at %s\n", + u3l_log("lite: unable to unmap ivory pill at %s", u3_Host.ops_u.lit_c); exit(1); } @@ -787,7 +787,7 @@ u3_king_commence() rlm.rlim_cur = 0; if ( 0 != setrlimit(RLIMIT_CORE, &rlm) ) { - u3l_log("king: unable to disable core dumps: %s\r\n", strerror(errno)); + u3l_log("king: unable to disable core dumps: %s", strerror(errno)); exit(1); } } @@ -955,7 +955,7 @@ u3_king_grab(void* vod_p) } #else { - u3_term_io_loja(0); + u3_term_io_loja(0, fil_u); } #endif } diff --git a/pkg/urbit/vere/lord.c b/pkg/urbit/vere/lord.c index 25ffe6096..e07d9ceb4 100644 --- a/pkg/urbit/vere/lord.c +++ b/pkg/urbit/vere/lord.c @@ -267,13 +267,13 @@ _lord_plea_live(u3_lord* god_u, u3_noun dat) case u3_writ_meld: { // XX wire into cb // - u3l_log("pier: meld complete\n"); + u3l_log("pier: meld complete"); } break; case u3_writ_pack: { // XX wire into cb // - u3l_log("pier: pack complete\n"); + u3l_log("pier: pack complete"); } break; } @@ -1098,10 +1098,10 @@ _lord_on_serf_bail(void* ptr_v, u3_lord* god_u = ptr_v; if ( UV_EOF == err_i ) { - u3l_log("pier: serf unexpectedly shut down\r\n"); + u3l_log("pier: serf unexpectedly shut down"); } else { - u3l_log("pier: serf error: %s\r\n", err_c); + u3l_log("pier: serf error: %s", err_c); } _lord_bail(god_u); @@ -1112,7 +1112,7 @@ _lord_on_serf_bail(void* ptr_v, void u3_lord_info(u3_lord* god_u) { - u3l_log(" lord: live=%s, event=%" PRIu64 ", mug=%x, queue=%u\n", + u3l_log(" lord: live=%s, event=%" PRIu64 ", mug=%x, queue=%u", ( c3y == god_u->liv_o ) ? "&" : "|", god_u->eve_d, god_u->mug_l, @@ -1148,7 +1148,7 @@ u3_lord_init(c3_c* pax_c, c3_w wag_w, c3_d key_d[4], u3_lord_cb cb_u) c3_c cev_c[11]; c3_i err_i; - sprintf(key_c, "%" PRIx64 ":%" PRIx64 ":%" PRIx64 ":%" PRIx64 "", + sprintf(key_c, "%" PRIx64 ":%" PRIx64 ":%" PRIx64 ":%" PRIx64, god_u->key_d[0], god_u->key_d[1], god_u->key_d[2], diff --git a/pkg/urbit/vere/newt.c b/pkg/urbit/vere/newt.c index 6325f0ef9..5c8a2a693 100644 --- a/pkg/urbit/vere/newt.c +++ b/pkg/urbit/vere/newt.c @@ -362,7 +362,7 @@ u3_newt_moat_info(u3_moat* mot_u) } if ( len_w ) { - u3l_log(" newt: %u inbound ipc messages pending\n", len_w); + u3l_log(" newt: %u inbound ipc messages pending", len_w); } } diff --git a/pkg/urbit/vere/pier.c b/pkg/urbit/vere/pier.c index 2bd308534..c64df414d 100644 --- a/pkg/urbit/vere/pier.c +++ b/pkg/urbit/vere/pier.c @@ -251,7 +251,7 @@ _pier_work(u3_work* wok_u) // XX this is when "boot" is actually complete // XX even better would be after neighboring with our sponsor // - u3l_log("pier (%" PRIu64 "): live\r\n", pir_u->god_u->eve_d); + u3l_log("pier (%" PRIu64 "): live", pir_u->god_u->eve_d); // XX move callbacking to king // @@ -286,7 +286,7 @@ _pier_on_lord_work_spin(void* ptr_v, u3_atom pin, c3_o del_o) u3_term_start_spinner(pin, del_o); } -/* _pier_on_lord_work_spin(): stop spinner +/* _pier_on_lord_work_spun(): stop spinner */ static void _pier_on_lord_work_spun(void* ptr_v) @@ -472,13 +472,13 @@ _pier_on_scry_done(void* ptr_v, u3_noun nun) u3_weak res = u3r_at(7, nun); if (u3_none == res) { - u3l_log("pier: scry failed\n"); + u3l_log("pier: scry failed"); } else { u3_weak out, pad; c3_c *ext_c, *pac_c; - u3l_log("pier: scry succeeded\n"); + u3l_log("pier: scry succeeded"); if ( u3_Host.ops_u.puk_c ) { pac_c = u3_Host.ops_u.puk_c; @@ -531,11 +531,11 @@ _pier_on_scry_done(void* ptr_v, u3_noun nun) pir_u->pax_c, pac_c+1, ext_c); u3_walk_save(fil_c, 0, out, pir_u->pax_c, pad); - u3l_log("pier: scry result in %s\n", fil_c); + u3l_log("pier: scry result in %s", fil_c); } } - u3l_log("pier: exit\n"); + u3l_log("pier: exit"); u3_pier_exit(pir_u); u3z(nun); @@ -614,7 +614,7 @@ _pier_work_init(u3_pier* pir_u) } else { // run the requested scry, jam to disk, then exit // - u3l_log("pier: scry\n"); + u3l_log("pier: scry"); u3_pier_peek_last(pir_u, u3_nul, u3k(car), u3k(dek), u3k(pax), pir_u, _pier_on_scry_done); } @@ -663,7 +663,7 @@ _pier_wyrd_fail(u3_pier* pir_u, u3_ovum* egg_u, u3_noun lud) { // XX version negotiation failed, print upgrade message // - u3l_log("pier: version negotation failed\n\n"); + u3l_log("pier: version negotation failed"); // XX only print trace with -v ? // @@ -749,7 +749,7 @@ _pier_on_lord_wyrd_done(void* ptr_v, // XX messaging, cli argument to bypass // - u3l_log("pier: version negotiation failed; downgrade\n"); + u3l_log("pier: version negotiation failed; downgrade"); _pier_wyrd_fail(pir_u, egg_u, u3_nul); } else { @@ -842,7 +842,7 @@ _pier_wyrd_init(u3_pier* pir_u) pir_u->sat_e = u3_psat_wyrd; - u3l_log("vere: checking version compatibility\n"); + u3l_log("vere: checking version compatibility"); { u3_lord* god_u = pir_u->god_u; @@ -1031,11 +1031,11 @@ _pier_play(u3_play* pay_u) if ( god_u->eve_d == pay_u->eve_d ) { // XX should be play_cb // - u3l_log("---------------- playback complete ----------------\r\n"); + u3l_log("---------------- playback complete ----------------"); u3_term_stop_spinner(); if ( pay_u->eve_d < log_u->dun_d ) { - // u3l_log("pier: replay barrier reached, shutting down\r\n"); + // u3l_log("pier: replay barrier reached, shutting down"); // // XX graceful shutdown // // // u3_lord_save(pir_u->god_u); @@ -1044,7 +1044,7 @@ _pier_play(u3_play* pay_u) // XX temporary hack // - u3l_log("pier: replay barrier reached, cramming\r\n"); + u3l_log("pier: replay barrier reached, cramming"); u3_pier_cram(pir_u); } else if ( pay_u->eve_d == log_u->dun_d ) { @@ -1070,12 +1070,12 @@ _pier_on_lord_play_done(void* ptr_v, u3_info fon_u, c3_l mug_l) c3_assert( u3_psat_play == pir_u->sat_e ); - u3l_log("pier: (%" PRIu64 "): play: done\r\n", tac_u->eve_d); + u3l_log("pier: (%" PRIu64 "): play: done", tac_u->eve_d); // XX optional // if ( tac_u->mug_l && (tac_u->mug_l != mug_l) ) { - u3l_log("pier: (%" PRIu64 "): play: mug mismatch %x %x\r\n", + u3l_log("pier: (%" PRIu64 "): play: mug mismatch %x %x", tac_u->eve_d, tac_u->mug_l, mug_l); @@ -1124,7 +1124,7 @@ _pier_on_lord_play_bail(void* ptr_v, u3_info fon_u, // XX optional // if ( las_l && (las_l != mug_l) ) { - u3l_log("pier: (%" PRIu64 "): play bail: mug mismatch %x %x\r\n", + u3l_log("pier: (%" PRIu64 "): play bail: mug mismatch %x %x", (c3_d)(eve_d - 1ULL), las_l, mug_l); @@ -1135,7 +1135,7 @@ _pier_on_lord_play_bail(void* ptr_v, u3_info fon_u, // #if 0 { - u3l_log("pier: (%" PRIu64 "): play: retry\r\n", eve_d); + u3l_log("pier: (%" PRIu64 "): play: retry", eve_d); fon_u.ext_u = tac_u; @@ -1156,7 +1156,7 @@ _pier_on_lord_play_bail(void* ptr_v, u3_info fon_u, } #else { - u3l_log("pier: (%" PRIu64 "): play: bail\r\n", eve_d); + u3l_log("pier: (%" PRIu64 "): play: bail", eve_d); u3_pier_punt_goof("play", dud); { u3_noun wir, tag; @@ -1192,12 +1192,12 @@ _pier_play_init(u3_pier* pir_u, c3_d eve_d) pay_u->eve_d = eve_d; pay_u->sen_d = god_u->eve_d; - u3l_log("---------------- playback starting ----------------\r\n"); + u3l_log("---------------- playback starting ----------------"); if ( (1ULL + god_u->eve_d) == eve_d ) { - u3l_log("pier: replaying event %" PRIu64 "\r\n", eve_d); + u3l_log("pier: replaying event %" PRIu64, eve_d); } else { - u3l_log("pier: replaying events %" PRIu64 "-%" PRIu64 "\r\n", + u3l_log("pier: replaying events %" PRIu64 "-%" PRIu64, (c3_d)(1ULL + god_u->eve_d), eve_d); } @@ -1326,7 +1326,7 @@ _pier_on_lord_cram(void* ptr_v) // XX temporary hack // if ( u3_psat_play == pir_u->sat_e ) { - u3l_log("pier: cram complete, shutting down\r\n"); + u3l_log("pier: cram complete, shutting down"); u3_pier_bail(pir_u); exit(0); } @@ -1355,7 +1355,7 @@ _pier_on_lord_exit(void* ptr_v) pir_u->god_u = 0; if ( u3_psat_done != pir_u->sat_e ) { - u3l_log("pier: serf shutdown unexpected\r\n"); + u3l_log("pier: serf shutdown unexpected"); u3_pier_bail(pir_u); } // if we made it all the way here, it's our jab to wrap up @@ -1416,10 +1416,10 @@ _pier_on_lord_live(void* ptr_v) // if ( u3_Host.ops_u.til_c ) { if ( 1 == sscanf(u3_Host.ops_u.til_c, "%" PRIu64 "", &eve_d) ) { - u3l_log("pier: replay till %" PRIu64 "\r\n", eve_d); + u3l_log("pier: replay till %" PRIu64, eve_d); } else { - u3l_log("pier: ignoring invalid replay barrier '%s'\r\n", + u3l_log("pier: ignoring invalid replay barrier '%s'", u3_Host.ops_u.til_c); eve_d = log_u->dun_d; } @@ -1443,51 +1443,51 @@ u3_pier_info(u3_pier* pir_u) { switch ( pir_u->sat_e ) { default: { - u3l_log("pier: unknown state: %u\r\n", pir_u->sat_e); + u3l_log("pier: unknown state: %u", pir_u->sat_e); } break; case u3_psat_init: { - u3l_log("pier: init\n"); + u3l_log("pier: init"); } break; case u3_psat_boot: { - u3l_log("pier: boot\n"); + u3l_log("pier: boot"); } break; case u3_psat_play: { - u3l_log("pier: play\n"); + u3l_log("pier: play"); { u3_play* pay_u = pir_u->pay_u; - u3l_log(" target: %" PRIu64 "\n", pay_u->eve_d); - u3l_log(" sent: %" PRIu64 "\n", pay_u->sen_d); - u3l_log(" read: %" PRIu64 "\n", pay_u->req_d); + u3l_log(" target: %" PRIu64, pay_u->eve_d); + u3l_log(" sent: %" PRIu64, pay_u->sen_d); + u3l_log(" read: %" PRIu64, pay_u->req_d); } } break; case u3_psat_work: { - u3l_log("pier: work\n"); + u3l_log("pier: work"); { u3_work* wok_u = pir_u->wok_u; - u3l_log(" effects: released=%" PRIu64 "\n", wok_u->fec_u.rel_d); + u3l_log(" effects: released=%" PRIu64, wok_u->fec_u.rel_d); if ( wok_u->fec_u.ext_u ) { if ( wok_u->fec_u.ext_u != wok_u->fec_u.ent_u ) { - u3l_log(" pending %" PRIu64 "-%" PRIu64 "\n", + u3l_log(" pending %" PRIu64 "-%" PRIu64, wok_u->fec_u.ext_u->eve_d, wok_u->fec_u.ent_u->eve_d); } else { - u3l_log(" pending %" PRIu64 "\n", wok_u->fec_u.ext_u->eve_d); + u3l_log(" pending %" PRIu64, wok_u->fec_u.ext_u->eve_d); } } if ( wok_u->wal_u ) { - u3l_log(" wall: %" PRIu64 "\n", wok_u->wal_u->eve_d); + u3l_log(" wall: %" PRIu64, wok_u->wal_u->eve_d); } if ( wok_u->car_u ) { @@ -1497,7 +1497,7 @@ u3_pier_info(u3_pier* pir_u) } break; case u3_psat_done: { - u3l_log("pier: done\n"); + u3l_log("pier: done"); } break; } @@ -1611,7 +1611,7 @@ u3_pier_stay(c3_w wag_w, u3_noun pax) if ( c3y == u3_Host.ops_u.veb ) { FILE* fil_u = u3_term_io_hija(); u3_lmdb_stat(pir_u->log_u->mdb_u, fil_u); - u3_term_io_loja(1); + u3_term_io_loja(1, fil_u); } u3z(pax); @@ -2221,10 +2221,12 @@ _pier_dump_wall(FILE* fil_u, u3_noun wol) while ( u3_nul != wal ) { _pier_dump_tape(fil_u, u3k(u3h(wal))); - putc(13, fil_u); - putc(10, fil_u); - wal = u3t(wal); + + if ( u3_nul != wal ) { + putc(13, fil_u); + putc(10, fil_u); + } } u3z(wol); @@ -2250,6 +2252,7 @@ u3_pier_tank(c3_l tab_l, c3_w pri_w, u3_noun tac) case 3: fprintf(fil_u, "\033[31m>>> "); break; case 2: fprintf(fil_u, "\033[33m>> "); break; case 1: fprintf(fil_u, "\033[32m> "); break; + case 0: fprintf(fil_u, "\033[90m" ); break; } } else { @@ -2266,8 +2269,6 @@ u3_pier_tank(c3_l tab_l, c3_w pri_w, u3_noun tac) if ( 0 == u3A->roc ) { if ( c3__leaf == u3h(tac) ) { _pier_dump_tape(fil_u, u3k(u3t(tac))); - putc(13, fil_u); - putc(10, fil_u); } } // We are calling nock here, but hopefully need no protection. @@ -2284,7 +2285,7 @@ u3_pier_tank(c3_l tab_l, c3_w pri_w, u3_noun tac) fflush(fil_u); - u3_term_io_loja(0); + u3_term_io_loja(0, fil_u); u3z(blu); u3z(tac); } @@ -2314,12 +2315,12 @@ u3_pier_punt_goof(const c3_c* cap_c, u3_noun dud) u3x_cell(dud, &mot, &tan); - u3l_log("\n"); + u3l_log(""); u3_pier_punt(0, u3qb_flop(tan)); { c3_c* mot_c = u3r_string(mot); - u3l_log("%s: bail: %%%s\r\n", cap_c, mot_c); + u3l_log("%s: bail: %%%s", cap_c, mot_c); c3_free(mot_c); } @@ -2335,7 +2336,7 @@ u3_pier_punt_ovum(const c3_c* cap_c, u3_noun wir, u3_noun tag) u3_noun riw = u3do("spat", wir); c3_c* wir_c = u3r_string(riw); - u3l_log("%s: %%%s event on %s failed\r\n\n", cap_c, tag_c, wir_c); + u3l_log("%s: %%%s event on %s failed", cap_c, tag_c, wir_c); c3_free(tag_c); c3_free(wir_c); diff --git a/pkg/urbit/vere/save.c b/pkg/urbit/vere/save.c index b2fc5b390..956d750cc 100644 --- a/pkg/urbit/vere/save.c +++ b/pkg/urbit/vere/save.c @@ -25,7 +25,7 @@ u3_save_ef_chld(u3_pier *pir_u) /* modified for cases with no pid_w */ - u3l_log("checkpoint: complete %d\n", sav_u->pid_w); + u3l_log("checkpoint: complete %d", sav_u->pid_w); pid_w = wait(&loc_i); if (0 != sav_u->pid_w) { c3_assert(pid_w == sav_u->pid_w); diff --git a/pkg/urbit/vere/walk.c b/pkg/urbit/vere/walk.c index 5c113cbac..3e0bb4a8c 100644 --- a/pkg/urbit/vere/walk.c +++ b/pkg/urbit/vere/walk.c @@ -37,7 +37,7 @@ u3_walk_safe(c3_c* pas_c) c3_y* pad_y; if ( (fid_i < 0) || (fstat(fid_i, &buf_b) < 0) ) { - // u3l_log("%s: %s\n", pas_c, strerror(errno)); + // u3l_log("%s: %s", pas_c, strerror(errno)); return 0; } fln_w = buf_b.st_size; @@ -69,7 +69,7 @@ u3_walk_load(c3_c* pas_c) c3_y* pad_y; if ( (fid_i < 0) || (fstat(fid_i, &buf_b) < 0) ) { - u3l_log("%s: %s\n", pas_c, strerror(errno)); + u3l_log("%s: %s", pas_c, strerror(errno)); return u3m_bail(c3__fail); } fln_w = buf_b.st_size; @@ -117,7 +117,7 @@ _walk_mkdirp(c3_c* bas_c, u3_noun pax) pax_c[len_w] = '\0'; if ( 0 != mkdir(pax_c, 0755) && EEXIST != errno ) { - u3l_log("error mkdiring %s: %s\n", pax_c, strerror(errno)); + u3l_log("error mkdiring %s: %s", pax_c, strerror(errno)); u3m_bail(c3__fail); } @@ -140,7 +140,7 @@ u3_walk_save(c3_c* pas_c, u3_noun tim, u3_atom pad, c3_c* bas_c, u3_noun pax) return u3_walk_save(pas_c, tim, pad, 0, u3_nul); } - u3l_log("%s: %s\n", pas_c, strerror(errno)); + u3l_log("%s: %s", pas_c, strerror(errno)); u3m_bail(c3__fail); } @@ -155,7 +155,7 @@ u3_walk_save(c3_c* pas_c, u3_noun tim, u3_atom pad, c3_c* bas_c, u3_noun pax) c3_free(pad_y); if ( rit_w != fln_w ) { - u3l_log("%s: %s\n", pas_c, strerror(errno)); + u3l_log("%s: %s", pas_c, strerror(errno)); u3m_bail(c3__fail); } @@ -185,7 +185,7 @@ _walk_in(const c3_c* dir_c, c3_w len_w) struct dirent* out_n; if ( u3_readdir_r(dir_d, &ent_n, &out_n) != 0 ) { - u3l_log("%s: %s\n", dir_c, strerror(errno)); + u3l_log("%s: %s", dir_c, strerror(errno)); break; } else if ( !out_n ) { @@ -267,7 +267,7 @@ u3_walk(const c3_c* dir_c, u3_noun old) struct stat buf_b; if ( 0 != stat(dir_c, &buf_b) ) { - u3l_log("can't stat %s\n", dir_c); + u3l_log("can't stat %s", dir_c); // return u3m_bail(c3__fail); c3_assert(0); } diff --git a/pkg/urbit/worker/serf.c b/pkg/urbit/worker/serf.c index 79fab1fc6..c8e3e6e51 100644 --- a/pkg/urbit/worker/serf.c +++ b/pkg/urbit/worker/serf.c @@ -244,7 +244,7 @@ _serf_grab(u3_serf* sef_u) u3z(sef_u->sac); sef_u->sac = u3_nul; - u3l_log("\n"); + u3l_log(""); } } @@ -282,7 +282,7 @@ u3_serf_post(u3_serf* sef_u) if ( c3y == sef_u->pac_o ) { u3a_print_memory(stderr, "serf: pack: gained", u3m_pack()); - u3l_log("\n"); + u3l_log(""); sef_u->pac_o = c3n; } } @@ -464,7 +464,7 @@ _serf_poke(u3_serf* sef_u, c3_c* cap_c, c3_w mil_w, u3_noun job) if ( (c3__belt != tag) && (c3__crud != tag) ) { - u3l_log("serf: %s (%" PRIu64 ") %s\r\n", cap_c, sef_u->sen_d, txt_c); + u3l_log("serf: %s (%" PRIu64 ") %s", cap_c, sef_u->sen_d, txt_c); } } #endif @@ -484,7 +484,7 @@ _serf_poke(u3_serf* sef_u, c3_c* cap_c, c3_w mil_w, u3_noun job) clr_w = ms_w > 1000 ? 1 : ms_w < 100 ? 2 : 3; // red, green, yellow if ( clr_w != 2 ) { - u3l_log("\x1b[3%dm%%%s (%" PRIu64 ") %4d.%02dms\x1b[0m\n", + u3l_log("\x1b[3%dm%%%s (%" PRIu64 ") %4d.%02dms\x1b[0m", clr_w, txt_c, sef_u->sen_d, ms_w, (int) (d0.tv_usec % 1000) / 10); } @@ -523,7 +523,7 @@ _serf_work(u3_serf* sef_u, c3_w mil_w, u3_noun job) // if ( u3_blip == u3h(gon) ) { u3_noun vir = _serf_sure(sef_u, pre_w, u3k(u3t(gon))); - + u3z(gon); u3z(job); return u3nc(c3__done, u3nt(u3i_chubs(1, &sef_u->dun_d), sef_u->mug_l, @@ -901,7 +901,7 @@ u3_serf_live(u3_serf* sef_u, u3_noun com, u3_noun* ret) return c3n; } - u3l_log("serf (%" PRIu64 "): saving rock\r\n", sef_u->dun_d); + u3l_log("serf (%" PRIu64 "): saving rock", sef_u->dun_d); if ( c3n == u3u_cram(sef_u->dir_c, eve_d) ) { fprintf(stderr, "serf (%" PRIu64 "): unable to jam state\r\n", eve_d); @@ -1045,7 +1045,7 @@ u3_serf_writ(u3_serf* sef_u, u3_noun wit, u3_noun* pel) static u3_noun _serf_ripe(u3_serf* sef_u) { - // u3l_log("serf: ripe %" PRIu64 "\r\n", sef_u->dun_d); + // u3l_log("serf: ripe %" PRIu64, sef_u->dun_d); sef_u->mug_l = ( 0 == sef_u->dun_d ) ? 0 From 71c7d315a9518a1735777d524cebd15688b3dfa5 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 25 Oct 2021 16:20:34 +0200 Subject: [PATCH 002/715] gen: add |new-desk for creating minimal desks Includes the bare minimum of necessary files. --- pkg/arvo/gen/hood/new-desk.hoon | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 pkg/arvo/gen/hood/new-desk.hoon diff --git a/pkg/arvo/gen/hood/new-desk.hoon b/pkg/arvo/gen/hood/new-desk.hoon new file mode 100644 index 000000000..627e8fd69 --- /dev/null +++ b/pkg/arvo/gen/hood/new-desk.hoon @@ -0,0 +1,35 @@ +:: |new-desk: creates a minimal desk +:: +:- %say +|= $: [now=@da eny=@uvJ bek=beak] + [=desk ~] + from=$~(%base desk) + == +:: +?: (~(has in .^((set ^desk) %cd (en-beam bek(q from) /))) desk) + ~| [%already-exists desk] + !! +:: +=+ .^(=dome:clay %cv (en-beam bek /)) +:: +:- %helm-pass +%^ new-desk:cloy desk + ~ +%- ~(gas by *(map path page:clay)) +|^ =- (turn - mage) + ^- (list path) + :~ /mar/noun/hoon + /mar/hoon/hoon + /mar/kelvin/hoon + /sys/kelvin + == +:: +++ mage + |= =path + :- path + ^- page:clay + =; =cage [p q.q]:cage + ~| [%missing-source-file from path] + (need (~(get an:cloy ank.dome) path)) +-- + From beebc5fe0ef8efca6ea6f68420825d43559ce138 Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 29 Oct 2021 11:28:19 +0200 Subject: [PATCH 003/715] gen: |new-desk -> |make-desk --- pkg/arvo/gen/hood/{new-desk.hoon => make-desk.hoon} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pkg/arvo/gen/hood/{new-desk.hoon => make-desk.hoon} (100%) diff --git a/pkg/arvo/gen/hood/new-desk.hoon b/pkg/arvo/gen/hood/make-desk.hoon similarity index 100% rename from pkg/arvo/gen/hood/new-desk.hoon rename to pkg/arvo/gen/hood/make-desk.hoon From 3ad84e3afd7c28ffe8fe3ba25598f022883e85db Mon Sep 17 00:00:00 2001 From: fang Date: Tue, 4 Jan 2022 15:58:37 +0100 Subject: [PATCH 004/715] make-desk: include /mar/txt --- pkg/arvo/gen/hood/make-desk.hoon | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/arvo/gen/hood/make-desk.hoon b/pkg/arvo/gen/hood/make-desk.hoon index 627e8fd69..ecb2e1f09 100644 --- a/pkg/arvo/gen/hood/make-desk.hoon +++ b/pkg/arvo/gen/hood/make-desk.hoon @@ -20,6 +20,7 @@ ^- (list path) :~ /mar/noun/hoon /mar/hoon/hoon + /mar/txt/hoon /mar/kelvin/hoon /sys/kelvin == From bbb1a716bf0d0c0111ed0b02073e9e82063adcdc Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 16 Feb 2022 01:04:08 +0100 Subject: [PATCH 005/715] ph: link missing lib Must've gotten lost during merge or something. --- pkg/arvo/lib/ph/util.hoon | 1 + 1 file changed, 1 insertion(+) create mode 120000 pkg/arvo/lib/ph/util.hoon diff --git a/pkg/arvo/lib/ph/util.hoon b/pkg/arvo/lib/ph/util.hoon new file mode 120000 index 000000000..ec423efc0 --- /dev/null +++ b/pkg/arvo/lib/ph/util.hoon @@ -0,0 +1 @@ +../../../base-dev/lib/ph/util.hoon \ No newline at end of file From c4f38032cec2418f7792f6d15bdeec8a124a352b Mon Sep 17 00:00:00 2001 From: fang Date: Sun, 20 Feb 2022 15:35:55 -0600 Subject: [PATCH 006/715] pkg: move /lib/dill into base-dev, include it Landscape desk needed it, but didn't have it. --- pkg/arvo/lib/dill.hoon | 94 +------------------------------------ pkg/base-dev/lib/dill.hoon | 93 ++++++++++++++++++++++++++++++++++++ pkg/landscape/lib/dill.hoon | 1 + 3 files changed, 95 insertions(+), 93 deletions(-) mode change 100644 => 120000 pkg/arvo/lib/dill.hoon create mode 100644 pkg/base-dev/lib/dill.hoon create mode 120000 pkg/landscape/lib/dill.hoon diff --git a/pkg/arvo/lib/dill.hoon b/pkg/arvo/lib/dill.hoon deleted file mode 100644 index d4cecdf14..000000000 --- a/pkg/arvo/lib/dill.hoon +++ /dev/null @@ -1,93 +0,0 @@ -:: dill: utilities for dill's data structures -:: -=, dill -|% -++ enjs - |% - ++ blit - |= =blit:dill - ^- json - =, enjs:format - %+ frond -.blit - ?- -.blit - %bel b+& - %clr b+& - %hop ?@ p.blit (numb p.blit) - (pairs 'r'^(numb r.p.blit) 'c'^(numb c.p.blit) ~) - %put a+(turn p.blit |=(c=@c s+(tuft c))) - %nel b+& - %url s+p.blit - %wyp b+& - :: - %sag - %- pairs - :~ 'path'^(path p.blit) - 'file'^s+(en:base64:mimes:html (as-octs:mimes:html (jam q.blit))) - == - :: - %sav - %- pairs - :~ 'path'^(path p.blit) - 'file'^s+(en:base64:mimes:html (as-octs:mimes:html q.blit)) - == - :: - %klr - :- %a - %+ turn p.blit - |= [=stye text=(list @c)] - %- pairs - :~ 'text'^a+(turn text |=(c=@c s+(tuft c))) - :: - :- 'stye' - %- pairs - |^ :~ 'back'^(color p.q.stye) - 'fore'^(color q.q.stye) - 'deco'^a+(turn ~(tap in p.stye) |=(d=deco ?~(d ~ s+d))) - == - ++ color - |= =tint - ?@ tint ?~(tint ~ s+tint) - =, tint - (pairs r+(numb r) g+(numb g) b+(numb b) ~) - -- - == - == - -- -:: -++ dejs - |% - ++ belt - |= jon=json - ^- belt:dill - ?: ?=([%s *] jon) - (taft p.jon) - =, dejs:format - %. jon - %- of - |^ :* mod+(ot 'mod'^mod 'key'^bot ~) - txt+(ar (cu taft so)) - bol - == - :: - ++ bol - :~ aro+(su (perk %d %l %r %u ~)) - bac+ul - del+ul - hit+(ot 'r'^ni 'c'^ni ~) - ret+ul - == - :: - ++ bot - |= j=json - ^- bolt:dill - ?+ j !! - [%s *] (taft p.j) - [%o *] ((of bol) j) - == - :: - ++ mod - |= j=json - ((su (perk %ctl %met %hyp ~)) j) - -- - -- --- \ No newline at end of file diff --git a/pkg/arvo/lib/dill.hoon b/pkg/arvo/lib/dill.hoon new file mode 120000 index 000000000..f9c2362f0 --- /dev/null +++ b/pkg/arvo/lib/dill.hoon @@ -0,0 +1 @@ +../../base-dev/lib/dill.hoon \ No newline at end of file diff --git a/pkg/base-dev/lib/dill.hoon b/pkg/base-dev/lib/dill.hoon new file mode 100644 index 000000000..d4cecdf14 --- /dev/null +++ b/pkg/base-dev/lib/dill.hoon @@ -0,0 +1,93 @@ +:: dill: utilities for dill's data structures +:: +=, dill +|% +++ enjs + |% + ++ blit + |= =blit:dill + ^- json + =, enjs:format + %+ frond -.blit + ?- -.blit + %bel b+& + %clr b+& + %hop ?@ p.blit (numb p.blit) + (pairs 'r'^(numb r.p.blit) 'c'^(numb c.p.blit) ~) + %put a+(turn p.blit |=(c=@c s+(tuft c))) + %nel b+& + %url s+p.blit + %wyp b+& + :: + %sag + %- pairs + :~ 'path'^(path p.blit) + 'file'^s+(en:base64:mimes:html (as-octs:mimes:html (jam q.blit))) + == + :: + %sav + %- pairs + :~ 'path'^(path p.blit) + 'file'^s+(en:base64:mimes:html (as-octs:mimes:html q.blit)) + == + :: + %klr + :- %a + %+ turn p.blit + |= [=stye text=(list @c)] + %- pairs + :~ 'text'^a+(turn text |=(c=@c s+(tuft c))) + :: + :- 'stye' + %- pairs + |^ :~ 'back'^(color p.q.stye) + 'fore'^(color q.q.stye) + 'deco'^a+(turn ~(tap in p.stye) |=(d=deco ?~(d ~ s+d))) + == + ++ color + |= =tint + ?@ tint ?~(tint ~ s+tint) + =, tint + (pairs r+(numb r) g+(numb g) b+(numb b) ~) + -- + == + == + -- +:: +++ dejs + |% + ++ belt + |= jon=json + ^- belt:dill + ?: ?=([%s *] jon) + (taft p.jon) + =, dejs:format + %. jon + %- of + |^ :* mod+(ot 'mod'^mod 'key'^bot ~) + txt+(ar (cu taft so)) + bol + == + :: + ++ bol + :~ aro+(su (perk %d %l %r %u ~)) + bac+ul + del+ul + hit+(ot 'r'^ni 'c'^ni ~) + ret+ul + == + :: + ++ bot + |= j=json + ^- bolt:dill + ?+ j !! + [%s *] (taft p.j) + [%o *] ((of bol) j) + == + :: + ++ mod + |= j=json + ((su (perk %ctl %met %hyp ~)) j) + -- + -- +-- \ No newline at end of file diff --git a/pkg/landscape/lib/dill.hoon b/pkg/landscape/lib/dill.hoon new file mode 120000 index 000000000..f9c2362f0 --- /dev/null +++ b/pkg/landscape/lib/dill.hoon @@ -0,0 +1 @@ +../../base-dev/lib/dill.hoon \ No newline at end of file From 3120681b2bd5abc59645dbee6b4fac01cd55ce4d Mon Sep 17 00:00:00 2001 From: fang Date: Sun, 20 Feb 2022 15:53:53 -0600 Subject: [PATCH 007/715] sole: properly support multiple sessions We update the sole protocol to more cleanly support multiple sessions. Primarily, the "sole id" is updated to be a [@p @ta] instead of a @ta, and it is now generated based off the connected dill session, rather than statically. This change ripples out to applications that support the sole protocol: the subscription path becomes /sole/[ship]/[session] (as opposed to /sole/[per-ship-constant]), and %sole-action pokes include the new id as well. For shoe agents, this means (at the very least) updating the function signatures of the shoe arms. /lib/sole has been updated to include helper functions for parsing a sole-id from a subscription path, and turning a sole-id into its corresponding path. It also has a function to aid in migrating old sole-ids. Existing sole agents are made to kick any known open sessions, forcing a resubscribe by drum, so that they may use exclusively the new format going forward. Third-party agents are recommended to do the same. Note that some functionality, such as |link, still operates exclusively on the default session. Improvements in this area to follow soon. --- pkg/arvo/app/dojo.hoon | 61 ++++++++++++++++++------- pkg/arvo/app/shoe.hoon | 8 ++-- pkg/arvo/lib/hood/drum.hoon | 41 ++++++++++------- pkg/base-dev/lib/shoe.hoon | 81 +++++++++++++++++++++------------ pkg/base-dev/lib/sole.hoon | 24 ++++++++++ pkg/base-dev/sur/sole.hoon | 3 +- pkg/landscape/app/chat-cli.hoon | 55 ++++++++++++++++------ 7 files changed, 193 insertions(+), 80 deletions(-) diff --git a/pkg/arvo/app/dojo.hoon b/pkg/arvo/app/dojo.hoon index 938d9f25a..c8fbd49d7 100644 --- a/pkg/arvo/app/dojo.hoon +++ b/pkg/arvo/app/dojo.hoon @@ -10,9 +10,9 @@ :::: :: :::: :: :: :: => |% :: external structures - +$ id @tasession :: session id + +$ id sole-id :: session id +$ house :: all state - $: %8 + $: %9 egg=@u :: command count hoc=(map id session) :: conversations acl=(set ship) :: remote access whitelist @@ -1019,13 +1019,14 @@ |= =card:agent:gall ^+ +> =? card ?=(%pass -.card) - card(p [id p.card]) + ^- card:agent:gall + card(p [(scot %p who.id) ses.id p.card]) %_(+> moz [card moz]) :: ++ he-diff :: emit update |= fec=sole-effect ^+ +> - (he-card %give %fact ~[/sole/[id]] %sole-effect !>(fec)) + (he-card %give %fact ~[(id-to-path:sole id)] %sole-effect !>(fec)) :: ++ he-stop :: abort work ^+ . @@ -1533,21 +1534,47 @@ :: ++ on-load |= ole=vase + ^- (quip card:agent:gall _..on-init) |^ =+ old=!<(house-any ole) =? old ?=(%5 -.old) + ^- house-any + ^- house-6 (house-5-to-6 old) =? old ?=(?(%6 %7) -.old) (house-6-7-to-8 +.old) - ?> ?=(%8 -.old) - `..on-init(state old) + =^ caz old + ?. ?=(%8 -.old) [~ old] + (house-8-to-9 old) + ?> ?=(%9 -.old) + [caz ..on-init(state old)] :: - +$ house-any $%(house house-7 house-6 house-5) + +$ house-any $%(house house-8 house-7 house-6 house-5) + :: + +$ id-8 @tasession + +$ house-8 + $: %8 + egg=@u + hoc=(map id-8 session) + acl=(set ship) + == + ++ house-8-to-9 + |= old=house-8 + ^- (quip card:agent:gall house) + :- %+ turn ~(tap in ~(key by hoc.old)) + |= id=@ta + ^- card:agent:gall + [%give %kick ~[/sole/[id]] ~] + =- [%9 egg.old - acl.old] + %- ~(gas by *(map sole-id session)) + %+ murn ~(tap by hoc.old) + |= [id=@ta s=session] + (bind (upgrade-id:sole id) (late s)) :: +$ house-7 [%7 house-6-7] +$ house-6 [%6 house-6-7] +$ house-6-7 $: egg=@u :: command count - hoc=(map id session-6) :: conversations + hoc=(map id-8 session-6) :: conversations acl=(set ship) :: remote access whitelist == :: +$ session-6 :: per conversation @@ -1574,9 +1601,10 @@ old(poy ~, -.dir [our.hid %base ud+0]) :: +$ house-5 - [%5 egg=@u hoc=(map id session)] + [%5 egg=@u hoc=(map id-8 session-6)] ++ house-5-to-6 |= old=house-5 + ^- house-6 [%6 egg.old hoc.old *(set ship)] -- :: @@ -1630,8 +1658,7 @@ ?> ?| (team:title our.hid src.hid) (~(has in acl) src.hid) == - ?> ?=([%sole @ ~] path) - =/ id i.t.path + =/ =id (need (path-to-id:sole path)) =? hoc (~(has by hoc) id) ~& [%dojo-peer-replaced id] (~(del by hoc) id) @@ -1643,7 +1670,7 @@ ++ on-leave |= =path ?> ?=([%sole *] path) - =. hoc (~(del by hoc) t.path) + =. hoc (~(del by hoc) (need (path-to-id:sole path))) [~ ..on-init] :: ++ on-peek @@ -1652,13 +1679,15 @@ :: ++ on-agent |= [=wire =sign:agent:gall] - ?> ?=([@ @ *] wire) - =/ =session (~(got by hoc) i.wire) - =/ he-full ~(. he hid i.wire ~ session) + ^- (quip card:agent:gall _..on-init) + ?> ?=([@ @ @ *] wire) + =/ =id [(slav %p i.wire) i.t.wire] + =/ =session (~(got by hoc) id) + =/ he-full ~(. he hid id ~ session) =^ moves state =< he-abet ^+ he - ?+ i.t.wire ~|([%dojo-bad-on-agent wire -.sign] !!) + ?+ i.t.t.wire ~|([%dojo-bad-on-agent wire -.sign] !!) %poke (he-unto:he-full t.wire sign) %wool (he-wool:he-full t.wire sign) == diff --git a/pkg/arvo/app/shoe.hoon b/pkg/arvo/app/shoe.hoon index 4b0538ad3..0e827f57c 100644 --- a/pkg/arvo/app/shoe.hoon +++ b/pkg/arvo/app/shoe.hoon @@ -43,13 +43,13 @@ ++ on-fail on-fail:def :: ++ command-parser - |= sole-id=@ta + |= =sole-id:shoe ^+ |~(nail *(like [? command])) %+ stag & (perk %demo %row %table ~) :: ++ tab-list - |= sole-id=@ta + |= =sole-id:shoe ^- (list [@t tank]) :~ ['demo' leaf+"run example command"] ['row' leaf+"print a row"] @@ -57,7 +57,7 @@ == :: ++ on-command - |= [sole-id=@ta =command] + |= [=sole-id:shoe =command] ^- (quip card _this) =; [to=(list _sole-id) fec=shoe-effect:shoe] [[%shoe to fec]~ this] @@ -87,7 +87,7 @@ == :: ++ can-connect - |= sole-id=@ta + |= =sole-id:shoe ^- ? ?| =(~zod src.bowl) (team:title [our src]:bowl) diff --git a/pkg/arvo/lib/hood/drum.hoon b/pkg/arvo/lib/hood/drum.hoon index c50f5a818..67abf801a 100644 --- a/pkg/arvo/lib/hood/drum.hoon +++ b/pkg/arvo/lib/hood/drum.hoon @@ -105,14 +105,15 @@ :: :: :: |% ++ en-gill :: gill to wire - |= gyl=gill:gall + |= [ses=@tas gyl=gill:gall] ^- wire - ::TODO include session? - [%drum %phat (scot %p p.gyl) q.gyl ~] + [%drum %phat (scot %p p.gyl) q.gyl ?:(=(%$ ses) ~ [ses ~])] :: ++ de-gill :: gill from wire - |= way=wire ^- gill:gall - ?>(?=([@ @ ~] way) [(slav %p i.way) i.t.way]) + |= way=wire ^- [@tas gill:gall] + ?> ?=([@ @ ?(~ [@ ~])] way) + :- ?~(t.t.way %$ i.t.t.way) + [(slav %p i.way) i.t.way] -- :: |= [hid=bowl:gall state] @@ -135,10 +136,15 @@ =. dev (~(gut by bin) ses *source) this :: +++ open + %+ cork de-gill + |= [s=@tas g=gill:gall] + [g (prep s)] +:: ++ diff-sole-effect-phat :: app event |= [way=wire fec=sole-effect] =< se-abet =< se-view - =+ gyl=(de-gill way) + =^ gyl this (open way) ?: (se-aint gyl) +>.$ (se-diff gyl fec) :: @@ -228,7 +234,7 @@ ++ reap-phat :: ack connect |= [way=wire saw=(unit tang)] =< se-abet =< se-view - =+ gyl=(de-gill way) + =^ gyl this (open way) ?~ saw (se-join gyl) :: Don't print stack trace because we probably just crashed to @@ -240,7 +246,7 @@ |= [way=wire saw=(unit tang)] =< se-abet =< se-view ?~ saw +> - =+ gyl=(de-gill way) + =^ gyl this (open way) ?: (se-aint gyl) +>.$ %- se-dump:(se-drop:(se-pull gyl) & gyl) :_ u.saw @@ -264,7 +270,7 @@ ++ quit-phat :: |= way=wire =< se-abet =< se-view - =+ gyl=(de-gill way) + =^ gyl this (open way) ~& [%drum-quit src.hid gyl] (se-drop %| gyl) :: :: :: @@ -279,7 +285,11 @@ :_ (flop moz) =/ =dill-blit:dill ?~(t.biz i.biz [%mor (flop biz)]) ::TODO remove /drum after dill cleans up - [%give %fact ~[/drum /dill/[ses]] %dill-blit !>(dill-blit)] + ::TODO but once we remove it, the empty trailing segment of + :: /dill/[ses] would prevent outsiders from subscribing + :: to the default session... + =/ to=(list path) [/dill/[ses] ?~(ses ~[/drum] ~)] + [%give %fact to %dill-blit !>(dill-blit)] :: ++ se-adze :: update connections ^+ . @@ -518,19 +528,18 @@ :: ++ se-poke :: send a poke |= [gyl=gill:gall par=cage] - (se-emit %pass (en-gill gyl) %agent gyl %poke par) + (se-emit %pass (en-gill ses gyl) %agent gyl %poke par) :: ++ se-peer :: send a peer |= gyl=gill:gall ~> %slog.0^leaf/"drum: link {<[p q]:gyl>}" - ::TODO include session - =/ =path /sole/(cat 3 'drum_' (scot %p our.hid)) + =/ =path (id-to-path:sole our.hid ses) %- se-emit(fug (~(put by fug) gyl ~)) - [%pass (en-gill gyl) %agent gyl %watch path] + [%pass (en-gill ses gyl) %agent gyl %watch path] :: ++ se-pull :: cancel subscription |= gyl=gill:gall - (se-emit %pass (en-gill gyl) %agent gyl %leave ~) + (se-emit %pass (en-gill ses gyl) %agent gyl %leave ~) :: ++ se-tame :: switch connection |= gyl=gill:gall @@ -555,7 +564,7 @@ ^+ +> (ta-poke %sole-action !>(act)) :: - ++ ta-id (cat 3 'drum_' (scot %p our.hid)) :: per-ship duct id + ++ ta-id [our.hid ses] :: per-ship-session id :: ++ ta-aro :: hear arrow |= key=?(%d %l %r %u) diff --git a/pkg/base-dev/lib/shoe.hoon b/pkg/base-dev/lib/shoe.hoon index cd4ab18db..856a4d782 100644 --- a/pkg/base-dev/lib/shoe.hoon +++ b/pkg/base-dev/lib/shoe.hoon @@ -13,15 +13,15 @@ /- *sole /+ sole, auto=language-server-complete |% -+$ state-0 - $: %0 - soles=(map @ta sole-share) ++$ state-1 + $: %1 + soles=(map sole-id sole-share) == :: $card: standard gall cards plus shoe effects :: +$ card $% card:agent:gall - [%shoe sole-ids=(list @ta) effect=shoe-effect] :: ~ sends to all soles + [%shoe sole-ids=(list sole-id) effect=shoe-effect] :: ~ sends to all == :: $shoe-effect: easier sole-effects :: @@ -47,30 +47,30 @@ :: if the head of the result is true, instantly run the command :: ++ command-parser - |~ sole-id=@ta + |~ =sole-id |~(nail *(like [? command-type])) :: +tab-list: autocomplete options for the session (to match +command-parser) :: ++ tab-list - |~ sole-id=@ta + |~ =sole-id :: (list [@t tank]) *(list (option:auto tank)) :: +on-command: called when a valid command is run :: ++ on-command - |~ [sole-id=@ta command=command-type] + |~ [=sole-id command=command-type] *(quip card _^|(..on-init)) :: ++ can-connect - |~ sole-id=@ta + |~ =sole-id *? :: ++ on-connect - |~ sole-id=@ta + |~ =sole-id *(quip card _^|(..on-init)) :: ++ on-disconnect - |~ sole-id=@ta + |~ =sole-id *(quip card _^|(..on-init)) :: ::NOTE standard gall agent arms below, though they may produce %shoe cards @@ -119,27 +119,27 @@ |* [shoe=* command-type=mold] |_ =bowl:gall ++ command-parser - |= sole-id=@ta + |= =sole-id (easy *[? command-type]) :: ++ tab-list - |= sole-id=@ta + |= =sole-id ~ :: ++ on-command - |= [sole-id=@ta command=command-type] + |= [=sole-id command=command-type] [~ shoe] :: ++ can-connect - |= sole-id=@ta + |= =sole-id (team:title [our src]:bowl) :: ++ on-connect - |= sole-id=@ta + |= =sole-id [~ shoe] :: ++ on-disconnect - |= sole-id=@ta + |= =sole-id [~ shoe] -- :: +agent: creates wrapper core that handles sole events and calls shoe arms @@ -147,7 +147,7 @@ ++ agent |* command-type=mold |= =(shoe command-type) - =| state-0 + =| state-1 =* state - ^- agent:gall => @@ -164,8 +164,7 @@ %+ turn ?^ sole-ids.card sole-ids.card ~(tap in ~(key by soles)) - |= sole-id=@ta - /sole/[sole-id] + id-to-path:sole :: %table =; fez=(list sole-effect) @@ -202,9 +201,36 @@ ?. ?=([%shoe-app ^] q.old-state) =^ cards shoe (on-load:og old-state) [(deal cards) this] - =^ old-inner state +:!<([%shoe-app vase state-0] old-state) - =^ cards shoe (on-load:og old-inner) - [(deal cards) this] + |^ =| old-outer=state-any + =^ old-inner old-outer + +:!<([%shoe-app vase state-any] old-state) + :: ~! q.old-state + :: ?+ +>.q.old-state !! + :: [%0 *] +:!<([%shoe-app vase state-0] old-state) + :: [%1 *] +:!<([%shoe-app vase state-1] old-state) + :: == + =^ caz shoe (on-load:og old-inner) + =^ cuz old-outer + ?. ?=(%0 -.old-outer) [~ old-outer] + (state-0-to-1 old-outer) + ?> ?=(%1 -.old-outer) + [(weld cuz (deal caz)) this(state old-outer)] + :: + +$ state-any $%(state-1 state-0) + +$ state-0 [%0 soles=(map @ta sole-share)] + ++ state-0-to-1 + |= old=state-0 + ^- (quip card:agent:gall state-1) + :- %+ turn ~(tap in ~(key by soles.old)) + |= id=@ta + ^- card:agent:gall + [%give %kick ~[/sole/[id]] ~] + :- %1 + %- ~(gas by *(map sole-id sole-share)) + %+ murn ~(tap by soles.old) + |= [id=@ta s=sole-share] + (bind (upgrade-id:sole id) (late s)) + -- :: ++ on-poke |= [=mark =vase] @@ -326,19 +352,18 @@ ++ on-watch |= =path ^- (quip card:agent:gall agent:gall) - ?. ?=([%sole @ ~] path) + ?~ sole-id=(path-to-id:sole path) =^ cards shoe (on-watch:og path) [(deal cards) this] - =* sole-id i.t.path - ?> (can-connect:og sole-id) - =. soles (~(put by soles) sole-id *sole-share) + ?> (can-connect:og u.sole-id) + =. soles (~(put by soles) u.sole-id *sole-share) =^ cards shoe - (on-connect:og sole-id) + (on-connect:og u.sole-id) :_ this %- deal :_ cards - [%shoe [sole-id]~ %sole %pro & dap.bowl "> "] + [%shoe [u.sole-id]~ %sole %pro & dap.bowl "> "] :: ++ on-leave |= =path diff --git a/pkg/base-dev/lib/sole.hoon b/pkg/base-dev/lib/sole.hoon index 66684668a..ad6b74962 100644 --- a/pkg/base-dev/lib/sole.hoon +++ b/pkg/base-dev/lib/sole.hoon @@ -136,4 +136,28 @@ =+ dat=(transmute [%mor leg] [%ins pos `@c`0]) ?> ?=(%ins -.dat) p.dat +:: +:: +++ path-to-id + |= =path + ^- (unit sole-id) + ?. ?=([%sole @ ?(~ [@ ~])] path) ~ + ?~ who=(slaw %p i.t.path) ~ + `[u.who ?~(t.t.path %$ i.t.t.path)] +:: +++ id-to-path + |= sole-id + ^- path + ::TODO this whole "no empty path ending" business feels icky. + :: do we want default session to be ~.~ ? + :: concern here is that outsiders cannot subscribe to the default + :: session, because /sole/~zod/ isn't a valid path... + [%sole (scot %p who) ?~(ses ~ /[ses])] +:: +++ upgrade-id + |= old=@ta + ^- (unit sole-id) + %+ rush old + %+ cook (late %$) + ;~(pfix (jest 'drum_~') fed:ag) -- diff --git a/pkg/base-dev/sur/sole.hoon b/pkg/base-dev/sur/sole.hoon index e942bccb8..f8141f701 100644 --- a/pkg/base-dev/sur/sole.hoon +++ b/pkg/base-dev/sur/sole.hoon @@ -3,8 +3,9 @@ :: ^? |% ++$ sole-id [who=@p ses=@ta] +$ sole-action :: sole to app - $: id=@ta :: duct id + $: id=sole-id :: session id $= dat $% :: [%abo ~] :: reset interaction [%det sole-change] :: command line edit diff --git a/pkg/landscape/app/chat-cli.hoon b/pkg/landscape/app/chat-cli.hoon index 4398cc7e8..a5aa5dee2 100644 --- a/pkg/landscape/app/chat-cli.hoon +++ b/pkg/landscape/app/chat-cli.hoon @@ -16,15 +16,15 @@ +$ card card:shoe :: +$ versioned-state - $% state-3 + $% state-4 + state-3 state-2 state-1 state-0 == :: -+$ state-3 - $: %3 - ::TODO support multiple sessions ++$ state-4 + $: %4 sessions=(map sole-id session) :: sole sessions bound=(map resource glyph) :: bound resource glyphs binds=(jug glyph resource) :: resource glyph lookup @@ -33,7 +33,17 @@ timez=(pair ? @ud) :: timezone adjustment == :: -+$ sole-id @ta ++$ state-3 + $: %3 + sessions=(map @ta session) + bound=(map resource glyph) + binds=(jug glyph resource) + settings=(set term) + width=@ud + timez=(pair ? @ud) + == +:: ++$ sole-id sole-id:shoe +$ session $: viewing=(set resource) :: connected graphs history=(list uid:post) :: scrollback pointers @@ -115,7 +125,7 @@ == :: :: -- -=| state-3 +=| state-4 =* state - :: %- agent:dbug @@ -258,14 +268,14 @@ settings width timez == :: - =^ cards u.old + =^ cards-1 u.old ?. ?=(%2 -.u.old) [~ u.old] :- :~ [%pass /chat-store %agent [our-self %chat-store] %leave ~] [%pass /invites %agent [our.bowl %invite-store] %leave ~] == ^- state-3 :- %3 - :* %+ ~(put in *(map sole-id session)) + :* %+ ~(put in *(map @ta session)) (cat 3 'drum_' (scot %p our.bowl)) :* ~ ~ 0 :: @@ -290,14 +300,29 @@ timez.u.old == :: - ?> ?=(%3 -.u.old) + =^ cards-2 u.old + ?. ?=(%3 -.u.old) [~ u.old] + :- %+ turn ~(tap in ~(key by sessions.u.old)) + |= id=@ta + ^- card:agent:gall + [%give %kick ~[/sole/[id]] ~] + =- u.old(- %4, sessions -) + %- ~(gas by *(map sole-id session)) + %+ murn ~(tap by sessions.u.old) + |= [id=@ta s=session] + (bind (upgrade-id:sole:shoe id) (late s)) + :: + ?> ?=(%4 -.u.old) :_ u.old - %+ welp - cards - ?: %- ~(has by wex.bowl) - [/graph-store our-self %graph-store] - ~ - ~[connect] + ;: welp + cards-1 + cards-2 + :: + ?: %- ~(has by wex.bowl) + [/graph-store our-self %graph-store] + ~ + ~[connect] + == :: +connect: connect to the graph-store :: ++ connect From da47cfb08e8e9044790633a76892c6f0794af611 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 21 Feb 2022 12:11:40 -0600 Subject: [PATCH 008/715] drum: correctly initialize session in +prep --- pkg/arvo/lib/hood/drum.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/lib/hood/drum.hoon b/pkg/arvo/lib/hood/drum.hoon index 67abf801a..1448d649e 100644 --- a/pkg/arvo/lib/hood/drum.hoon +++ b/pkg/arvo/lib/hood/drum.hoon @@ -132,7 +132,7 @@ :: ++ prep |= s=@tas - =. ses ses + =. ses s =. dev (~(gut by bin) ses *source) this :: From 20c46457272e53549fb7fe09babb79f06a17b8e5 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Tue, 22 Feb 2022 13:07:01 -0500 Subject: [PATCH 009/715] gall: adds optional agent integration with |mass --- pkg/arvo/sys/vane/gall.hoon | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pkg/arvo/sys/vane/gall.hoon b/pkg/arvo/sys/vane/gall.hoon index af07252e2..6b216dcfc 100644 --- a/pkg/arvo/sys/vane/gall.hoon +++ b/pkg/arvo/sys/vane/gall.hoon @@ -1753,8 +1753,16 @@ (sort ~(tap by queued) aor) :: =/ running - =/ active (~(run by yokes.state) |=(yoke [%.y +<])) - (sort ~(tap by active) aor) + %+ turn (sort ~(tap by yokes.state) aor) + |= [dap=term =yoke] + ^- mass + =/ met=(list mass) + =/ dat (mo-peek:mo dap [~ ship] %x /whey/noun) + ?: ?=(?(~ [~ ~]) dat) ~ + (fall ((soft (list mass)) q.q.u.u.dat) ~) + ?~ met + dap^&+yoke + dap^|+(welp met dot+&+yoke ~) :: =/ maz=(list mass) :~ [%foreign %.y contacts.state] From 92779d8179b116f95f68da46530312617fcaac84 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 23 Feb 2022 00:14:44 -0500 Subject: [PATCH 010/715] gall: updates agent /whey scry to produce %mass mark --- pkg/arvo/sys/vane/gall.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/sys/vane/gall.hoon b/pkg/arvo/sys/vane/gall.hoon index 6b216dcfc..93c05597a 100644 --- a/pkg/arvo/sys/vane/gall.hoon +++ b/pkg/arvo/sys/vane/gall.hoon @@ -1757,7 +1757,7 @@ |= [dap=term =yoke] ^- mass =/ met=(list mass) - =/ dat (mo-peek:mo dap [~ ship] %x /whey/noun) + =/ dat (mo-peek:mo | dap [~ ship] %x /whey/mass) ?: ?=(?(~ [~ ~]) dat) ~ (fall ((soft (list mass)) q.q.u.u.dat) ~) ?~ met From 9c930688356b06079598b6e1824823ac078f2b84 Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 23 Feb 2022 00:15:37 -0500 Subject: [PATCH 011/715] gall: adds verbose arg to agent scry implementation --- pkg/arvo/sys/vane/gall.hoon | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/arvo/sys/vane/gall.hoon b/pkg/arvo/sys/vane/gall.hoon index 93c05597a..5214f756d 100644 --- a/pkg/arvo/sys/vane/gall.hoon +++ b/pkg/arvo/sys/vane/gall.hoon @@ -840,11 +840,11 @@ :: ++ mo-peek ~/ %mo-peek - |= [dap=term =routes care=term =path] + |= [veb=? dap=term =routes care=term =path] ^- (unit (unit cage)) :: =/ app (ap-abed:ap dap routes) - (ap-peek:app care path) + (ap-peek:app veb care path) :: ++ mo-apply |= [dap=term =routes =deal] @@ -1246,7 +1246,7 @@ :: ++ ap-peek ~/ %ap-peek - |= [care=term tyl=path] + |= [veb=? care=term tyl=path] ^- (unit (unit cage)) :: take trailing mark off path for %x scrys :: @@ -1259,6 +1259,7 @@ =/ peek-result=(each (unit (unit cage)) tang) (ap-mule-peek |.((on-peek:ap-agent-core [care tyl]))) ?: ?=(%| -.peek-result) + ?. veb [~ ~] ((slog leaf+"peek bad result" p.peek-result) [~ ~]) :: for non-%x scries, or failed %x scries, or %x results that already :: have the requested mark, produce the result as-is @@ -1814,7 +1815,7 @@ ?. ?=(^ path) ~ =/ =routes [~ ship] - (mo-peek:mo dap routes care path) + (mo-peek:mo & dap routes care path) :: +stay: save without cache; suspend non-%base agents :: :: TODO: superfluous? see +molt From 8cac5b50c4a34127d4c784b77d8a83ba66b2b4dc Mon Sep 17 00:00:00 2001 From: Joe Bryan Date: Wed, 23 Feb 2022 00:16:27 -0500 Subject: [PATCH 012/715] graph-store: integrates with |mass --- pkg/landscape/app/graph-store.hoon | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pkg/landscape/app/graph-store.hoon b/pkg/landscape/app/graph-store.hoon index ca6e85cf8..fabe7d743 100644 --- a/pkg/landscape/app/graph-store.hoon +++ b/pkg/landscape/app/graph-store.hoon @@ -617,6 +617,16 @@ |= =path ^- (unit (unit cage)) ?+ path (on-peek:def path) + [%x %whey ~] + =/ liv=(list mass) + (sort (turn ~(tap by graphs) |=([[* n=term] g=*] n^&+g)) aor) + =/ log=(list mass) + (sort (turn ~(tap by update-logs) |=([[* n=term] l=*] n^&+l)) aor) + =/ sil=(list mass) + (sort (turn ~(tap by archive) |=([[* n=term] g=*] n^&+g)) aor) + :^ ~ ~ %mass + !>(`(list mass)`[live+|+liv logs+|+log ?~(sil ~ [silo+|+sil ~])]) + :: [%x %export ~] ``noun+!>(state) :: [%x %keys ~] From bb11c74278b6619652b34093a77d77d91ab2058e Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 28 Feb 2022 16:24:41 -0600 Subject: [PATCH 013/715] drum: don't drop state during se-subze Previously, it was putting new session state into the old map, preserving only the state of the last session in the map. --- pkg/arvo/lib/hood/drum.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/lib/hood/drum.hoon b/pkg/arvo/lib/hood/drum.hoon index 1448d649e..0f1aa6ce4 100644 --- a/pkg/arvo/lib/hood/drum.hoon +++ b/pkg/arvo/lib/hood/drum.hoon @@ -315,7 +315,7 @@ =< .(con +>) |: $:,[[ses=@tas dev=source] con=_.] ^+ con =+ xeno=se-subze-local:%_(con ses ses, dev dev) - xeno(ses ses.con, dev dev.con, bin (~(put by bin) ses dev.xeno)) + xeno(ses ses.con, dev dev.con, bin (~(put by bin.xeno) ses dev.xeno)) :: ++ se-subze-local ^+ . From bf97b8da38a84e68534faae1c2be96f645dd93d2 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 28 Feb 2022 16:27:29 -0600 Subject: [PATCH 014/715] drum: move +se-view call into +se-abet We practically always do se-abet:se-view anyway. --- pkg/arvo/lib/hood/drum.hoon | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pkg/arvo/lib/hood/drum.hoon b/pkg/arvo/lib/hood/drum.hoon index 0f1aa6ce4..3019b8826 100644 --- a/pkg/arvo/lib/hood/drum.hoon +++ b/pkg/arvo/lib/hood/drum.hoon @@ -143,7 +143,7 @@ :: ++ diff-sole-effect-phat :: app event |= [way=wire fec=sole-effect] - =< se-abet =< se-view + =< se-abet =^ gyl this (open way) ?: (se-aint gyl) +>.$ (se-diff gyl fec) @@ -154,7 +154,7 @@ (prep i.t.pax) ~| [%drum-unauthorized our+our.hid src+src.hid] :: ourself ?> (team:title our.hid src.hid) :: or our own moon - =< se-abet =< se-view + =< se-abet (se-text "[{}, driving {}]") :: ++ poke-dill @@ -163,7 +163,7 @@ :: ++ poke-dill-belt :: terminal event |= bet=dill-belt:dill - =< se-abet =< se-view + =< se-abet (se-belt bet) :: ++ poke-dill-blit :: terminal output @@ -172,12 +172,12 @@ :: ++ poke-link :: connect app |= gyl=gill:gall - =< se-abet =< se-view + =< se-abet (se-link gyl) :: ++ poke-unlink :: disconnect app |= gyl=gill:gall - =< se-abet =< se-view + =< se-abet (se-drop:(se-pull gyl) & gyl) :: ++ poke-exit :: shutdown @@ -201,7 +201,7 @@ :: ++ on-load |= [hood-version=@ud old=any-state] - =< se-abet =< se-view + =< se-abet =? old ?=(%2 -.old) [%4 [eel bin]:old] =? old ?=(%3 -.old) [%4 [eel bin]:old] =? old ?=(%4 -.old) @@ -233,7 +233,7 @@ :: ++ reap-phat :: ack connect |= [way=wire saw=(unit tang)] - =< se-abet =< se-view + =< se-abet =^ gyl this (open way) ?~ saw (se-join gyl) @@ -244,7 +244,7 @@ :: ++ take-coup-phat :: ack poke |= [way=wire saw=(unit tang)] - =< se-abet =< se-view + =< se-abet ?~ saw +> =^ gyl this (open way) ?: (se-aint gyl) +>.$ @@ -269,7 +269,7 @@ :: ++ quit-phat :: |= way=wire - =< se-abet =< se-view + =< se-abet =^ gyl this (open way) ~& [%drum-quit src.hid gyl] (se-drop %| gyl) @@ -278,7 +278,7 @@ :: :: :: ++ se-abet :: resolve ^- (quip card:agent:gall state) - =. . se-subze:se-adze + =. . se-view:se-subze:se-adze :_ sat(bin (~(put by bin) ses dev)) ^- (list card:agent:gall) ?~ biz (flop moz) From 41a063867b52ebfc87d97b837afacf913c263e32 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 28 Feb 2022 16:41:49 -0600 Subject: [PATCH 015/715] dojo: auto-fill generator's named drum-session arg If a generator has a named argument named "drum-session", and the caller doesn't specify a value for it, dojo auto-fills it with the current drum session identifier. --- pkg/arvo/app/dojo.hoon | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/pkg/arvo/app/dojo.hoon b/pkg/arvo/app/dojo.hoon index c8fbd49d7..bf0c24dd4 100644 --- a/pkg/arvo/app/dojo.hoon +++ b/pkg/arvo/app/dojo.hoon @@ -821,12 +821,23 @@ =/ poz=vase (dy-sore p.cig) =/ kev=vase =/ kuv=(unit vase) (slew 7 som) - ?: =(~ q.cig) - (fall kuv !>(~)) =/ soz=(list [var=term vax=vase]) %~ tap by %- ~(run by q.cig) |=(val=(unit dojo-source) ?~(val !>([~ ~]) (dy-vase p.u.val))) + :: if the generator takes a named argument "drum-session", + :: then if a value isn't already supplied, we set it to the session + :: that this dojo instance is being run in. + :: (dojo is, indeed, quite coupled with drum.) + :: + =? soz + ?& ?=(^ kuv) + (slab %both %drum-session p.u.kuv) + !(~(has by q.cig) %drum-session) + == + [[%drum-session !>(ses.id)] soz] ::TODO does the who matter? + ?: =(~ soz) + (fall kuv !>(~)) ~| keyword-arg-failure+~(key by q.cig) %+ slap (with-faces kuv+(need kuv) rep+(with-faces soz) ~) From f6f2fcfcac5ace02e7d451efad9d790aba1003e1 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 28 Feb 2022 16:45:56 -0600 Subject: [PATCH 016/715] drum: make eel per-session This allows us to have different apps connected to different sessions. --- pkg/arvo/lib/hood/drum.hoon | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/arvo/lib/hood/drum.hoon b/pkg/arvo/lib/hood/drum.hoon index 3019b8826..27792b56d 100644 --- a/pkg/arvo/lib/hood/drum.hoon +++ b/pkg/arvo/lib/hood/drum.hoon @@ -15,8 +15,7 @@ +$ state-2 [%2 pith-2] :: +$ pith-5 - $: eel=(set gill:gall) :: connect to - bin=(map @ source) :: terminals + $: bin=(map @ source) :: terminals == :: +$ pith-4 @@ -75,6 +74,7 @@ off=@ud :: window offset kil=kill :: kill buffer inx=@ud :: ring index + eel=(set gill:gall) :: connect to fug=(map gill:gall (unit target)) :: connections mir=(pair @ud stub) :: mirrored terminal == :: @@ -205,12 +205,12 @@ =? old ?=(%2 -.old) [%4 [eel bin]:old] =? old ?=(%3 -.old) [%4 [eel bin]:old] =? old ?=(%4 -.old) - :+ %5 eel.old - |^ (~(run by bin.old) source-4-to-5) + |^ 5+(~(run by bin.old) source-4-to-5) ++ source-4-to-5 - |= s=source-4 + |= source-4 ^- source - s(fug (~(run by fug.s) |=(t=(unit target-4) (bind t target-4-to-5)))) + =; fug [edg off kil inx eel.old fug mir] + (~(run by fug) |=(t=(unit target-4) (bind t target-4-to-5))) :: ++ target-4-to-5 |= t=target-4 From e53cb4a205c212e121d1c815047711ee1c775c51 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 28 Feb 2022 16:47:49 -0600 Subject: [PATCH 017/715] drum: make |un/link work for non-default sessions --- pkg/arvo/gen/hood/link.hoon | 4 +++- pkg/arvo/gen/hood/unlink.hoon | 4 +++- pkg/arvo/lib/hood/drum.hoon | 2 +- pkg/arvo/mar/drum-put.hoon | 7 +++---- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pkg/arvo/gen/hood/link.hoon b/pkg/arvo/gen/hood/link.hoon index 5fe183279..5e14126a1 100644 --- a/pkg/arvo/gen/hood/link.hoon +++ b/pkg/arvo/gen/hood/link.hoon @@ -8,9 +8,11 @@ :: :- %say |= $: [now=@da eny=@uvJ byk=beak] - [arg=$?([dap=term ~] [who=ship dap=term ~]) ~] + arg=$?([dap=term ~] [who=ship dap=term ~]) + drum-session=@ta == :- %drum-link +:- drum-session ?~ +.arg [p.byk dap.arg] [who.arg dap.arg] diff --git a/pkg/arvo/gen/hood/unlink.hoon b/pkg/arvo/gen/hood/unlink.hoon index d7bc509b0..fc6e1fb01 100644 --- a/pkg/arvo/gen/hood/unlink.hoon +++ b/pkg/arvo/gen/hood/unlink.hoon @@ -8,9 +8,11 @@ :: :- %say |= $: [now=@da eny=@uvJ byk=beak] - [arg=$?([dap=term ~] [who=ship dap=term ~]) ~] + arg=$?([dap=term ~] [who=ship dap=term ~]) + drum-session=@ta == :- %drum-unlink +:- drum-session ?~ +.arg [p.byk dap.arg] [who.arg dap.arg] diff --git a/pkg/arvo/lib/hood/drum.hoon b/pkg/arvo/lib/hood/drum.hoon index 27792b56d..f62143e21 100644 --- a/pkg/arvo/lib/hood/drum.hoon +++ b/pkg/arvo/lib/hood/drum.hoon @@ -128,7 +128,7 @@ ++ klr klr:format +$ state ^state :: proxy +$ any-state ^any-state :: proxy -++ on-init (poke-link our.hid %dojo) +++ on-init (poke-link %$ our.hid %dojo) :: ++ prep |= s=@tas diff --git a/pkg/arvo/mar/drum-put.hoon b/pkg/arvo/mar/drum-put.hoon index e6094158e..8fa3773c0 100644 --- a/pkg/arvo/mar/drum-put.hoon +++ b/pkg/arvo/mar/drum-put.hoon @@ -1,8 +1,7 @@ +:: %drum-put: download into host system :: -:::: /hoon/do-claim/womb/mar - :: /? 310 -|_ [path @] +|_ [path $@(@ [@ta @])] :: ++ grad %noun ++ grow @@ -11,6 +10,6 @@ -- ++ grab :: convert from |% - +$ noun [path @] :: clam from %noun + +$ noun [path $@(@ [@ta @])] :: clam from %noun -- -- From 998f7d081a4a88b2fe61d6fbda029274c4e3b5b4 Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 2 Mar 2022 17:24:54 -0600 Subject: [PATCH 018/715] dill: fix %shut session deletion +abet would re-insert the session into state, so we just pull the deletion logic outside of the main core. --- pkg/arvo/sys/vane/dill.hoon | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pkg/arvo/sys/vane/dill.hoon b/pkg/arvo/sys/vane/dill.hoon index b7c81afc7..e2c1e4d2e 100644 --- a/pkg/arvo/sys/vane/dill.hoon +++ b/pkg/arvo/sys/vane/dill.hoon @@ -219,10 +219,6 @@ |= [g=gill _..open] (send [%yow g]) :: - ++ shut - ::TODO send a %bye blit? - pull(eye.all (~(del by eye.all) ses)) - :: ++ send :: send action |= bet=dill-belt ^+ +> @@ -384,7 +380,12 @@ =/ nus ~| [%no-session ses] (need (ax hen ses)) - =^ moz all abet:shut:nus + ::NOTE we do deletion from state outside of the core, + :: because +abet would re-insert. + ::TODO send a %bye blit? xx + =^ moz all abet:pull:nus + =. dug.all (~(del by dug.all) ses) + =. eye.all (~(del by eye.all) ses) [moz ..^$] :: %view opens a subscription to the target session, on the current duct :: From d98611a04bb3f5aeb87bc154cc9485a72aef3402 Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 2 Mar 2022 17:34:19 -0600 Subject: [PATCH 019/715] webterm: support multiple sessions Fully implements webterm support for multiple dill terminal sessions. Remaining work includes styling, session creation safety (name-wise), and general cleanup. Co-authored-by: tomholford Co-authored-by: liam-fitzgerald --- pkg/interface/webterm/.eslintrc.js | 7 + pkg/interface/webterm/.nvmrc | 1 + pkg/interface/webterm/Buffer.tsx | 276 ++++++++++++++++++ pkg/interface/webterm/Tab.tsx | 44 +++ pkg/interface/webterm/Tabs.tsx | 36 +++ pkg/interface/webterm/app.tsx | 416 +++------------------------- pkg/interface/webterm/constants.ts | 1 + pkg/interface/webterm/index.html | 38 +++ pkg/interface/webterm/lib/blit.ts | 73 +++++ pkg/interface/webterm/lib/stye.ts | 60 ++++ pkg/interface/webterm/lib/theme.ts | 21 ++ pkg/interface/webterm/state.ts | 12 +- pkg/interface/webterm/tsconfig.json | 26 ++ pkg/npm/api/term/lib.ts | 4 +- pkg/npm/api/term/types.ts | 4 +- 15 files changed, 626 insertions(+), 393 deletions(-) create mode 100644 pkg/interface/webterm/.eslintrc.js create mode 100644 pkg/interface/webterm/.nvmrc create mode 100644 pkg/interface/webterm/Buffer.tsx create mode 100644 pkg/interface/webterm/Tab.tsx create mode 100644 pkg/interface/webterm/Tabs.tsx create mode 100644 pkg/interface/webterm/constants.ts create mode 100644 pkg/interface/webterm/lib/blit.ts create mode 100644 pkg/interface/webterm/lib/stye.ts create mode 100644 pkg/interface/webterm/lib/theme.ts create mode 100644 pkg/interface/webterm/tsconfig.json diff --git a/pkg/interface/webterm/.eslintrc.js b/pkg/interface/webterm/.eslintrc.js new file mode 100644 index 000000000..66d65c291 --- /dev/null +++ b/pkg/interface/webterm/.eslintrc.js @@ -0,0 +1,7 @@ +const config = { + "rules": { + "spaced-comment": false, + } +} + +export default config; diff --git a/pkg/interface/webterm/.nvmrc b/pkg/interface/webterm/.nvmrc new file mode 100644 index 000000000..0b77208ae --- /dev/null +++ b/pkg/interface/webterm/.nvmrc @@ -0,0 +1 @@ +16.14.0 \ No newline at end of file diff --git a/pkg/interface/webterm/Buffer.tsx b/pkg/interface/webterm/Buffer.tsx new file mode 100644 index 000000000..d33b2e9ec --- /dev/null +++ b/pkg/interface/webterm/Buffer.tsx @@ -0,0 +1,276 @@ +import { Terminal, ITerminalOptions } from 'xterm'; +import { FitAddon } from 'xterm-addon-fit'; +import bel from './lib/bel'; +import api from './api'; + +import { + Belt, pokeTask, pokeBelt +} from '@urbit/api/term'; +import { Session } from './state'; +import { useCallback, useEffect, useRef } from 'react'; +import useTermState from './state'; +import React from 'react'; +import { Box, Col } from '@tlon/indigo-react'; +import { makeTheme } from './lib/theme'; +import { useDark } from './join'; +import { showBlit, csi, showSlog } from './lib/blit'; + +const termConfig: ITerminalOptions = { + logLevel: 'warn', + // + convertEol: true, + // + rows: 24, + cols: 80, + scrollback: 10000, + // + fontFamily: '"Source Code Pro", "Roboto mono", "Courier New", monospace', + fontWeight: 400, + // NOTE theme colors configured dynamically + // + bellStyle: 'sound', + bellSound: bel, + // + // allows text selection by holding modifier (option, or shift) + macOptionClickForcesSelection: true +}; + +const readInput = (term: Terminal, e: string): Belt[] => { + const belts: Belt[] = []; + let strap = ''; + + while (e.length > 0) { + let c = e.charCodeAt(0); + + // text input + // + if (c >= 32 && c !== 127) { + strap += e[0]; + e = e.slice(1); + continue; + } else if ('' !== strap) { + belts.push({ txt: strap.split('') }); + strap = ''; + } + + // special keys/characters + // + if (0 === c) { + term.write('\x07'); // bel + } else if (8 === c || 127 === c) { + belts.push({ bac: null }); + } else if (13 === c) { + belts.push({ ret: null }); + } else if (c <= 26) { + let k = String.fromCharCode(96 + c); + //NOTE prevent remote shut-downs + if ('d' !== k) { + belts.push({ mod: { mod: 'ctl', key: k } }); + } + } + + // escape sequences + // + if (27 === c) { // ESC + e = e.slice(1); + c = e.charCodeAt(0); + if (91 === c || 79 === c) { // [ or O + e = e.slice(1); + c = e.charCodeAt(0); + /* eslint-disable max-statements-per-line */ + switch (c) { + case 65: belts.push({ aro: 'u' }); break; + case 66: belts.push({ aro: 'd' }); break; + case 67: belts.push({ aro: 'r' }); break; + case 68: belts.push({ aro: 'l' }); break; + // + case 77: { + const m = e.charCodeAt(1) - 31; + if (1 === m) { + const c = e.charCodeAt(2) - 32; + const r = e.charCodeAt(3) - 32; + belts.push({ hit: { r: term.rows - r, c: c - 1 } }); + } + e = e.slice(3); + break; + } + // + default: term.write('\x07'); break; // bel + } + } else if (c >= 97 && c <= 122) { // a <= c <= z + belts.push({ mod: { mod: 'met', key: e[0] } }); + } else if (c === 46) { // . + belts.push({ mod: { mod: 'met', key: '.' } }); + } else if (c === 8 || c === 127) { + belts.push({ mod: { mod: 'met', key: { bac: null } } }); + } else { + term.write('\x07'); break; // bel + } + } + + e = e.slice(1); + } + if ('' !== strap) { + belts.push({ txt: strap.split('') }); + strap = ''; + } + return belts; +}; + +const onResize = (session: Session) => () => { + //TODO debounce, if it ever becomes a problem + //TODO test that we only send this to the selected session, + // and that we *do* send it on-selected-change if necessary. + session?.fit.fit(); +}; + +const onInput = (name: string, session: Session, e: string) => { + if (!session) { + return; + } + const term = session.term; + const belts = readInput(term, e); + belts.map((b) => { + api.poke(pokeBelt(name, b)); + }); +}; + +interface BufferProps { + name: string, + selected: boolean, +} + +export default function Buffer({ name, selected }: BufferProps) { + const container = useRef(null); + const dark = useDark(); + + const session: Session = useTermState(s => s.sessions[name]); + + const initSession = useCallback(async (name: string, dark: boolean) => { + console.log('setting up', name); + + // set up xterm terminal + // + const term = new Terminal(termConfig); + term.setOption('theme', makeTheme(dark)); + const fit = new FitAddon(); + term.loadAddon(fit); + fit.fit(); + term.focus(); + + // start mouse reporting + // + term.write(csi('?9h')); + + const ses: Session = { term, fit, hasBell: false }; + + // set up event handlers + // + term.onData(e => onInput(name, ses, e)); + term.onBinary(e => onInput(name, ses, e)); + term.onResize((e) => { + api.poke(pokeTask(name, { blew: { w: e.cols, h: e.rows } })); + }); + + // open subscription + // + await api.subscribe({ app: 'herm', path: '/session/'+name+'/view', + event: (e) => { + showBlit(ses.term, e); + if (e.bel && !selected) { + useTermState.getState().set(state => { + state.sessions[name].hasBell = true; + }); + } + //TODO should handle %bye on this higher level though, for deletion + }, + quit: () => { // quit + // TODO show user a message + console.error('oops quit, pls handle'); + } + }); + + useTermState.getState().set((state) => { + state.sessions[name] = ses; + }); + }, []); + + // init session + useEffect(() => { + if(session) { + return; + } + + initSession(name, dark); + }, [name]); + + // on selected change, maybe setup the term, or put it into the container + // + const setContainer = useCallback((containerRef: HTMLDivElement | null) => { + let newContainer = containerRef || container.current; + if(session && newContainer) { + container.current = newContainer; + console.log('newcont', newContainer); + // session.term.open(newContainer); + } else { + console.log('kaboom', session); + } + }, [session]); + + // on-init, open slogstream and fetch existing sessions + // + useEffect(() => { + + window.addEventListener('resize', onResize(session)); + + return () => { + // TODO clean up subs? + window.removeEventListener('resize', onResize(session)); + }; + }, []); + + // on dark mode change, change terminals' theme + // + useEffect(() => { + const theme = makeTheme(dark); + if (session) { + session.term.setOption('theme', theme); + } + if (container.current) { + container.current.style.backgroundColor = theme.background || ''; + } + }, [dark]); + + useEffect(() => { + if (session && selected && !session.term.isOpen) { + session!.term.open(container.current); + session!.fit.fit(); + session!.term.focus(); + session!.term.isOpen = true; + } + }, [selected, session]); + + return ( + !session && !selected ? +