logo

adventofcode

Code used to solve https://adventofcode.com/, one branch per year git clone https://anongit.hacktivis.me/git/adventofcode.git/

7spw.ha (2382B)


  1. use encoding::utf8;
  2. use io;
  3. use types::c;
  4. @symbol("close") fn close(int) int;
  5. @symbol("dup") fn dup(int) int;
  6. @symbol("dup2") fn dup2(int, int) int;
  7. @symbol("lseek") fn lseek(int, io::off, int) io::off;
  8. @symbol("mkstemp") fn mkstemp(*c::char) int;
  9. @symbol("perror") fn perror(nullable *const c::char) void;
  10. @symbol("read") fn read(int, *opaque, size) c::ssize;
  11. @symbol("unlink") fn unlink(*const c::char) int;
  12. @symbol("write") fn write(int, *const opaque, size) c::ssize;
  13. type error = !str;
  14. def STDOUT_FILENO: int = 1;
  15. def STDERR_FILENO: int = 2;
  16. let stderr = -1;
  17. let tmpfd = -1;
  18. let tmpname: [_]u8 = ['/', 't', 'm', 'p', '/', 'X', 'X', 'X', 'X', 'X', 'X', '\0'];
  19. @init fn tmp() void = {
  20. stderr = dup(STDERR_FILENO);
  21. assert(stderr != -1);
  22. tmpfd = mkstemp(tmpname[..]: *[*]u8: *c::char);
  23. assert(tmpfd != -1);
  24. // libc wrapper functions will set stderr back to actual stderr before
  25. // performing any operation on it
  26. // (in this demo i didn't bother with this, but like hypothetically)
  27. const n = dup2(tmpfd, STDERR_FILENO);
  28. assert(n != -1);
  29. };
  30. @fini fn tmp() void = {
  31. if (tmpfd != -1) {
  32. close(tmpfd);
  33. unlink(tmpname[..]: *[*]u8: *const c::char);
  34. };
  35. };
  36. export fn main() void = {
  37. // set errno to EBADF to demonstrate
  38. const n = close(-1);
  39. assert(n == -1);
  40. const err = errno();
  41. write(STDOUT_FILENO, *(&err: **const opaque), len(err));
  42. write(STDOUT_FILENO, &10u8, 1);
  43. };
  44. fn errno() error = {
  45. perror(null);
  46. if (write(STDERR_FILENO, &0u8, 1) == -1) {
  47. return "Unknown error";
  48. };
  49. // we don't know the value of SEEK_SET, so iterate from 0 to 2 and check
  50. // which one has expected seek behavior
  51. // technically the value may not be from 0 to 2, but if that's the case
  52. // then eh just abort, i think this is a reasonable assumption to make
  53. let i = 0;
  54. for (i < 2; i += 1) {
  55. if (lseek(STDERR_FILENO, 0, i) == 0) {
  56. break;
  57. };
  58. };
  59. assert(i < 2);
  60. defer {
  61. // seek to beginning of file when function returns, so next time
  62. // errno() is called the position is already set (necessary
  63. // since lseek may overwrite errno)
  64. lseek(STDERR_FILENO, 0, i);
  65. };
  66. static let buf: [1024]u8 = [0...];
  67. const n = read(STDERR_FILENO, &buf, len(buf));
  68. if (n == -1) {
  69. return "Unknown error";
  70. };
  71. const n = c::strlen(buf[..]: *[*]u8: *const c::char);
  72. if (n == 0 || !utf8::valid(buf[..n - 1])) {
  73. return "Unknown error";
  74. };
  75. return *(&buf[..n - 1]: *str);
  76. };