https://github.com/akkartik/mu/blob/main/501draw-text.mu
  1 # some primitives for moving the cursor without making assumptions about
  2 # raster order
  3 fn move-cursor-left screen: (addr screen) {
  4   var cursor-x/eax: int <- copy 0
  5   var cursor-y/ecx: int <- copy 0
  6   cursor-x, cursor-y <- cursor-position screen
  7   compare cursor-x, 0
  8   {
  9     break-if->
 10     return
 11   }
 12   cursor-x <- decrement
 13   set-cursor-position screen, cursor-x, cursor-y
 14 }
 15 
 16 fn move-cursor-right screen: (addr screen) {
 17   var _width/eax: int <- copy 0
 18   var dummy/ecx: int <- copy 0
 19   _width, dummy <- screen-size screen
 20   var limit/edx: int <- copy _width
 21   limit <- decrement
 22   var cursor-x/e
/*
 * resource.h
 * vim: expandtab:ts=4:sts=4:sw=4
 *
 * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
 *
 * This file is part of Profanity.
 *
 * Profanity is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Profanity is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Profanity.  If not, see <https://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give permission to
 * link the code of portions of this program with the OpenSSL library under
 * certain conditions as described in each individual source file, and
 * distribute linked combinations including the two.
 *
 * You must obey the GNU General Public License in all respects for all of the
 * code used other than OpenSSL. If you modify file(s) with this exception, you
 * may extend this exception to your version of the file(s), but you are not
 * obligated to do so. If you do not wish to do so, delete this exception
 * statement from your version. If you delete this exception statement from all
 * source files in the program, then also delete it here.
 *
 */

#ifndef XMPP_RESOURCE_H
#define XMPP_RESOURCE_H

#include "common.h"

typedef struct resource_t
{
    char* name;
    resource_presence_t presence;
    char* status;
    int priority;
} Resource;

Resource* resource_new(const char* const name, resource_presence_t presence, const char* const status,
                       const int priority);
void resource_destroy(Resource* resource);
int resource_compare_availability(Resource* first, Resource* second);

gboolean valid_resource_presence_string(const char* const str);
const char* string_from_resource_presence(resource_presence_t presence);
resource_presence_t resource_presence_from_string(const char* const str);
contact_presence_t contact_presence_from_resource_presence(resource_presence_t resource_presence);

#endif
ite.subx.html#L11'>write stream, text 110 var xcurr/eax: int <- draw-stream-rightward screen, stream, x, xmax, y, color, background-color 111 return xcurr 112 } 113 114 # draw a single-line stream from x, y to xmax 115 # return the next 'x' coordinate 116 # if there isn't enough space, truncate 117 fn draw-stream-rightward screen: (addr screen), stream: (addr stream byte), x: int, xmax: int, y: int, color: int, background-color: int -> _/eax: int { 118 var xcurr/ecx: int <- copy x 119 { 120 var g/eax: code-point-utf8 <- read-code-point-utf8 stream 121 compare g, 0xffffffff/end-of-file 122 break-if-= 123 var c/eax: code-point <- to-code-point g 124 var offset/eax: int <- draw-code-point screen, c, xcurr, y, color, background-color 125 xcurr <- add offset 126 loop 127 } 128 set-cursor-position screen, xcurr, y 129 return xcurr 130 } 131 132 fn draw-text-rightward-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int, background-color: int -> _/eax: int { 133 var width/eax: int <- copy 0 134 var height/ecx: int <- copy 0 135 width, height <- screen-size screen 136 var result/eax: int <- draw-text-rightward screen, text, x, width, y, color, background-color 137 return result 138 } 139 140 fn draw-text-rightward-from-cursor screen: (addr screen), text: (addr array byte), xmax: int, color: int, background-color: int { 141 var cursor-x/eax: int <- copy 0 142 var cursor-y/ecx: int <- copy 0 143 cursor-x, cursor-y <- cursor-position screen 144 cursor-x <- draw-text-rightward screen, text, cursor-x, xmax, cursor-y, color, background-color 145 set-cursor-position screen, cursor-x, cursor-y 146 } 147 148 fn draw-text-rightward-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int, background-color: int { 149 var width/eax: int <- copy 0 150 var height/ecx: int <- copy 0 151 width, height <- screen-size screen 152 draw-text-rightward-from-cursor screen, text, width, color, background-color 153 } 154 155 fn render-code-point screen: (addr screen), c: code-point, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { 156 var x/ecx: int <- copy x 157 compare c, 0xa/newline 158 { 159 break-if-!= 160 # minimum effort to clear cursor 161 var dummy/eax: int <- draw-code-point screen, 0x20/space, x, y, color, background-color 162 x <- copy xmin 163 increment y 164 return x, y 165 } 166 var offset/eax: int <- draw-code-point screen, c, x, y, color, background-color 167 x <- add offset 168 compare x, xmax 169 { 170 break-if-< 171 x <- copy xmin 172 increment y 173 } 174 return x, y 175 } 176 177 # draw text in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary 178 # return the next (x, y) coordinate in raster order where drawing stopped 179 # that way the caller can draw more if given the same min and max bounding-box. 180 # if there isn't enough space, truncate 181 fn draw-text-wrapping-right-then-down screen: (addr screen), _text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { 182 var stream-storage: (stream byte 0x200/print-buffer-size) 183 var stream/edi: (addr stream byte) <- address stream-storage 184 var text/esi: (addr array byte) <- copy _text 185 var len/eax: int <- length text 186 compare len, 0x200/print-buffer-size 187 { 188 break-if-< 189 write stream, "ERROR: stream too small in draw-text-wrapping-right-then-down" 190 } 191 compare len, 0x200/print-buffer-size 192 { 193 break-if->= 194 write stream, text 195 } 196 var x/eax: int <- copy _x 197 var y/ecx: int <- copy _y 198 x, y <- draw-stream-wrapping-right-then-down screen, stream, xmin, ymin, xmax, ymax, x, y, color, background-color 199 return x, y 200 } 201 202 # draw a stream in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary 203 # return the next (x, y) coordinate in raster order where drawing stopped 204 # that way the caller can draw more if given the same min and max bounding-box. 205 # if there isn't enough space, truncate 206 fn draw-stream-wrapping-right-then-down screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { 207 var xcurr/ecx: int <- copy x 208 var ycurr/edx: int <- copy y 209 var c/ebx: code-point <- copy 0 210 var next-c/esi: code-point <- copy 0 211 $draw-stream-wrapping-right-then-down:loop: { 212 # read c from either next-c or stream 213 $draw-stream-wrapping-right-then-down:read-base: { 214 compare next-c, 0 215 { 216 break-if-= 217 c <- copy next-c 218 next-c <- copy 0 219 break $draw-stream-wrapping-right-then-down:read-base 220 } 221 var g/eax: code-point-utf8 <- read-code-point-utf8 stream 222 var _c/eax: code-point <- to-code-point g 223 c <- copy _c 224 } 225 compare c, 0xffffffff/end-of-file 226 break-if-= 227 compare c, 0xa/newline 228 { 229 break-if-!= 230 # minimum effort to clear cursor 231 var dummy/eax: int <- draw-code-point screen, 0x20/space, xcurr, ycurr, color, background-color 232 xcurr <- copy xmin 233 ycurr <- increment 234 loop $draw-stream-wrapping-right-then-down:loop 235 } 236 var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color 237 # overlay a combining character if necessary 238 $draw-stream-wrapping-right-then-down:read-combiner: { 239 var done?/eax: boolean <- stream-empty? stream 240 compare done?, 0/false 241 break-if-!= 242 # read a character 243 var g/eax: code-point-utf8 <- read-code-point-utf8 stream 244 var c/eax: code-point <- to-code-point g 245 # if not a combining character, save for next iteration and loop 246 { 247 var combining-code-point?/eax: boolean <- combining-code-point? c 248 compare combining-code-point?, 0/false 249 } 250 { 251 break-if-!= 252 next-c <- copy c 253 break $draw-stream-wrapping-right-then-down:read-combiner 254 } 255 # otherwise overlay it without saving its width 256 # This means strange results if a base and its combiner have different 257 # widths. We'll always follow the base width. 258 var dummy/eax: int <- overlay-code-point screen, c, xcurr, ycurr, color, background-color 259 } 260 xcurr <- add offset 261 compare xcurr, xmax 262 { 263 break-if-< 264 xcurr <- copy xmin 265 ycurr <- increment 266 } 267 loop 268 } 269 set-cursor-position screen, xcurr, ycurr 270 return xcurr, ycurr 271 } 272 273 fn draw-stream-wrapping-right-then-down-from-cursor screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int { 274 var cursor-x/eax: int <- copy 0 275 var cursor-y/ecx: int <- copy 0 276 cursor-x, cursor-y <- cursor-position screen 277 var end-x/edx: int <- copy cursor-x 278 end-x <- increment 279 compare end-x, xmax 280 { 281 break-if-< 282 cursor-x <- copy xmin 283 cursor-y <- increment 284 } 285 cursor-x, cursor-y <- draw-stream-wrapping-right-then-down screen, stream, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color 286 } 287 288 fn draw-stream-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), stream: (addr stream byte), color: int, background-color: int { 289 var width/eax: int <- copy 0 290 var height/ecx: int <- copy 0 291 width, height <- screen-size screen 292 draw-stream-wrapping-right-then-down-from-cursor screen, stream, 0/xmin, 0/ymin, width, height, color, background-color 293 } 294 295 fn move-cursor-rightward-and-downward screen: (addr screen), xmin: int, xmax: int { 296 var cursor-x/eax: int <- copy 0 297 var cursor-y/ecx: int <- copy 0 298 cursor-x, cursor-y <- cursor-position screen 299 cursor-x <- increment 300 compare cursor-x, xmax 301 { 302 break-if-< 303 cursor-x <- copy xmin 304 cursor-y <- increment 305 } 306 set-cursor-position screen, cursor-x, cursor-y 307 } 308 309 fn draw-text-wrapping-right-then-down-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { 310 var x2/eax: int <- copy 0 311 var y2/ecx: int <- copy 0 312 x2, y2 <- screen-size screen # width, height 313 x2, y2 <- draw-text-wrapping-right-then-down screen, text, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color 314 return x2, y2 # cursor-x, cursor-y 315 } 316 317 fn draw-text-wrapping-right-then-down-from-cursor screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int { 318 var cursor-x/eax: int <- copy 0 319 var cursor-y/ecx: int <- copy 0 320 cursor-x, cursor-y <- cursor-position screen 321 var end-x/edx: int <- copy cursor-x 322 end-x <- increment 323 compare end-x, xmax 324 { 325 break-if-< 326 cursor-x <- copy xmin 327 cursor-y <- increment 328 } 329 cursor-x, cursor-y <- draw-text-wrapping-right-then-down screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color 330 } 331 332 fn draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int, background-color: int { 333 var width/eax: int <- copy 0 334 var height/ecx: int <- copy 0 335 width, height <- screen-size screen 336 draw-text-wrapping-right-then-down-from-cursor screen, text, 0/xmin, 0/ymin, width, height, color, background-color 337 } 338 339 fn draw-int32-hex-wrapping-right-then-down screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { 340 var stream-storage: (stream byte 0x100) 341 var stream/esi: (addr stream byte) <- address stream-storage 342 write-int32-hex stream, n 343 var xcurr/edx: int <- copy x 344 var ycurr/ecx: int <- copy y 345 { 346 var g/eax: code-point-utf8 <- read-code-point-utf8 stream 347 compare g, 0xffffffff/end-of-file 348 break-if-= 349 var c/eax: code-point <- to-code-point g 350 var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color 351 xcurr <- add offset 352 compare xcurr, xmax 353 { 354 break-if-< 355 xcurr <- copy xmin 356 ycurr <- increment 357 } 358 loop 359 } 360 set-cursor-position screen, xcurr, ycurr 361 return xcurr, ycurr 362 } 363 364 fn draw-int32-hex-wrapping-right-then-down-over-full-screen screen: (addr screen), n: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { 365 var x2/eax: int <- copy 0 366 var y2/ecx: int <- copy 0 367 x2, y2 <- screen-size screen # width, height 368 x2, y2 <- draw-int32-hex-wrapping-right-then-down screen, n, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color 369 return x2, y2 # cursor-x, cursor-y 370 } 371 372 fn draw-int32-hex-wrapping-right-then-down-from-cursor screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int { 373 var cursor-x/eax: int <- copy 0 374 var cursor-y/ecx: int <- copy 0 375 cursor-x, cursor-y <- cursor-position screen 376 var end-x/edx: int <- copy cursor-x 377 end-x <- increment 378 compare end-x, xmax 379 { 380 break-if-< 381 cursor-x <- copy xmin 382 cursor-y <- increment 383 } 384 cursor-x, cursor-y <- draw-int32-hex-wrapping-right-then-down screen, n, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color 385 } 386 387 fn draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), n: int, color: int, background-color: int { 388 var width/eax: int <- copy 0 389 var height/ecx: int <- copy 0 390 width, height <- screen-size screen 391 draw-int32-hex-wrapping-right-then-down-from-cursor screen, n, 0/xmin, 0/ymin, width, height, color, background-color 392 } 393 394 fn draw-int32-decimal-wrapping-right-then-down screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { 395 var stream-storage: (stream byte 0x100) 396 var stream/esi: (addr stream byte) <- address stream-storage 397 write-int32-decimal stream, n 398 var xcurr/edx: int <- copy x 399 var ycurr/ecx: int <- copy y 400 { 401 var g/eax: code-point-utf8 <- read-code-point-utf8 stream 402 compare g, 0xffffffff/end-of-file 403 break-if-= 404 var c/eax: code-point <- to-code-point g 405 var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color 406 xcurr <- add offset 407 compare xcurr, xmax 408 { 409 break-if-< 410 xcurr <- copy xmin 411 ycurr <- increment 412 } 413 loop 414 } 415 set-cursor-position screen, xcurr, ycurr 416 return xcurr, ycurr 417 } 418 419 fn draw-int32-decimal-wrapping-right-then-down-over-full-screen screen: (addr screen), n: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { 420 var x2/eax: int <- copy 0 421 var y2/ecx: int <- copy 0 422 x2, y2 <- screen-size screen # width, height 423 x2, y2 <- draw-int32-decimal-wrapping-right-then-down screen, n, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color 424 return x2, y2 # cursor-x, cursor-y 425 } 426 427 fn draw-int32-decimal-wrapping-right-then-down-from-cursor screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int { 428 var cursor-x/eax: int <- copy 0 429 var cursor-y/ecx: int <- copy 0 430 cursor-x, cursor-y <- cursor-position screen 431 var end-x/edx: int <- copy cursor-x 432 end-x <- increment 433 compare end-x, xmax 434 { 435 break-if-< 436 cursor-x <- copy xmin 437 cursor-y <- increment 438 } 439 cursor-x, cursor-y <- draw-int32-decimal-wrapping-right-then-down screen, n, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color 440 } 441 442 fn draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), n: int, color: int, background-color: int { 443 var width/eax: int <- copy 0 444 var height/ecx: int <- copy 0 445 width, height <- screen-size screen 446 draw-int32-decimal-wrapping-right-then-down-from-cursor screen, n, 0/xmin, 0/ymin, width, height, color, background-color 447 } 448 449 ## Text direction: down then right 450 451 # draw a single line of text vertically from x, y to ymax 452 # return the next 'y' coordinate 453 # if there isn't enough space, truncate 454 fn draw-text-downward screen: (addr screen), text: (addr array byte), x: int, y: int, ymax: int, color: int, background-color: int -> _/eax: int { 455 var stream-storage: (stream byte 0x100) 456 var stream/esi: (addr stream byte) <- address stream-storage 457 write stream, text 458 var ycurr/eax: int <- draw-stream-downward screen, stream, x, y, ymax, color, background-color 459 return ycurr 460 } 461 462 # draw a single-line stream vertically from x, y to ymax 463 # return the next 'y' coordinate 464 # if there isn't enough space, truncate 465 # TODO: should we track horizontal width? 466 fn draw-stream-downward screen: (addr screen), stream: (addr stream byte), x: int, y: int, ymax: int, color: int, background-color: int -> _/eax: int { 467 var ycurr/ecx: int <- copy y 468 { 469 var g/eax: code-point-utf8 <- read-code-point-utf8 stream 470 compare g, 0xffffffff/end-of-file 471 break-if-= 472 var c/eax: code-point <- to-code-point g 473 var dummy/eax: int <- draw-code-point screen, c, x, ycurr, color, background-color 474 ycurr <- increment 475 loop 476 } 477 set-cursor-position screen, x, ycurr 478 return ycurr 479 } 480 481 fn draw-text-downward-from-cursor screen: (addr screen), text: (addr array byte), ymax: int, color: int, background-color: int { 482 var cursor-x/eax: int <- copy 0 483 var cursor-y/ecx: int <- copy 0 484 cursor-x, cursor-y <- cursor-position screen 485 var result/eax: int <- draw-text-downward screen, text, cursor-x, cursor-y, ymax, color, background-color 486 } 487 488 # draw text down and right in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary 489 # return the next (x, y) coordinate in raster order where drawing stopped 490 # that way the caller can draw more if given the same min and max bounding-box. 491 # if there isn't enough space, truncate 492 fn draw-text-wrapping-down-then-right screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { 493 var stream-storage: (stream byte 0x100) 494 var stream/esi: (addr stream byte) <- address stream-storage 495 write stream, text 496 var x/eax: int <- copy _x 497 var y/ecx: int <- copy _y 498 x, y <- draw-stream-wrapping-down-then-right screen, stream, xmin, ymin, xmax, ymax, x, y, color, background-color 499 return x, y 500 } 501 502 # draw a stream down and right in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary 503 # return the next (x, y) coordinate in raster order where drawing stopped 504 # that way the caller can draw more if given the same min and max bounding-box. 505 # if there isn't enough space, truncate 506 # TODO: should we track horizontal width? just always offset by 2 for now 507 fn draw-stream-wrapping-down-then-right screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { 508 var xcurr/edx: int <- copy x 509 var ycurr/ecx: int <- copy y 510 { 511 var g/eax: code-point-utf8 <- read-code-point-utf8 stream 512 compare g, 0xffffffff/end-of-file 513 break-if-= 514 var c/eax: code-point <- to-code-point g 515 var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color 516 ycurr <- increment 517 compare ycurr, ymax 518 { 519 break-if-< 520 xcurr <- add 2 521 ycurr <- copy ymin 522 } 523 loop 524 } 525 set-cursor-position screen, xcurr, ycurr 526 return xcurr, ycurr 527 } 528 529 fn draw-text-wrapping-down-then-right-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int { 530 var x2/eax: int <- copy 0 531 var y2/ecx: int <- copy 0 532 x2, y2 <- screen-size screen # width, height 533 x2, y2 <- draw-text-wrapping-down-then-right screen, text, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color 534 return x2, y2 # cursor-x, cursor-y 535 } 536 537 fn draw-text-wrapping-down-then-right-from-cursor screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int { 538 var cursor-x/eax: int <- copy 0 539 var cursor-y/ecx: int <- copy 0 540 cursor-x, cursor-y <- cursor-position screen 541 var end-y/edx: int <- copy cursor-y 542 end-y <- increment 543 compare end-y, ymax 544 { 545 break-if-< 546 cursor-x <- increment 547 cursor-y <- copy ymin 548 } 549 cursor-x, cursor-y <- draw-text-wrapping-down-then-right screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color 550 } 551 552 fn draw-text-wrapping-down-then-right-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int, background-color: int { 553 var width/eax: int <- copy 0 554 var height/ecx: int <- copy 0 555 width, height <- screen-size screen 556 draw-text-wrapping-down-then-right-from-cursor screen, text, 0/xmin, 0/ymin, width, height, color, background-color 557 }