diff --git a/html/browse-slack/environment.mu.html b/html/browse-slack/environment.mu.html new file mode 100644 index 00000000..50872a6c --- /dev/null +++ b/html/browse-slack/environment.mu.html @@ -0,0 +1,339 @@ + + +
+ ++ 1 # The environment is a thin layer in this app, just a history of 'tabs' that + 2 # are fully specified by the operations used to generate them. + 3 + 4 type environment { + 5 item-index: int + 6 } + 7 + 8 # static buffer sizes in this file: + 9 # main-panel-hor # in characters + 10 # item-padding-hor # in pixels + 11 # item-padding-ver # in characters + 12 # avatar-side # in pixels + 13 # avatar-space-hor # in characters + 14 # avatar-space-ver # in characters + 15 # search-position-x # in characters + 16 # search-space-ver # in characters + 17 # author-name-padding-ver # in characters + 18 # post-right-coord # in characters + 19 # channel-offset-x # in characters + 20 # menu-space-ver # in characters + 21 + 22 fn initialize-environment _self: (addr environment), _items: (addr item-list) { + 23 var self/esi: (addr environment) <- copy _self + 24 var items/eax: (addr item-list) <- copy _items + 25 var newest-item-a/eax: (addr int) <- get items, newest + 26 var newest-item/eax: int <- copy *newest-item-a + 27 var dest/edi: (addr int) <- get self, item-index + 28 copy-to *dest, newest-item + 29 } + 30 + 31 fn render-environment screen: (addr screen), env: (addr environment), users: (addr array user), channels: (addr array channel), items: (addr item-list) { + 32 clear-screen screen + 33 render-search-input screen, env + 34 render-channels screen, env, channels + 35 render-item-list screen, env, items, users + 36 render-menu screen + 37 } + 38 + 39 fn render-channels screen: (addr screen), env: (addr environment), _channels: (addr array channel) { + 40 var channels/esi: (addr array channel) <- copy _channels + 41 var y/ebx: int <- copy 2/search-space-ver + 42 y <- add 1/item-padding-ver + 43 var i/ecx: int <- copy 0 + 44 var max/edx: int <- length channels + 45 { + 46 compare i, max + 47 break-if->= + 48 var offset/eax: (offset channel) <- compute-offset channels, i + 49 var curr/eax: (addr channel) <- index channels, offset + 50 var name-ah/eax: (addr handle array byte) <- get curr, name + 51 var name/eax: (addr array byte) <- lookup *name-ah + 52 compare name, 0 + 53 break-if-= + 54 set-cursor-position screen, 2/x y + 55 draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "#", 0xf/grey 0/black + 56 draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, name, 0xf/grey 0/black + 57 y <- add 2/channel-padding + 58 i <- increment + 59 loop + 60 } + 61 } + 62 + 63 fn render-item-list screen: (addr screen), _env: (addr environment), _items: (addr item-list), users: (addr array user) { + 64 var env/esi: (addr environment) <- copy _env + 65 var tmp-width/eax: int <- copy 0 + 66 var tmp-height/ecx: int <- copy 0 + 67 tmp-width, tmp-height <- screen-size screen + 68 var screen-width: int + 69 copy-to screen-width, tmp-width + 70 var screen-height: int + 71 copy-to screen-height, tmp-height + 72 # + 73 var y/ecx: int <- copy 2/search-space-ver + 74 y <- add 1/item-padding-ver + 75 var newest-item/eax: (addr int) <- get env, item-index + 76 var i/ebx: int <- copy *newest-item + 77 var items/esi: (addr item-list) <- copy _items + 78 var items-data-ah/eax: (addr handle array item) <- get items, data + 79 var _items-data/eax: (addr array item) <- lookup *items-data-ah + 80 var items-data/edi: (addr array item) <- copy _items-data + 81 { + 82 compare i, 0 + 83 break-if-< + 84 compare y, screen-height + 85 break-if->= + 86 var offset/eax: (offset item) <- compute-offset items-data, i + 87 var curr-item/eax: (addr item) <- index items-data, offset + 88 y <- render-item screen, curr-item, users, y, screen-height + 89 i <- decrement + 90 loop + 91 } + 92 var top/eax: int <- copy screen-height + 93 top <- subtract 2/menu-space-ver + 94 clear-rect screen, 0 top, screen-width screen-height, 0/bg + 95 } + 96 + 97 fn render-search-input screen: (addr screen), env: (addr environment) { + 98 set-cursor-position 0/screen, 0x22/x=search-position-x 1/y + 99 draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "search ", 7/fg 0/bg +100 draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "________________________________", 0xf/fg 0/bg +101 } +102 +103 fn render-menu screen: (addr screen) { +104 var width/eax: int <- copy 0 +105 var y/ecx: int <- copy 0 +106 width, y <- screen-size screen +107 y <- decrement +108 set-cursor-position screen, 2/x, y +109 draw-text-rightward-from-cursor screen, " / ", width, 0/fg 0xf/bg +110 draw-text-rightward-from-cursor screen, " search ", width, 0xf/fg, 0/bg +111 draw-text-rightward-from-cursor screen, " ^f ", width, 0/fg 0xf/bg +112 draw-text-rightward-from-cursor screen, " next page ", width, 0xf/fg, 0/bg +113 draw-text-rightward-from-cursor screen, " ^b ", width, 0/fg 0xf/bg +114 draw-text-rightward-from-cursor screen, " previous page ", width, 0xf/fg, 0/bg +115 } +116 +117 fn render-item screen: (addr screen), _item: (addr item), _users: (addr array user), y: int, screen-height: int -> _/ecx: int { +118 var item/esi: (addr item) <- copy _item +119 var users/edi: (addr array user) <- copy _users +120 var author-index-addr/ecx: (addr int) <- get item, by +121 var author-index/ecx: int <- copy *author-index-addr +122 var author-offset/ecx: (offset user) <- compute-offset users, author-index +123 var author/ecx: (addr user) <- index users, author-offset +124 # author avatar +125 var author-avatar-ah/eax: (addr handle image) <- get author, avatar +126 var _author-avatar/eax: (addr image) <- lookup *author-avatar-ah +127 var author-avatar/ebx: (addr image) <- copy _author-avatar +128 { +129 compare author-avatar, 0 +130 break-if-= +131 var y/edx: int <- copy y +132 y <- shift-left 4/log2font-height +133 var x/eax: int <- copy 0x20/main-panel-hor +134 x <- shift-left 3/log2font-width +135 x <- add 0x18/item-padding-hor +136 render-image screen, author-avatar, x, y, 0x50/avatar-side, 0x50/avatar-side +137 } +138 # channel +139 var channel-name-ah/eax: (addr handle array byte) <- get item, channel +140 var channel-name/eax: (addr array byte) <- lookup *channel-name-ah +141 { +142 var x/eax: int <- copy 0x20/main-panel-hor +143 x <- add 0x40/channel-offset-x +144 set-cursor-position screen, x y +145 } +146 draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "#", 7/grey 0/black +147 draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, channel-name, 7/grey 0/black +148 # author name +149 var author-real-name-ah/eax: (addr handle array byte) <- get author, real-name +150 var author-real-name/eax: (addr array byte) <- lookup *author-real-name-ah +151 { +152 var x/ecx: int <- copy 0x20/main-panel-hor +153 x <- add 0x10/avatar-space-hor +154 set-cursor-position screen, x y +155 draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, author-real-name, 0xf/white 0/black +156 } +157 increment y +158 # text +159 var text-ah/eax: (addr handle array byte) <- get item, text +160 var _text/eax: (addr array byte) <- lookup *text-ah +161 var text/edx: (addr array byte) <- copy _text +162 var x/eax: int <- copy 0x20/main-panel-hor +163 x <- add 0x10/avatar-space-hor +164 var text-y/ecx: int <- copy y +165 text-y <- add 1/author-name-padding-ver +166 x, text-y <- draw-text-wrapping-right-then-down screen, text, x text-y, 0x70/xmax=post-right-coord screen-height, x text-y, 7/fg 0/bg +167 text-y <- add 2/item-padding-ver +168 # flush +169 add-to y, 6/avatar-space-ver +170 compare y, text-y +171 { +172 break-if-< +173 return y +174 } +175 return text-y +176 } +177 +178 fn update-environment env: (addr environment), key: byte, items: (addr item-list) { +179 { +180 compare key, 6/ctrl-f +181 break-if-!= +182 page-down env, items +183 return +184 } +185 { +186 compare key, 2/ctrl-b +187 break-if-!= +188 page-up env, items +189 return +190 } +191 } +192 +193 fn page-down _env: (addr environment), _items: (addr item-list) { +194 var env/edi: (addr environment) <- copy _env +195 var items/esi: (addr item-list) <- copy _items +196 var items-data-ah/eax: (addr handle array item) <- get items, data +197 var _items-data/eax: (addr array item) <- lookup *items-data-ah +198 var items-data/ebx: (addr array item) <- copy _items-data +199 var src/eax: (addr int) <- get env, item-index +200 var new-item-index/ecx: int <- copy *src +201 var y/edx: int <- copy 2 +202 { +203 compare new-item-index, 0 +204 break-if-< +205 compare y, 0x28/screen-height-minus-menu +206 break-if->= +207 var offset/eax: (offset item) <- compute-offset items-data, new-item-index +208 var item/eax: (addr item) <- index items-data, offset +209 var item-text-ah/eax: (addr handle array byte) <- get item, text +210 var item-text/eax: (addr array byte) <- lookup *item-text-ah +211 var h/eax: int <- estimate-height item-text +212 set-cursor-position 0/screen, 0 0 +213 draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, h, 4/fg 0/bg +214 y <- add h +215 new-item-index <- decrement +216 loop +217 } +218 new-item-index <- increment +219 var dest/eax: (addr int) <- get env, item-index +220 copy-to *dest, new-item-index +221 } +222 +223 fn page-up _env: (addr environment), _items: (addr item-list) { +224 var env/edi: (addr environment) <- copy _env +225 var items/esi: (addr item-list) <- copy _items +226 var items-data-ah/eax: (addr handle array item) <- get items, data +227 var _items-data/eax: (addr array item) <- lookup *items-data-ah +228 var items-data/ebx: (addr array item) <- copy _items-data +229 var newest-item-index-a/esi: (addr int) <- get items, newest +230 var src/eax: (addr int) <- get env, item-index +231 var new-item-index/ecx: int <- copy *src +232 var y/edx: int <- copy 2 +233 { +234 compare new-item-index, *newest-item-index-a +235 break-if-> +236 compare y, 0x28/screen-height-minus-menu +237 break-if->= +238 var offset/eax: (offset item) <- compute-offset items-data, new-item-index +239 var item/eax: (addr item) <- index items-data, offset +240 var item-text-ah/eax: (addr handle array byte) <- get item, text +241 var item-text/eax: (addr array byte) <- lookup *item-text-ah +242 var h/eax: int <- estimate-height item-text +243 set-cursor-position 0/screen, 0 0 +244 draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, h, 4/fg 0/bg +245 y <- add h +246 new-item-index <- increment +247 loop +248 } +249 new-item-index <- decrement +250 var dest/eax: (addr int) <- get env, item-index +251 copy-to *dest, new-item-index +252 } +253 +254 # keep sync'd with render-item +255 fn estimate-height _message-text: (addr array byte) -> _/eax: int { +256 var message-text/esi: (addr array byte) <- copy _message-text +257 var result/eax: int <- length message-text +258 var remainder/edx: int <- copy 0 +259 result, remainder <- integer-divide result, 0x40/post-width +260 compare remainder, 0 +261 { +262 break-if-= +263 result <- increment +264 } +265 result <- add 2/item-padding-ver +266 compare result, 6/avatar-space-ver +267 { +268 break-if-> +269 return 6/avatar-space-ver +270 } +271 return result +272 } ++ + + diff --git a/html/browse-slack/main.mu.html b/html/browse-slack/main.mu.html new file mode 100644 index 00000000..17dea13b --- /dev/null +++ b/html/browse-slack/main.mu.html @@ -0,0 +1,518 @@ + + + + +
+ 1 type channel { + 2 name: (handle array byte) + 3 posts: (handle array int) # item indices + 4 newest-post-index: int + 5 } + 6 + 7 type user { + 8 id: (handle array byte) + 9 name: (handle array byte) + 10 real-name: (handle array byte) + 11 avatar: (handle image) + 12 } + 13 + 14 type item { + 15 id: (handle array byte) + 16 channel: (handle array byte) + 17 by: int # user index + 18 text: (handle array byte) + 19 parent: int # item index + 20 comments: (handle array int) + 21 newest-comment-index: int + 22 } + 23 + 24 type item-list { + 25 data: (handle array item) + 26 newest: int + 27 } + 28 + 29 # globals: + 30 # users: (handle array user) + 31 # channels: (handle array channel) + 32 # items: (handle array item) + 33 # + 34 # flows: + 35 # channel -> posts + 36 # user -> posts|comments + 37 # post -> comments + 38 # comment -> post|comments + 39 # keywords -> posts|comments + 40 + 41 # static buffer sizes in this program: + 42 # data-size + 43 # data-size-in-sectors + 44 # num-channels + 45 # num-users + 46 # num-items + 47 # num-comments + 48 # message-text-limit + 49 # channel-capacity + 50 + 51 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { + 52 # load entire disk contents to a single enormous stream + 53 var s-h: (handle stream byte) # the stream is too large to put on the stack + 54 var s-ah/eax: (addr handle stream byte) <- address s-h + 55 populate-stream s-ah, 0x4000000/data-size + 56 var _s/eax: (addr stream byte) <- lookup *s-ah + 57 var s/ebx: (addr stream byte) <- copy _s + 58 var sector-count/eax: int <- copy 0x400 # test_data + 59 #? var sector-count/eax: int <- copy 0x20000 # largest size tested; slow + 60 draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "loading ", 3/fg 0/bg + 61 draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, sector-count, 3/fg 0/bg + 62 draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, " sectors from data disk..", 3/fg 0/bg + 63 load-sectors data-disk, 0/lba, sector-count, s + 64 draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "done", 3/fg 0/bg + 65 # parse global data structures out of the stream + 66 var users-h: (handle array user) + 67 var users-ah/eax: (addr handle array user) <- address users-h + 68 populate users-ah, 0x800/num-users + 69 var _users/eax: (addr array user) <- lookup *users-ah + 70 var users/edi: (addr array user) <- copy _users + 71 var channels-h: (handle array channel) + 72 var channels-ah/eax: (addr handle array channel) <- address channels-h + 73 populate channels-ah, 0x20/num-channels + 74 var _channels/eax: (addr array channel) <- lookup *channels-ah + 75 var channels/esi: (addr array channel) <- copy _channels + 76 var items-storage: item-list + 77 var items/edx: (addr item-list) <- address items-storage + 78 var items-data-ah/eax: (addr handle array item) <- get items, data + 79 populate items-data-ah, 0x10000/num-items + 80 parse s, users, channels, items + 81 # render + 82 var env-storage: environment + 83 var env/ebx: (addr environment) <- address env-storage + 84 initialize-environment env, items + 85 { + 86 render-environment screen, env, users, channels, items + 87 { + 88 var key/eax: byte <- read-key keyboard + 89 compare key, 0 + 90 loop-if-= + 91 update-environment env, key, items + 92 } + 93 loop + 94 } + 95 } + 96 + 97 fn parse in: (addr stream byte), users: (addr array user), channels: (addr array channel), _items: (addr item-list) { + 98 var items/esi: (addr item-list) <- copy _items + 99 var items-data-ah/eax: (addr handle array item) <- get items, data +100 var _items-data/eax: (addr array item) <- lookup *items-data-ah +101 var items-data/edi: (addr array item) <- copy _items-data +102 # 'in' consists of a long, flat sequence of records surrounded by parens +103 var record-storage: (stream byte 0x18000) +104 var record/ecx: (addr stream byte) <- address record-storage +105 var user-idx/edx: int <- copy 0 +106 var item-idx/ebx: int <- copy 0 +107 { +108 var done?/eax: boolean <- stream-empty? in +109 compare done?, 0/false +110 break-if-!= +111 var c/eax: byte <- peek-byte in +112 compare c, 0 +113 break-if-= +114 set-cursor-position 0/screen, 0x20 0x20 +115 draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, user-idx, 3/fg 0/bg +116 draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, item-idx, 4/fg 0/bg +117 clear-stream record +118 parse-record in, record +119 var user?/eax: boolean <- user-record? record +120 { +121 compare user?, 0/false +122 break-if-= +123 parse-user record, users, user-idx +124 user-idx <- increment +125 } +126 { +127 compare user?, 0/false +128 break-if-!= +129 parse-item record, channels, items-data, item-idx +130 item-idx <- increment +131 } +132 loop +133 } +134 var dest/eax: (addr int) <- get items, newest +135 copy-to *dest, item-idx +136 decrement *dest +137 } +138 +139 fn parse-record in: (addr stream byte), out: (addr stream byte) { +140 var paren/eax: byte <- read-byte in +141 compare paren, 0x28/open-paren +142 { +143 break-if-= +144 set-cursor-position 0/screen, 0x20 0x10 +145 var c/eax: int <- copy paren +146 draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen c, 5/fg 0/bg +147 abort "parse-record: (" +148 } +149 var paren-int/eax: int <- copy paren +150 append-byte out, paren-int +151 { +152 { +153 var eof?/eax: boolean <- stream-empty? in +154 compare eof?, 0/false +155 break-if-= +156 abort "parse-record: truncated; increase the sector-count to load from disk" +157 } +158 var c/eax: byte <- read-byte in +159 { +160 var c-int/eax: int <- copy c +161 append-byte out, c-int +162 } +163 compare c, 0x29/close-paren +164 break-if-= +165 compare c, 0x22/double-quote +166 { +167 break-if-!= +168 slurp-json-string in, out +169 } +170 loop +171 } +172 skip-chars-matching-whitespace in +173 } +174 +175 fn user-record? record: (addr stream byte) -> _/eax: boolean { +176 rewind-stream record +177 var c/eax: byte <- read-byte record # skip paren +178 var c/eax: byte <- read-byte record # skip double quote +179 var c/eax: byte <- read-byte record +180 compare c, 0x55/U +181 { +182 break-if-!= +183 return 1/true +184 } +185 rewind-stream record +186 return 0/false +187 } +188 +189 fn parse-user record: (addr stream byte), _users: (addr array user), user-idx: int { +190 var users/esi: (addr array user) <- copy _users +191 var offset/eax: (offset user) <- compute-offset users, user-idx +192 var user/esi: (addr user) <- index users, offset +193 # +194 var s-storage: (stream byte 0x100) +195 var s/ecx: (addr stream byte) <- address s-storage +196 # +197 rewind-stream record +198 var paren/eax: byte <- read-byte record +199 compare paren, 0x28/open-paren +200 { +201 break-if-= +202 abort "parse-user: (" +203 } +204 # user id +205 skip-chars-matching-whitespace record +206 var double-quote/eax: byte <- read-byte record +207 compare double-quote, 0x22/double-quote +208 { +209 break-if-= +210 abort "parse-user: id" +211 } +212 next-json-string record, s +213 var dest/eax: (addr handle array byte) <- get user, id +214 stream-to-array s, dest +215 # user name +216 skip-chars-matching-whitespace record +217 var double-quote/eax: byte <- read-byte record +218 compare double-quote, 0x22/double-quote +219 { +220 break-if-= +221 abort "parse-user: name" +222 } +223 clear-stream s +224 next-json-string record, s +225 var dest/eax: (addr handle array byte) <- get user, name +226 stream-to-array s, dest +227 # real name +228 skip-chars-matching-whitespace record +229 var double-quote/eax: byte <- read-byte record +230 compare double-quote, 0x22/double-quote +231 { +232 break-if-= +233 abort "parse-user: real-name" +234 } +235 clear-stream s +236 next-json-string record, s +237 var dest/eax: (addr handle array byte) <- get user, real-name +238 stream-to-array s, dest +239 # avatar +240 skip-chars-matching-whitespace record +241 var open-bracket/eax: byte <- read-byte record +242 compare open-bracket, 0x5b/open-bracket +243 { +244 break-if-= +245 abort "parse-user: avatar" +246 } +247 skip-chars-matching-whitespace record +248 var c/eax: byte <- peek-byte record +249 { +250 compare c, 0x5d/close-bracket +251 break-if-= +252 var dest-ah/eax: (addr handle image) <- get user, avatar +253 allocate dest-ah +254 var dest/eax: (addr image) <- lookup *dest-ah +255 initialize-image dest, record +256 } +257 } +258 +259 fn parse-item record: (addr stream byte), _channels: (addr array channel), _items: (addr array item), item-idx: int { +260 var items/esi: (addr array item) <- copy _items +261 var offset/eax: (offset item) <- compute-offset items, item-idx +262 var item/edi: (addr item) <- index items, offset +263 # +264 var s-storage: (stream byte 0x40) +265 var s/ecx: (addr stream byte) <- address s-storage +266 # +267 rewind-stream record +268 var paren/eax: byte <- read-byte record +269 compare paren, 0x28/open-paren +270 { +271 break-if-= +272 abort "parse-item: (" +273 } +274 # item id +275 skip-chars-matching-whitespace record +276 var double-quote/eax: byte <- read-byte record +277 compare double-quote, 0x22/double-quote +278 { +279 break-if-= +280 abort "parse-item: id" +281 } +282 next-json-string record, s +283 var dest/eax: (addr handle array byte) <- get item, id +284 stream-to-array s, dest +285 # parent index +286 { +287 var word-slice-storage: slice +288 var word-slice/ecx: (addr slice) <- address word-slice-storage +289 next-word record, word-slice +290 var src/eax: int <- parse-decimal-int-from-slice word-slice +291 compare src, -1 +292 break-if-= +293 var dest/edx: (addr int) <- get item, parent +294 copy-to *dest, src +295 # cross-link to parent +296 var parent-offset/eax: (offset item) <- compute-offset items, src +297 var parent-item/esi: (addr item) <- index items, parent-offset +298 var parent-comments-ah/ebx: (addr handle array int) <- get parent-item, comments +299 var parent-comments/eax: (addr array int) <- lookup *parent-comments-ah +300 compare parent-comments, 0 +301 { +302 break-if-!= +303 populate parent-comments-ah, 0x200/num-comments +304 parent-comments <- lookup *parent-comments-ah +305 } +306 var parent-newest-comment-index-addr/edi: (addr int) <- get parent-item, newest-comment-index +307 var parent-newest-comment-index/edx: int <- copy *parent-newest-comment-index-addr +308 var dest/eax: (addr int) <- index parent-comments, parent-newest-comment-index +309 var src/ecx: int <- copy item-idx +310 copy-to *dest, src +311 increment *parent-newest-comment-index-addr +312 } +313 # channel name +314 skip-chars-matching-whitespace record +315 var double-quote/eax: byte <- read-byte record +316 compare double-quote, 0x22/double-quote +317 { +318 break-if-= +319 abort "parse-item: channel" +320 } +321 clear-stream s +322 next-json-string record, s +323 var dest/eax: (addr handle array byte) <- get item, channel +324 stream-to-array s, dest +325 # cross-link to channels +326 { +327 var channels/esi: (addr array channel) <- copy _channels +328 var channel-index/eax: int <- find-or-insert channels, s +329 var channel-offset/eax: (offset channel) <- compute-offset channels, channel-index +330 var channel/eax: (addr channel) <- index channels, channel-offset +331 var channel-posts-ah/ecx: (addr handle array int) <- get channel, posts +332 var channel-newest-post-index-addr/edx: (addr int) <- get channel, newest-post-index +333 var channel-newest-post-index/edx: int <- copy *channel-newest-post-index-addr +334 var channel-posts/eax: (addr array int) <- lookup *channel-posts-ah +335 var dest/eax: (addr int) <- index channel-posts, channel-newest-post-index +336 } +337 # user index +338 { +339 var word-slice-storage: slice +340 var word-slice/ecx: (addr slice) <- address word-slice-storage +341 next-word record, word-slice +342 var src/eax: int <- parse-decimal-int-from-slice word-slice +343 var dest/edx: (addr int) <- get item, by +344 copy-to *dest, src +345 } +346 # text +347 var s-storage: (stream byte 0x4000) # message-text-limit +348 var s/ecx: (addr stream byte) <- address s-storage +349 skip-chars-matching-whitespace record +350 var double-quote/eax: byte <- read-byte record +351 compare double-quote, 0x22/double-quote +352 { +353 break-if-= +354 abort "parse-item: text" +355 } +356 next-json-string record, s +357 var dest/eax: (addr handle array byte) <- get item, text +358 stream-to-array s, dest +359 } +360 +361 fn find-or-insert _channels: (addr array channel), name: (addr stream byte) -> _/eax: int { +362 var channels/esi: (addr array channel) <- copy _channels +363 var i/ecx: int <- copy 0 +364 var max/edx: int <- length channels +365 { +366 compare i, max +367 break-if->= +368 var offset/eax: (offset channel) <- compute-offset channels, i +369 var curr/ebx: (addr channel) <- index channels, offset +370 var curr-name-ah/edi: (addr handle array byte) <- get curr, name +371 var curr-name/eax: (addr array byte) <- lookup *curr-name-ah +372 { +373 compare curr-name, 0 +374 break-if-!= +375 rewind-stream name +376 stream-to-array name, curr-name-ah +377 var posts-ah/eax: (addr handle array int) <- get curr, posts +378 populate posts-ah, 0x8000/channel-capacity +379 return i +380 } +381 var found?/eax: boolean <- stream-data-equal? name, curr-name +382 { +383 compare found?, 0/false +384 break-if-= +385 return i +386 } +387 i <- increment +388 loop +389 } +390 abort "out of channels" +391 return -1 +392 } +393 +394 # includes trailing double quote +395 fn slurp-json-string in: (addr stream byte), out: (addr stream byte) { +396 # open quote is already slurped +397 { +398 { +399 var eof?/eax: boolean <- stream-empty? in +400 compare eof?, 0/false +401 break-if-= +402 abort "slurp-json-string: truncated" +403 } +404 var c/eax: byte <- read-byte in +405 { +406 var c-int/eax: int <- copy c +407 append-byte out, c-int +408 } +409 compare c, 0x22/double-quote +410 break-if-= +411 compare c, 0x5c/backslash +412 { +413 break-if-!= +414 # read next byte raw +415 c <- read-byte in +416 var c-int/eax: int <- copy c +417 append-byte out, c-int +418 } +419 loop +420 } +421 } +422 +423 # drops trailing double quote +424 fn next-json-string in: (addr stream byte), out: (addr stream byte) { +425 # open quote is already read +426 { +427 { +428 var eof?/eax: boolean <- stream-empty? in +429 compare eof?, 0/false +430 break-if-= +431 abort "next-json-string: truncated" +432 } +433 var c/eax: byte <- read-byte in +434 compare c, 0x22/double-quote +435 break-if-= +436 { +437 var c-int/eax: int <- copy c +438 append-byte out, c-int +439 } +440 compare c, 0x5c/backslash +441 { +442 break-if-!= +443 # read next byte raw +444 c <- read-byte in +445 var c-int/eax: int <- copy c +446 append-byte out, c-int +447 } +448 loop +449 } +450 } ++ + +