Subversion Repositories Kolibri OS

Rev

Rev 9337 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.     UMKa - User-Mode KolibriOS developer tools
  3.     umka_shell - interactive shell
  4.     Copyright (C) 2018--2020  Ivan Baravy <dunkaist@gmail.com>
  5.  
  6.     This program is free software: you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation, either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program.  If not, see <https://www.gnu.org/licenses/>.
  18. */
  19.  
  20. #include <stdio.h>
  21. #include <stdbool.h>
  22. #include <stdint.h>
  23. #include <stdlib.h>
  24. #include <stddef.h>
  25. #include <string.h>
  26. #include <assert.h>
  27. #include <errno.h>
  28.  
  29. #include "getopt.h"
  30. #include "vdisk.h"
  31. #include "umka.h"
  32. #include "trace.h"
  33. #include "pci.h"
  34. #include "lodepng.h"
  35.  
  36. #define PATH_MAX 4096
  37. #define FGETS_BUF_LEN 4096
  38. #define MAX_COMMAND_ARGS 42
  39. #define PRINT_BYTES_PER_LINE 32
  40. #define MAX_DIRENTS_TO_READ 100
  41. #define MAX_BYTES_TO_READ (1024*1024)
  42.  
  43. #define DEFAULT_READDIR_ENCODING UTF8
  44. #define DEFAULT_PATH_ENCODING UTF8
  45.  
  46. FILE *fin, *fout;
  47.  
  48. char cur_dir[PATH_MAX] = "/";
  49. const char *last_dir = cur_dir;
  50. bool cur_dir_changed = true;
  51.  
  52. char cmd_buf[FGETS_BUF_LEN];
  53.  
  54. typedef struct {
  55.     char *name;
  56.     void (*func) (int, char **);
  57. } func_table_t;
  58.  
  59. const char *f70_status_name[] = {
  60.                                  "success",
  61.                                  "disk_base",
  62.                                  "unsupported_fs",
  63.                                  "unknown_fs",
  64.                                  "partition",
  65.                                  "file_not_found",
  66.                                  "end_of_file",
  67.                                  "memory_pointer",
  68.                                  "disk_full",
  69.                                  "fs_fail",
  70.                                  "access_denied",
  71.                                  "device",
  72.                                  "out_of_memory"
  73.                                 };
  74.  
  75. static const char *
  76. get_f70_status_name(int s) {
  77.     switch (s) {
  78.     case ERROR_SUCCESS:
  79. //        return "";
  80.     case ERROR_DISK_BASE:
  81.     case ERROR_UNSUPPORTED_FS:
  82.     case ERROR_UNKNOWN_FS:
  83.     case ERROR_PARTITION:
  84.     case ERROR_FILE_NOT_FOUND:
  85.     case ERROR_END_OF_FILE:
  86.     case ERROR_MEMORY_POINTER:
  87.     case ERROR_DISK_FULL:
  88.     case ERROR_FS_FAIL:
  89.     case ERROR_ACCESS_DENIED:
  90.     case ERROR_DEVICE:
  91.     case ERROR_OUT_OF_MEMORY:
  92.         return f70_status_name[s];
  93.     default:
  94.         return "unknown";
  95.     }
  96. }
  97.  
  98. static void
  99. convert_f70_file_attr(uint32_t attr, char s[KF_ATTR_CNT+1]) {
  100.     s[0] = (attr & KF_READONLY) ? 'r' : '-';
  101.     s[1] = (attr & KF_HIDDEN)   ? 'h' : '-';
  102.     s[2] = (attr & KF_SYSTEM)   ? 's' : '-';
  103.     s[3] = (attr & KF_LABEL)    ? 'l' : '-';
  104.     s[4] = (attr & KF_FOLDER)   ? 'f' : '-';
  105.     s[5] = '\0';
  106. }
  107.  
  108. static void
  109. print_f70_status(f7080ret_t *r, int use_ebx) {
  110.     fprintf(fout, "status = %d %s", r->status, get_f70_status_name(r->status));
  111.     if (use_ebx &&
  112.         (r->status == ERROR_SUCCESS || r->status == ERROR_END_OF_FILE))
  113.         fprintf(fout, ", count = %d", r->count);
  114.     fputc('\n', fout);
  115. }
  116.  
  117. static bool
  118. parse_uintmax(const char *str, uintmax_t *res) {
  119.     char *endptr;
  120.     *res = strtoumax(str, &endptr, 0);
  121.     bool ok = (str != endptr) && (*endptr == '\0');
  122.     return ok;
  123. }
  124.  
  125. static bool
  126. parse_uint32(const char *str, uint32_t *res) {
  127.     uintmax_t x;
  128.     if (parse_uintmax(str, &x) && x <= UINT32_MAX) {
  129.         *res = (uint32_t)x;
  130.         return true;
  131.     } else {
  132.         perror("invalid number");
  133.         return false;
  134.     }
  135. }
  136.  
  137. static bool
  138. parse_uint64(const char *str, uint64_t *res) {
  139.     uintmax_t x;
  140.     if (parse_uintmax(str, &x) && x <= UINT64_MAX) {
  141.         *res = x;
  142.         return true;
  143.     } else {
  144.         perror("invalid number");
  145.         return false;
  146.     }
  147. }
  148.  
  149. static void
  150. print_bytes(uint8_t *x, size_t len) {
  151.     for (size_t i = 0; i < len; i++) {
  152.         if (i % PRINT_BYTES_PER_LINE == 0 && i != 0) {
  153.             fputc('\n', fout);
  154.         }
  155.         fprintf(fout, "%2.2x", x[i]);
  156.     }
  157.     fputc('\n', fout);
  158. }
  159.  
  160. static void
  161. print_hash(uint8_t *x, size_t len) {
  162.     hash_context ctx;
  163.     hash_oneshot(&ctx, x, len);
  164.     for (size_t i = 0; i < HASH_SIZE; i++) {
  165.         fprintf(fout, "%2.2x", ctx.hash[i]);
  166.     }
  167.     fputc('\n', fout);
  168. }
  169.  
  170. static const char *
  171. get_last_dir(const char *path) {
  172.     const char *last = strrchr(path, '/');
  173.     if (!last) {
  174.         last = path;
  175.     } else if (last != path || last[1] != '\0') {
  176.         last++;
  177.     }
  178.     return last;
  179. }
  180.  
  181. static void
  182. prompt() {
  183.     if (cur_dir_changed) {
  184.         if (umka_initialized) {
  185.             COVERAGE_ON();
  186.             umka_sys_get_cwd(cur_dir, PATH_MAX);
  187.             COVERAGE_OFF();
  188.         }
  189.         last_dir = get_last_dir(cur_dir);
  190.         cur_dir_changed = false;
  191.     }
  192.     fprintf(fout, "%s> ", last_dir);
  193.     fflush(fout);
  194. }
  195.  
  196. static int
  197. next_line(int is_tty) {
  198.     if (is_tty) {
  199.         prompt();
  200.     }
  201.     return fgets(cmd_buf, FGETS_BUF_LEN, fin) != NULL;
  202. }
  203.  
  204. static int
  205. split_args(char *s, char **argv) {
  206.     int argc = -1;
  207.     for (; (argv[++argc] = strtok(s, " \t\n\r")) != NULL; s = NULL);
  208.     return argc;
  209. }
  210.  
  211. static void
  212. shell_umka_init(int argc, char **argv) {
  213.     const char *usage = \
  214.         "usage: umka_init";
  215.     (void)argv;
  216.     if (argc < 0) {
  217.         fputs(usage, fout);
  218.         return;
  219.     }
  220.     COVERAGE_ON();
  221.     umka_init();
  222.     COVERAGE_OFF();
  223. }
  224.  
  225. static void
  226. shell_umka_set_boot_params(int argc, char **argv) {
  227.     const char *usage = \
  228.         "usage: umka_set_boot_params [--x_res <num>] [--y_res <num>]\n"
  229.         "  --x_res <num>    screen width\n"
  230.         "  --y_res <num>    screen height";
  231.  
  232.     argc -= 1;
  233.     argv += 1;
  234.  
  235.     while (argc) {
  236.         if (!strcmp(argv[0], "--x_res") && argc > 1) {
  237.             kos_boot.x_res = strtoul(argv[1], NULL, 0);
  238.             kos_boot.pitch = kos_boot.x_res * 4;    // assume 32bpp
  239.             argc -= 2;
  240.             argv += 2;
  241.             continue;
  242.         } else if (!strcmp(argv[0], "--y_res") && argc > 1) {
  243.             kos_boot.y_res = strtoul(argv[1], NULL, 0);
  244.             argc -= 2;
  245.             argv += 2;
  246.             continue;
  247.         } else {
  248.             printf("bad option: %s\n", argv[0]);
  249.             puts(usage);
  250.             exit(1);
  251.         }
  252.     }
  253.  
  254. }
  255.  
  256. static void
  257. shell_i40(int argc, char **argv) {
  258.     const char *usage = \
  259.         "usage: i40 <eax> [ebx [ecx [edx [esi [edi [ebp]]]]]]...\n"
  260.         "  see '/kernel/docs/sysfuncs.txt' for details";
  261.     if (argc < 2 || argc > 8) {
  262.         fputs(usage, fout);
  263.         return;
  264.     }
  265.     pushad_t regs = {0, 0, 0, 0, 0, 0, 0, 0};
  266.     if (argv[1]) regs.eax = strtoul(argv[1], NULL, 0);
  267.     if (argv[2]) regs.ebx = strtoul(argv[2], NULL, 0);
  268.     if (argv[3]) regs.ecx = strtoul(argv[3], NULL, 0);
  269.     if (argv[4]) regs.edx = strtoul(argv[4], NULL, 0);
  270.     if (argv[5]) regs.esi = strtoul(argv[5], NULL, 0);
  271.     if (argv[6]) regs.edi = strtoul(argv[6], NULL, 0);
  272.     if (argv[7]) regs.ebp = strtoul(argv[7], NULL, 0);
  273.     COVERAGE_ON();
  274.     umka_i40(&regs);
  275.     COVERAGE_OFF();
  276.     fprintf(fout, "eax = %8.8x  %" PRIu32 "  %" PRIi32 "\n"
  277.            "ebx = %8.8x  %" PRIu32 "  %" PRIi32 "\n",
  278.            regs.eax, regs.eax, (int32_t)regs.eax,
  279.            regs.ebx, regs.ebx, (int32_t)regs.ebx);
  280. }
  281.  
  282. static void
  283. disk_list_partitions(disk_t *d) {
  284.     for (size_t i = 0; i < d->num_partitions; i++) {
  285.         fprintf(fout, "/%s/%d: ", d->name, i+1);
  286.         if (d->partitions[i]->fs_user_functions == xfs_user_functions) {
  287.             fputs("xfs\n", fout);
  288.         } else if (d->partitions[i]->fs_user_functions == ext_user_functions) {
  289.             fputs("ext\n", fout);
  290.         } else if (d->partitions[i]->fs_user_functions == fat_user_functions) {
  291.             fputs("fat\n", fout);
  292.         } else if (d->partitions[i]->fs_user_functions == ntfs_user_functions) {
  293.             fputs("ntfs\n", fout);
  294.         } else {
  295.             fputs("???\n", fout);
  296.         }
  297.     }
  298. }
  299.  
  300. static void
  301. shell_ramdisk_init(int argc, char **argv) {
  302.     const char *usage = \
  303.         "usage: ramdisk_init <file>\n"
  304.         "  <file>           absolute or relative path";
  305.     if (argc != 2) {
  306.         fputs(usage, fout);
  307.         return;
  308.     }
  309.     const char *fname = argv[1];
  310.     FILE *f = fopen(fname, "rb");
  311.     if (!f) {
  312.         fprintf(fout, "[!] can't open file '%s': %s\n", fname, strerror(errno));
  313.         return;
  314.     }
  315.     fseek(f, 0, SEEK_END);
  316.     size_t fsize = ftell(f);
  317.     if (fsize > 2880*512) {
  318.         fprintf(fout, "[!] file '%s' is too big, max size is 1474560 bytes\n",
  319.                 fname);
  320.         return;
  321.     }
  322.     rewind(f);
  323.     fread(kos_ramdisk, fsize, 1, f);
  324.     fclose(f);
  325.     COVERAGE_ON();
  326.     void *ramdisk = kos_ramdisk_init();
  327.     COVERAGE_OFF();
  328.     disk_list_partitions(ramdisk);
  329. }
  330.  
  331. static void
  332. shell_disk_add(int argc, char **argv) {
  333.     const char *usage = \
  334.         "usage: disk_add <file> <name> [option]...\n"
  335.         "  <file>           absolute or relative path\n"
  336.         "  <name>           disk name, e.g. hd0 or rd\n"
  337.         "  -c cache size    size of disk cache in bytes";
  338.     if (argc < 3) {
  339.         fputs(usage, fout);
  340.         return;
  341.     }
  342.     size_t cache_size = 0;
  343.     int adjust_cache_size = 0;
  344.     int opt;
  345.     optind = 1;
  346.     const char *file_name = argv[optind++];
  347.     const char *disk_name = argv[optind++];
  348.     while ((opt = getopt(argc, argv, "c:")) != -1) {
  349.         switch (opt) {
  350.         case 'c':
  351.             cache_size = strtoul(optarg, NULL, 0);
  352.             adjust_cache_size = 1;
  353.             break;
  354.         default:
  355.             fputs(usage, fout);
  356.             return;
  357.         }
  358.     }
  359.  
  360.     void *userdata = vdisk_init(file_name, adjust_cache_size, cache_size);
  361.     if (userdata) {
  362.         COVERAGE_ON();
  363.         void *vdisk = disk_add(&vdisk_functions, disk_name, userdata, 0);
  364.         COVERAGE_OFF();
  365.         if (vdisk) {
  366.             COVERAGE_ON();
  367.             disk_media_changed(vdisk, 1);
  368.             COVERAGE_OFF();
  369.             disk_list_partitions(vdisk);
  370.             return;
  371.         }
  372.     }
  373.     fprintf(fout, "umka: can't add file '%s' as disk '%s'\n", file_name,
  374.             disk_name);
  375.     return;
  376. }
  377.  
  378. static void
  379. disk_del_by_name(const char *name) {
  380.     for(disk_t *d = disk_list.next; d != &disk_list; d = d->next) {
  381.         if (!strcmp(d->name, name)) {
  382.             COVERAGE_ON();
  383.             disk_del(d);
  384.             COVERAGE_OFF();
  385.             return;
  386.         }
  387.     }
  388.     fprintf(fout, "umka: can't find disk '%s'\n", name);
  389. }
  390.  
  391. static void
  392. shell_disk_del(int argc, char **argv) {
  393.     const char *usage = \
  394.         "usage: disk_del <name>\n"
  395.         "  name             disk name, i.e. rd or hd0";
  396.     if (argc != 2) {
  397.         fputs(usage, fout);
  398.         return;
  399.     }
  400.     const char *name = argv[1];
  401.     disk_del_by_name(name);
  402.     return;
  403. }
  404.  
  405. static void
  406. shell_pwd(int argc, char **argv) {
  407.     const char *usage = \
  408.         "usage: pwd";
  409.     if (argc != 1) {
  410.         fputs(usage, fout);
  411.         return;
  412.     }
  413.     (void)argv;
  414.     bool quoted = false;
  415.     const char *quote = quoted ? "'" : "";
  416.     COVERAGE_ON();
  417.     umka_sys_get_cwd(cur_dir, PATH_MAX);
  418.     COVERAGE_OFF();
  419.     fprintf(fout, "%s%s%s\n", quote, cur_dir, quote);
  420. }
  421.  
  422. static void
  423. shell_set_pixel(int argc, char **argv) {
  424.     const char *usage = \
  425.         "usage: set_pixel <x> <y> <color> [-i]\n"
  426.         "  x                x window coordinate\n"
  427.         "  y                y window coordinate\n"
  428.         "  color            argb in hex\n"
  429.         "  -i               inverted color";
  430.     if (argc < 4) {
  431.         fputs(usage, fout);
  432.         return;
  433.     }
  434.     size_t x = strtoul(argv[1], NULL, 0);
  435.     size_t y = strtoul(argv[2], NULL, 0);
  436.     uint32_t color = strtoul(argv[3], NULL, 16);
  437.     int invert = (argc == 5) && !strcmp(argv[4], "-i");
  438.     COVERAGE_ON();
  439.     umka_sys_set_pixel(x, y, color, invert);
  440.     COVERAGE_OFF();
  441. }
  442.  
  443. static void
  444. shell_write_text(int argc, char **argv) {
  445.     const char *usage = \
  446.         "usage: write_text <x> <y> <color> <string> <asciiz> <fill_bg>"
  447.             " <font_and_enc> <draw_to_buf> <scale_factor> <length>"
  448.             " <bg_color_or_buf>\n"
  449.         "  x                x window coordinate\n"
  450.         "  y                y window coordinate\n"
  451.         "  color            argb in hex\n"
  452.         "  string           escape spaces\n"
  453.         "  asciiz           1 if the string is zero-terminated\n"
  454.         "  fill_bg          fill text background with specified color\n"
  455.         "  font_and_enc     font size and string encoding\n"
  456.         "  draw_to_buf      draw to the buffer pointed to by the next param\n"
  457.         "  length           length of the string if it is non-asciiz\n"
  458.         "  bg_color_or_buf  argb or pointer";
  459.     if (argc != 12) {
  460.         fputs(usage, fout);
  461.         return;
  462.     }
  463.     size_t x = strtoul(argv[1], NULL, 0);
  464.     size_t y = strtoul(argv[2], NULL, 0);
  465.     uint32_t color = strtoul(argv[3], NULL, 16);
  466.     const char *string = argv[4];
  467.     int asciiz = strtoul(argv[5], NULL, 0);
  468.     int fill_background = strtoul(argv[6], NULL, 0);
  469.     int font_and_encoding = strtoul(argv[7], NULL, 0);
  470.     int draw_to_buffer = strtoul(argv[8], NULL, 0);
  471.     int scale_factor = strtoul(argv[9], NULL, 0);
  472.     int length = strtoul(argv[10], NULL, 0);
  473.     int background_color_or_buffer = strtoul(argv[11], NULL, 0);
  474.     COVERAGE_ON();
  475.     umka_sys_write_text(x, y, color, asciiz, fill_background, font_and_encoding,
  476.                         draw_to_buffer, scale_factor, string, length,
  477.                         background_color_or_buffer);
  478.     COVERAGE_OFF();
  479. }
  480.  
  481. static void
  482. shell_dump_win_stack(int argc, char **argv) {
  483.     const char *usage = \
  484.         "usage: dump_win_stack [count]\n"
  485.         "  count            how many items to dump";
  486.     if (argc < 1) {
  487.         fputs(usage, fout);
  488.         return;
  489.     }
  490.     int depth = 5;
  491.     if (argc > 1) {
  492.         depth = strtol(argv[1], NULL, 0);
  493.     }
  494.     for (int i = 0; i < depth; i++) {
  495.         fprintf(fout, "%3i: %3u\n", i, kos_win_stack[i]);
  496.     }
  497. }
  498.  
  499. static void
  500. shell_dump_win_pos(int argc, char **argv) {
  501.     const char *usage = \
  502.         "usage: dump_win_pos [count]\n"
  503.         "  count            how many items to dump";
  504.     if (argc < 1) {
  505.         fputs(usage, fout);
  506.         return;
  507.     }
  508.     int depth = 5;
  509.     if (argc > 1) {
  510.         depth = strtol(argv[1], NULL, 0);
  511.     }
  512.     for (int i = 0; i < depth; i++) {
  513.         fprintf(fout, "%3i: %3u\n", i, kos_win_pos[i]);
  514.     }
  515. }
  516.  
  517. static void
  518. shell_dump_win_map(int argc, char **argv) {
  519.     const char *usage = \
  520.         "usage: dump_win_map";
  521.     (void)argv;
  522.     if (argc < 0) {
  523.         fputs(usage, fout);
  524.         return;
  525.     }
  526.     for (size_t y = 0; y < kos_display.height; y++) {
  527.         for (size_t x = 0; x < kos_display.width; x++) {
  528.             fputc(kos_display.win_map[y * kos_display.width + x] + '0', fout);
  529.         }
  530.         fputc('\n', fout);
  531.     }
  532. }
  533.  
  534. static void
  535. shell_dump_appdata(int argc, char **argv) {
  536.     const char *usage = \
  537.         "usage: dump_appdata <index> [-p]\n"
  538.         "  index            index into appdata array to dump\n"
  539.         "  -p               print fields that are pointers";
  540.     if (argc < 2) {
  541.         fputs(usage, fout);
  542.         return;
  543.     }
  544.     int show_pointers = 0;
  545.     int idx = strtol(argv[1], NULL, 0);
  546.     if (argc > 2 && !strcmp(argv[2], "-p")) {
  547.         show_pointers = 1;
  548.     }
  549.     appdata_t *a = kos_slot_base + idx;
  550.     fprintf(fout, "app_name: %s\n", a->app_name);
  551.     if (show_pointers) {
  552.         fprintf(fout, "process: %p\n", (void*)a->process);
  553.         fprintf(fout, "fpu_state: %p\n", (void*)a->fpu_state);
  554.         fprintf(fout, "exc_handler: %p\n", (void*)a->exc_handler);
  555.     }
  556.     fprintf(fout, "except_mask: %" PRIx32 "\n", a->except_mask);
  557.     if (show_pointers) {
  558.         fprintf(fout, "pl0_stack: %p\n", (void*)a->pl0_stack);
  559.         fprintf(fout, "cursor: %p\n", (void*)a->cursor);
  560.         fprintf(fout, "fd_ev: %p\n", (void*)a->fd_ev);
  561.         fprintf(fout, "bk_ev: %p\n", (void*)a->bk_ev);
  562.         fprintf(fout, "fd_obj: %p\n", (void*)a->fd_obj);
  563.         fprintf(fout, "bk_obj: %p\n", (void*)a->bk_obj);
  564.         fprintf(fout, "saved_esp: %p\n", (void*)a->saved_esp);
  565.     }
  566.     fprintf(fout, "dbg_state: %u\n", a->dbg_state);
  567.     fprintf(fout, "cur_dir: %s\n", a->cur_dir);
  568.     fprintf(fout, "draw_bgr_x: %u\n", a->draw_bgr_x);
  569.     fprintf(fout, "draw_bgr_y: %u\n", a->draw_bgr_y);
  570.     fprintf(fout, "event_mask: %" PRIx32 "\n", a->event_mask);
  571.     fprintf(fout, "terminate_protection: %u\n", a->terminate_protection);
  572.     fprintf(fout, "keyboard_mode: %u\n", a->keyboard_mode);
  573.     fprintf(fout, "captionEncoding: %u\n", a->captionEncoding);
  574.     fprintf(fout, "exec_params: %s\n", a->exec_params);
  575.     fprintf(fout, "wnd_caption: %s\n", a->wnd_caption);
  576.     fprintf(fout, "wnd_clientbox (ltwh): %u %u %u %u\n", a->wnd_clientbox.left,
  577.             a->wnd_clientbox.top, a->wnd_clientbox.width,
  578.             a->wnd_clientbox.height);
  579.     fprintf(fout, "priority: %u\n", a->priority);
  580.  
  581.     fprintf(fout, "in_schedule: prev");
  582.     if (show_pointers) {
  583.         fprintf(fout, " %p", (void*)a->in_schedule.prev);
  584.     }
  585.     fprintf(fout, " (%u), next",
  586.             (appdata_t*)a->in_schedule.prev - kos_slot_base);
  587.     if (show_pointers) {
  588.         fprintf(fout, " %p", (void*)a->in_schedule.next);
  589.     }
  590.     fprintf(fout, " (%u)\n",
  591.             (appdata_t*)a->in_schedule.next - kos_slot_base);
  592. }
  593.  
  594. static void
  595. shell_dump_taskdata(int argc, char **argv) {
  596.     const char *usage = \
  597.         "usage: dump_taskdata <index>\n"
  598.         "  index            index into taskdata array to dump";
  599.     if (argc < 2) {
  600.         fputs(usage, fout);
  601.         return;
  602.     }
  603.     int idx = strtol(argv[1], NULL, 0);
  604.     taskdata_t *t = kos_task_table + idx;
  605.     fprintf(fout, "event_mask: %" PRIx32 "\n", t->event_mask);
  606.     fprintf(fout, "pid: %" PRId32 "\n", t->pid);
  607.     fprintf(fout, "state: 0x%" PRIx8 "\n", t->state);
  608.     fprintf(fout, "wnd_number: %" PRIu8 "\n", t->wnd_number);
  609.     fprintf(fout, "counter_sum: %" PRIu32 "\n", t->counter_sum);
  610.     fprintf(fout, "counter_add: %" PRIu32 "\n", t->counter_add);
  611.     fprintf(fout, "cpu_usage: %" PRIu32 "\n", t->cpu_usage);
  612. }
  613.  
  614. static void
  615. shell_switch_to_thread(int argc, char **argv) {
  616.     const char *usage = \
  617.         "usage: switch_to_thread <tid>\n"
  618.         "  <tid>          thread id to switch to";
  619.     if (argc != 2) {
  620.         fputs(usage, fout);
  621.         return;
  622.     }
  623.     uint8_t tid = strtoul(argv[1], NULL, 0);
  624.     kos_current_slot_idx = tid;
  625.     kos_task_base = kos_task_table + tid;
  626.     kos_current_slot = kos_slot_base + tid;
  627. }
  628.  
  629. static void
  630. shell_set(int argc, char **argv) {
  631.     const char *usage = \
  632.         "usage: set <var> <value>\n"
  633.         "  <var>          variable to set\n"
  634.         "  <value>        decimal or hex value";
  635.     if (argc != 3) {
  636.         fputs(usage, fout);
  637.         return;
  638.     }
  639.     const char *var = argv[1];
  640.     size_t value = strtoul(argv[2], NULL, 0);
  641.     if (!strcmp(var, "redraw_background")) {
  642.         kos_redraw_background = value;
  643.     } else {
  644.         printf("bad option: %s\n", argv[0]);
  645.         puts(usage);
  646.         exit(1);
  647.     }
  648. }
  649.  
  650. static void
  651. shell_new_sys_thread(int argc, char **argv) {
  652.     const char *usage = \
  653.         "usage: new_sys_thread";
  654.     if (!argc) {
  655.         fputs(usage, fout);
  656.         return;
  657.     }
  658.     (void)argv;
  659.     size_t tid = umka_new_sys_threads(0, NULL, NULL);
  660.     fprintf(fout, "tid: %u\n", tid);
  661. }
  662.  
  663. static void
  664. shell_mouse_move(int argc, char **argv) {
  665.     const char *usage = \
  666.         "usage: mouse_move [-l] [-m] [-r] [-x {+|-|=}<value>]"
  667.             "[-y {+|-|=}<value>] [-h {+|-}<value>] [-v {+|-}<value>]\n"
  668.         "  -l             left button is held\n"
  669.         "  -m             middle button is held\n"
  670.         "  -r             right button is held\n"
  671.         "  -x             increase, decrease or set x coordinate\n"
  672.         "  -y             increase, decrease or set y coordinate\n"
  673.         "  -h             scroll horizontally\n"
  674.         "  -v             scroll vertically\n";
  675.     if (!argc) {
  676.         fputs(usage, fout);
  677.         return;
  678.     }
  679.     int lbheld = 0, mbheld = 0, rbheld = 0, xabs = 0, yabs = 0;
  680.     int32_t xmoving = 0, ymoving = 0, hscroll = 0, vscroll = 0;
  681.     int opt;
  682.     optind = 1;
  683.     while ((opt = getopt(argc, argv, "lmrx:y:h:v:")) != -1) {
  684.         switch (opt) {
  685.         case 'l':
  686.             lbheld = 1;
  687.             break;
  688.         case 'm':
  689.             mbheld = 1;
  690.             break;
  691.         case 'r':
  692.             rbheld = 1;
  693.             break;
  694.         case 'x':
  695.             switch (*optarg++) {
  696.             case '=':
  697.                 xabs = 1;
  698.                 __attribute__ ((fallthrough));
  699.             case '+':
  700.                 xmoving = strtol(optarg, NULL, 0);
  701.                 break;
  702.             case '-':
  703.                 xmoving = -strtol(optarg, NULL, 0);
  704.                 break;
  705.             default:
  706.                 fputs(usage, fout);
  707.                 return;
  708.             }
  709.             break;
  710.         case 'y':
  711.             switch (*optarg++) {
  712.             case '=':
  713.                 yabs = 1;
  714.                 __attribute__ ((fallthrough));
  715.             case '+':
  716.                 ymoving = strtol(optarg, NULL, 0);
  717.                 break;
  718.             case '-':
  719.                 ymoving = -strtol(optarg, NULL, 0);
  720.                 break;
  721.             default:
  722.                 fputs(usage, fout);
  723.                 return;
  724.             }
  725.             break;
  726.         case 'h':
  727.             if ((optarg[0] != '+') && (optarg[0] != '-')) {
  728.                 fputs(usage, fout);
  729.                 return;
  730.             }
  731.             hscroll = strtol(optarg, NULL, 0);
  732.             break;
  733.         case 'v':
  734.             if ((optarg[0] != '+') && (optarg[0] != '-')) {
  735.                 fputs(usage, fout);
  736.                 return;
  737.             }
  738.             vscroll = strtol(optarg, NULL, 0);
  739.             break;
  740.         default:
  741.             fputs(usage, fout);
  742.             return;
  743.         }
  744.     }
  745.     COVERAGE_ON();
  746.     umka_mouse_move(lbheld, mbheld, rbheld, xabs, xmoving, yabs, ymoving,
  747.                     hscroll, vscroll);
  748.     COVERAGE_OFF();
  749. }
  750.  
  751. static void
  752. shell_process_info(int argc, char **argv) {
  753.     const char *usage = \
  754.         "usage: process_info <pid>\n"
  755.         "  pid              process id to dump, -1 for self";
  756.     if (argc != 2) {
  757.         fputs(usage, fout);
  758.         return;
  759.     }
  760.     process_information_t info;
  761.     int32_t pid = strtol(argv[1], NULL, 0);
  762.     COVERAGE_ON();
  763.     umka_sys_process_info(pid, &info);
  764.     COVERAGE_OFF();
  765.     fprintf(fout, "cpu_usage: %u\n", info.cpu_usage);
  766.     fprintf(fout, "window_stack_position: %u\n", info.window_stack_position);
  767.     fprintf(fout, "window_stack_value: %u\n", info.window_stack_value);
  768.     fprintf(fout, "process_name: %s\n", info.process_name);
  769.     fprintf(fout, "memory_start: 0x%.8" PRIx32 "\n", info.memory_start);
  770.     fprintf(fout, "used_memory: %u (0x%x)\n", info.used_memory,
  771.             info.used_memory);
  772.     fprintf(fout, "pid: %u\n", info.pid);
  773.     fprintf(fout, "box: %u %u %u %u\n", info.box.left, info.box.top,
  774.             info.box.width, info.box.height);
  775.     fprintf(fout, "slot_state: %u\n", info.slot_state);
  776.     fprintf(fout, "client_box: %u %u %u %u\n", info.client_box.left,
  777.             info.client_box.top, info.client_box.width, info.client_box.height);
  778.     fprintf(fout, "wnd_state: 0x%.2" PRIx8 "\n", info.wnd_state);
  779. }
  780.  
  781. static void
  782. shell_display_number(int argc, char **argv) {
  783.     const char *usage = \
  784.         "usage: display_number <is_pointer> <base> <num_digits> <is_qword>"
  785.             " <show_lead_zeros> <num_or_ptr> <x> <y> <color> <fill_bg> <font>"
  786.             " <draw_to_buf> <scale_factor> <bg_color_or_buf>\n"
  787.         "  is_pointer       if num_or_ptr argument is a pointer\n"
  788.         "  base             0 - dec, 1 - hex, 2 - bin\n"
  789.         "  num_digits       how many digits to print\n"
  790.         "  is_qword         if 1, is_pointer = 1 and num_or_ptr is pointer\n"
  791.         "  show_lead_zeros  0/1\n"
  792.         "  num_or_ptr       number itself or a pointer to it\n"
  793.         "  x                x window coord\n"
  794.         "  y                y window coord\n"
  795.         "  color            argb in hex\n"
  796.         "  fill_bg          0/1\n"
  797.         "  font             0 = 6x9, 1 = 8x16\n"
  798.         "  draw_to_buf      0/1\n"
  799.         "  scale_factor     0 = x1, ..., 7 = x8\n"
  800.         "  bg_color_or_buf  depending on flags fill_bg and draw_to_buf";
  801.     if (argc != 15) {
  802.         fputs(usage, fout);
  803.         return;
  804.     }
  805.     int is_pointer = strtoul(argv[1], NULL, 0);
  806.     int base = strtoul(argv[2], NULL, 0);
  807.     if (base == 10) base = 0;
  808.     else if (base == 16) base = 1;
  809.     else if (base == 2) base = 2;
  810.     else base = 0;
  811.     size_t digits_to_display = strtoul(argv[3], NULL, 0);
  812.     int is_qword = strtoul(argv[4], NULL, 0);
  813.     int show_leading_zeros = strtoul(argv[5], NULL, 0);
  814.     uintptr_t number_or_pointer = strtoul(argv[6], NULL, 0);
  815.     size_t x = strtoul(argv[7], NULL, 0);
  816.     size_t y = strtoul(argv[8], NULL, 0);
  817.     uint32_t color = strtoul(argv[9], NULL, 16);
  818.     int fill_background = strtoul(argv[10], NULL, 0);
  819.     int font = strtoul(argv[11], NULL, 0);
  820.     int draw_to_buffer = strtoul(argv[12], NULL, 0);
  821.     int scale_factor = strtoul(argv[13], NULL, 0);
  822.     uintptr_t background_color_or_buffer = strtoul(argv[14], NULL, 16);
  823.     COVERAGE_ON();
  824.     umka_sys_display_number(is_pointer, base, digits_to_display, is_qword,
  825.                             show_leading_zeros, number_or_pointer, x, y, color,
  826.                             fill_background, font, draw_to_buffer, scale_factor,
  827.                             background_color_or_buffer);
  828.     COVERAGE_OFF();
  829. }
  830.  
  831. static void
  832. shell_set_window_colors(int argc, char **argv) {
  833.     const char *usage = \
  834.         "usage: set_window_colors <frame> <grab> <work_3d_dark> <work_3d_light>"
  835.             " <grab_text> <work> <work_button> <work_button_text> <work_text>"
  836.             " <work_graph>\n"
  837.         "  *                all colors are in hex";
  838.     if (argc != (1 + sizeof(system_colors_t)/4)) {
  839.         fputs(usage, fout);
  840.         return;
  841.     }
  842.     system_colors_t colors;
  843.     colors.frame            = strtoul(argv[1], NULL, 16);
  844.     colors.grab             = strtoul(argv[2], NULL, 16);
  845.     colors.work_3d_dark     = strtoul(argv[3], NULL, 16);
  846.     colors.work_3d_light    = strtoul(argv[4], NULL, 16);
  847.     colors.grab_text        = strtoul(argv[5], NULL, 16);
  848.     colors.work             = strtoul(argv[6], NULL, 16);
  849.     colors.work_button      = strtoul(argv[7], NULL, 16);
  850.     colors.work_button_text = strtoul(argv[8], NULL, 16);
  851.     colors.work_text        = strtoul(argv[9], NULL, 16);
  852.     colors.work_graph       = strtoul(argv[10], NULL, 16);
  853.     COVERAGE_ON();
  854.     umka_sys_set_window_colors(&colors);
  855.     COVERAGE_OFF();
  856. }
  857.  
  858. static void
  859. shell_get_window_colors(int argc, char **argv) {
  860.     const char *usage = \
  861.         "usage: get_window_colors";
  862.     if (argc != 1) {
  863.         fputs(usage, fout);
  864.         return;
  865.     }
  866.     (void)argv;
  867.     system_colors_t colors;
  868.     memset(&colors, 0xaa, sizeof(colors));
  869.     COVERAGE_ON();
  870.     umka_sys_get_window_colors(&colors);
  871.     COVERAGE_OFF();
  872.     fprintf(fout, "0x%.8" PRIx32 " frame\n", colors.frame);
  873.     fprintf(fout, "0x%.8" PRIx32 " grab\n", colors.grab);
  874.     fprintf(fout, "0x%.8" PRIx32 " work_3d_dark\n", colors.work_3d_dark);
  875.     fprintf(fout, "0x%.8" PRIx32 " work_3d_light\n", colors.work_3d_light);
  876.     fprintf(fout, "0x%.8" PRIx32 " grab_text\n", colors.grab_text);
  877.     fprintf(fout, "0x%.8" PRIx32 " work\n", colors.work);
  878.     fprintf(fout, "0x%.8" PRIx32 " work_button\n", colors.work_button);
  879.     fprintf(fout, "0x%.8" PRIx32 " work_button_text\n",
  880.             colors.work_button_text);
  881.     fprintf(fout, "0x%.8" PRIx32 " work_text\n", colors.work_text);
  882.     fprintf(fout, "0x%.8" PRIx32 " work_graph\n", colors.work_graph);
  883. }
  884.  
  885. static void
  886. shell_get_skin_height(int argc, char **argv) {
  887.     const char *usage = \
  888.         "usage: get_skin_height";
  889.     if (argc != 1) {
  890.         fputs(usage, fout);
  891.         return;
  892.     }
  893.     (void)argv;
  894.     COVERAGE_ON();
  895.     uint32_t skin_height = umka_sys_get_skin_height();
  896.     COVERAGE_OFF();
  897.     fprintf(fout, "%" PRIu32 "\n", skin_height);
  898. }
  899.  
  900. static void
  901. shell_get_screen_area(int argc, char **argv) {
  902.     const char *usage = \
  903.         "usage: get_screen_area";
  904.     if (argc != 1) {
  905.         fputs(usage, fout);
  906.         return;
  907.     }
  908.     (void)argv;
  909.     rect_t wa;
  910.     COVERAGE_ON();
  911.     umka_sys_get_screen_area(&wa);
  912.     COVERAGE_OFF();
  913.     fprintf(fout, "%" PRIu32 " left\n", wa.left);
  914.     fprintf(fout, "%" PRIu32 " top\n", wa.top);
  915.     fprintf(fout, "%" PRIu32 " right\n", wa.right);
  916.     fprintf(fout, "%" PRIu32 " bottom\n", wa.bottom);
  917. }
  918.  
  919. static void
  920. shell_set_screen_area(int argc, char **argv) {
  921.     const char *usage = \
  922.         "usage: set_screen_area <left> <top> <right> <bottom>\n"
  923.         "  left             left x coord\n"
  924.         "  top              top y coord\n"
  925.         "  right            right x coord (not length!)\n"
  926.         "  bottom           bottom y coord";
  927.     if (argc != 5) {
  928.         fputs(usage, fout);
  929.         return;
  930.     }
  931.     rect_t wa;
  932.     wa.left   = strtoul(argv[1], NULL, 0);
  933.     wa.top    = strtoul(argv[2], NULL, 0);
  934.     wa.right  = strtoul(argv[3], NULL, 0);
  935.     wa.bottom = strtoul(argv[4], NULL, 0);
  936.     COVERAGE_ON();
  937.     umka_sys_set_screen_area(&wa);
  938.     COVERAGE_OFF();
  939. }
  940.  
  941. static void
  942. shell_get_skin_margins(int argc, char **argv) {
  943.     const char *usage = \
  944.         "usage: get_skin_margins";
  945.     if (argc != 1) {
  946.         fputs(usage, fout);
  947.         return;
  948.     }
  949.     (void)argv;
  950.     rect_t wa;
  951.     COVERAGE_ON();
  952.     umka_sys_get_skin_margins(&wa);
  953.     COVERAGE_OFF();
  954.     fprintf(fout, "%" PRIu32 " left\n", wa.left);
  955.     fprintf(fout, "%" PRIu32 " top\n", wa.top);
  956.     fprintf(fout, "%" PRIu32 " right\n", wa.right);
  957.     fprintf(fout, "%" PRIu32 " bottom\n", wa.bottom);
  958. }
  959.  
  960. static void
  961. shell_set_button_style(int argc, char **argv) {
  962.     const char *usage = \
  963.         "usage: set_button_style <style>\n"
  964.         "  style            0 - flat, 1 - 3d";
  965.     if (argc != 2) {
  966.         fputs(usage, fout);
  967.         return;
  968.     }
  969.     uint32_t style = strtoul(argv[1], NULL, 0);
  970.     COVERAGE_ON();
  971.     umka_sys_set_button_style(style);
  972.     COVERAGE_OFF();
  973. }
  974.  
  975. static void
  976. shell_set_skin(int argc, char **argv) {
  977.     const char *usage = \
  978.         "usage: set_skin <path>\n"
  979.         "  path             i.e. /rd/1/DEFAULT.SKN";
  980.     if (argc != 2) {
  981.         fputs(usage, fout);
  982.         return;
  983.     }
  984.     const char *path = argv[1];
  985.     COVERAGE_ON();
  986.     int32_t status = umka_sys_set_skin(path);
  987.     COVERAGE_OFF();
  988.     fprintf(fout, "status: %" PRIi32 "\n", status);
  989. }
  990.  
  991. static void
  992. shell_get_font_smoothing(int argc, char **argv) {
  993.     const char *usage = \
  994.         "usage: get_font_smoothing";
  995.     if (argc != 1) {
  996.         fputs(usage, fout);
  997.         return;
  998.     }
  999.     (void)argv;
  1000.     const char *names[] = {"off", "anti-aliasing", "subpixel"};
  1001.     COVERAGE_ON();
  1002.     int type = umka_sys_get_font_smoothing();
  1003.     COVERAGE_OFF();
  1004.     fprintf(fout, "font smoothing: %i - %s\n", type, names[type]);
  1005. }
  1006.  
  1007. static void
  1008. shell_set_font_smoothing(int argc, char **argv) {
  1009.     const char *usage = \
  1010.         "usage: set_font_smoothing <mode>\n"
  1011.         "  mode             0 - off, 1 - gray AA, 2 - subpixel AA";
  1012.     if (argc != 2) {
  1013.         fputs(usage, fout);
  1014.         return;
  1015.     }
  1016.     int type = strtol(argv[1], NULL, 0);
  1017.     COVERAGE_ON();
  1018.     umka_sys_set_font_smoothing(type);
  1019.     COVERAGE_OFF();
  1020. }
  1021.  
  1022. static void
  1023. shell_get_font_size(int argc, char **argv) {
  1024.     const char *usage = \
  1025.         "usage: get_font_size";
  1026.     if (argc != 1) {
  1027.         fputs(usage, fout);
  1028.         return;
  1029.     }
  1030.     (void)argv;
  1031.     COVERAGE_ON();
  1032.     size_t size = umka_sys_get_font_size();
  1033.     COVERAGE_OFF();
  1034.     fprintf(fout, "%upx\n", size);
  1035. }
  1036.  
  1037. static void
  1038. shell_set_font_size(int argc, char **argv) {
  1039.     const char *usage = \
  1040.         "usage: set_font_size <size>\n"
  1041.         "  size             in pixels";
  1042.     if (argc != 2) {
  1043.         fputs(usage, fout);
  1044.         return;
  1045.     }
  1046.     uint32_t size = strtoul(argv[1], NULL, 0);
  1047.     COVERAGE_ON();
  1048.     umka_sys_set_font_size(size);
  1049.     COVERAGE_OFF();
  1050. }
  1051.  
  1052. static void
  1053. shell_button(int argc, char **argv) {
  1054.     const char *usage = \
  1055.         "usage: button <x> <xsize> <y> <ysize> <id> <color> <draw_button>"
  1056.             " <draw_frame>\n"
  1057.         "  x                x\n"
  1058.         "  xsize            may be size-1, check it\n"
  1059.         "  y                y\n"
  1060.         "  ysize            may be size-1, check it\n"
  1061.         "  id               24-bit\n"
  1062.         "  color            hex\n"
  1063.         "  draw_button      0/1\n"
  1064.         "  draw_frame       0/1";
  1065.     if (argc != 9) {
  1066.         fputs(usage, fout);
  1067.         return;
  1068.     }
  1069.     size_t x     = strtoul(argv[1], NULL, 0);
  1070.     size_t xsize = strtoul(argv[2], NULL, 0);
  1071.     size_t y     = strtoul(argv[3], NULL, 0);
  1072.     size_t ysize = strtoul(argv[4], NULL, 0);
  1073.     uint32_t button_id = strtoul(argv[5], NULL, 0);
  1074.     uint32_t color = strtoul(argv[6], NULL, 16);
  1075.     int draw_button = strtoul(argv[7], NULL, 0);
  1076.     int draw_frame = strtoul(argv[8], NULL, 0);
  1077.     COVERAGE_ON();
  1078.     umka_sys_button(x, xsize, y, ysize, button_id, draw_button, draw_frame,
  1079.                     color);
  1080.     COVERAGE_OFF();
  1081. }
  1082.  
  1083. static void
  1084. shell_put_image(int argc, char **argv) {
  1085.     const char *usage = \
  1086.         "usage: put_image <file> <xsize> <ysize> <x> <y>\n"
  1087.         "  file             file with rgb triplets\n"
  1088.         "  xsize            x size\n"
  1089.         "  ysize            y size\n"
  1090.         "  x                x coord\n"
  1091.         "  y                y coord";
  1092.     if (argc != 6) {
  1093.         fputs(usage, fout);
  1094.         return;
  1095.     }
  1096.     FILE *f = fopen(argv[1], "rb");
  1097.     fseek(f, 0, SEEK_END);
  1098.     size_t fsize = ftell(f);
  1099.     rewind(f);
  1100.     uint8_t *image = (uint8_t*)malloc(fsize);
  1101.     fread(image, fsize, 1, f);
  1102.     fclose(f);
  1103.     size_t xsize = strtoul(argv[2], NULL, 0);
  1104.     size_t ysize = strtoul(argv[3], NULL, 0);
  1105.     size_t x = strtoul(argv[4], NULL, 0);
  1106.     size_t y = strtoul(argv[5], NULL, 0);
  1107.     COVERAGE_ON();
  1108.     umka_sys_put_image(image, xsize, ysize, x, y);
  1109.     COVERAGE_OFF();
  1110.     free(image);
  1111. }
  1112.  
  1113. static void
  1114. shell_put_image_palette(int argc, char **argv) {
  1115.     const char *usage = \
  1116.         "usage: put_image_palette <file> <xsize> <ysize> <x> <y> <bpp>"
  1117.             " <row_offset>\n"
  1118.         "  file             path/to/file, contents according tp bpp argument\n"
  1119.         "  xsize            x size\n"
  1120.         "  ysize            y size\n"
  1121.         "  x                x coord\n"
  1122.         "  y                y coord\n"
  1123.         "  bpp              bits per pixel\n"
  1124.         "  row_offset       in bytes";
  1125.     if (argc != 8) {
  1126.         fputs(usage, fout);
  1127.         return;
  1128.     }
  1129.     FILE *f = fopen(argv[1], "rb");
  1130.     fseek(f, 0, SEEK_END);
  1131.     size_t fsize = ftell(f);
  1132.     rewind(f);
  1133.     uint8_t *image = (uint8_t*)malloc(fsize);
  1134.     fread(image, fsize, 1, f);
  1135.     fclose(f);
  1136.     size_t xsize = strtoul(argv[2], NULL, 0);
  1137.     size_t ysize = strtoul(argv[3], NULL, 0);
  1138.     size_t x = strtoul(argv[4], NULL, 0);
  1139.     size_t y = strtoul(argv[5], NULL, 0);
  1140.     size_t bpp = strtoul(argv[6], NULL, 0);
  1141.     void *palette = NULL;
  1142.     size_t row_offset = strtoul(argv[7], NULL, 0);
  1143.     COVERAGE_ON();
  1144.     umka_sys_put_image_palette(image, xsize, ysize, x, y, bpp, palette,
  1145.                                row_offset);
  1146.     COVERAGE_OFF();
  1147.     free(image);
  1148. }
  1149.  
  1150. static void
  1151. shell_draw_rect(int argc, char **argv) {
  1152.     const char *usage = \
  1153.         "usage: draw_rect <x> <xsize> <y> <ysize> <color> [-g]\n"
  1154.         "  x                x coord\n"
  1155.         "  xsize            x size\n"
  1156.         "  y                y coord\n"
  1157.         "  ysize            y size\n"
  1158.         "  color            in hex\n"
  1159.         "  -g               0/1 - gradient";
  1160.     if (argc < 6) {
  1161.         fputs(usage, fout);
  1162.         return;
  1163.     }
  1164.     size_t x     = strtoul(argv[1], NULL, 0);
  1165.     size_t xsize = strtoul(argv[2], NULL, 0);
  1166.     size_t y     = strtoul(argv[3], NULL, 0);
  1167.     size_t ysize = strtoul(argv[4], NULL, 0);
  1168.     uint32_t color = strtoul(argv[5], NULL, 16);
  1169.     int gradient = (argc == 7) && !strcmp(argv[6], "-g");
  1170.     COVERAGE_ON();
  1171.     umka_sys_draw_rect(x, xsize, y, ysize, color, gradient);
  1172.     COVERAGE_OFF();
  1173. }
  1174.  
  1175. static void
  1176. shell_get_screen_size(int argc, char **argv) {
  1177.     const char *usage = \
  1178.         "usage: get_screen_size";
  1179.     if (argc != 1) {
  1180.         fputs(usage, fout);
  1181.         return;
  1182.     }
  1183.     (void)argv;
  1184.     uint32_t xsize, ysize;
  1185.     COVERAGE_ON();
  1186.     umka_sys_get_screen_size(&xsize, &ysize);
  1187.     COVERAGE_OFF();
  1188.     fprintf(fout, "%" PRIu32 "x%" PRIu32 "\n", xsize, ysize);
  1189. }
  1190.  
  1191. static void
  1192. shell_draw_line(int argc, char **argv) {
  1193.     const char *usage = \
  1194.         "usage: draw_line <xbegin> <xend> <ybegin> <yend> <color> [-i]\n"
  1195.         "  xbegin           x left coord\n"
  1196.         "  xend             x right coord\n"
  1197.         "  ybegin           y top coord\n"
  1198.         "  yend             y bottom coord\n"
  1199.         "  color            hex\n"
  1200.         "  -i               inverted color";
  1201.     if (argc < 6) {
  1202.         fputs(usage, fout);
  1203.         return;
  1204.     }
  1205.     size_t x    = strtoul(argv[1], NULL, 0);
  1206.     size_t xend = strtoul(argv[2], NULL, 0);
  1207.     size_t y    = strtoul(argv[3], NULL, 0);
  1208.     size_t yend = strtoul(argv[4], NULL, 0);
  1209.     uint32_t color = strtoul(argv[5], NULL, 16);
  1210.     int invert = (argc == 7) && !strcmp(argv[6], "-i");
  1211.     COVERAGE_ON();
  1212.     umka_sys_draw_line(x, xend, y, yend, color, invert);
  1213.     COVERAGE_OFF();
  1214. }
  1215.  
  1216. static void
  1217. shell_set_window_caption(int argc, char **argv) {
  1218.     const char *usage = \
  1219.         "usage: set_window_caption <caption> <encoding>\n"
  1220.         "  caption          asciiz string\n"
  1221.         "  encoding         1 = cp866, 2 = UTF-16LE, 3 = UTF-8";
  1222.     if (argc != 3) {
  1223.         fputs(usage, fout);
  1224.         return;
  1225.     }
  1226.     const char *caption = argv[1];
  1227.     int encoding = strtoul(argv[2], NULL, 0);
  1228.     COVERAGE_ON();
  1229.     umka_sys_set_window_caption(caption, encoding);
  1230.     COVERAGE_OFF();
  1231. }
  1232.  
  1233. static void
  1234. shell_draw_window(int argc, char **argv) {
  1235.     const char *usage = \
  1236.         "usage: draw_window <x> <xsize> <y> <ysize> <color> <has_caption>"
  1237.             " <client_relative> <fill_workarea> <gradient_fill> <movable>"
  1238.             " <style> <caption>\n"
  1239.         "  x                x coord\n"
  1240.         "  xsize            x size\n"
  1241.         "  y                y coord\n"
  1242.         "  ysize            y size\n"
  1243.         "  color            hex\n"
  1244.         "  has_caption      0/1\n"
  1245.         "  client_relative  0/1\n"
  1246.         "  fill_workarea    0/1\n"
  1247.         "  gradient_fill    0/1\n"
  1248.         "  movable          0/1\n"
  1249.         "  style            1 - draw nothing, 3 - skinned, 4 - skinned fixed\n"
  1250.         "  caption          asciiz";
  1251.     if (argc != 13) {
  1252.         fputs(usage, fout);
  1253.         return;
  1254.     }
  1255.     size_t x     = strtoul(argv[1], NULL, 0);
  1256.     size_t xsize = strtoul(argv[2], NULL, 0);
  1257.     size_t y     = strtoul(argv[3], NULL, 0);
  1258.     size_t ysize = strtoul(argv[4], NULL, 0);
  1259.     uint32_t color = strtoul(argv[5], NULL, 16);
  1260.     int has_caption = strtoul(argv[6], NULL, 0);
  1261.     int client_relative = strtoul(argv[7], NULL, 0);
  1262.     int fill_workarea = strtoul(argv[8], NULL, 0);
  1263.     int gradient_fill = strtoul(argv[9], NULL, 0);
  1264.     int movable = strtoul(argv[10], NULL, 0);
  1265.     int style = strtoul(argv[11], NULL, 0);
  1266.     const char *caption = argv[12];
  1267.     COVERAGE_ON();
  1268.     umka_sys_draw_window(x, xsize, y, ysize, color, has_caption,
  1269.                          client_relative, fill_workarea, gradient_fill, movable,
  1270.                          style, caption);
  1271.     COVERAGE_OFF();
  1272. }
  1273.  
  1274. static void
  1275. shell_window_redraw(int argc, char **argv) {
  1276.     const char *usage = \
  1277.         "usage: window_redraw <1|2>\n"
  1278.         "  1                begin\n"
  1279.         "  2                end";
  1280.     if (argc != 2) {
  1281.         fputs(usage, fout);
  1282.         return;
  1283.     }
  1284.     int begin_end = strtoul(argv[1], NULL, 0);
  1285.     COVERAGE_ON();
  1286.     umka_sys_window_redraw(begin_end);
  1287.     COVERAGE_OFF();
  1288. }
  1289.  
  1290. static void
  1291. shell_move_window(int argc, char **argv) {
  1292.     const char *usage = \
  1293.         "usage: move_window <x> <y> <xsize> <ysize>\n"
  1294.         "  x                new x coord\n"
  1295.         "  y                new y coord\n"
  1296.         "  xsize            x size -1\n"
  1297.         "  ysize            y size -1";
  1298.     if (argc != 5) {
  1299.         fputs(usage, fout);
  1300.         return;
  1301.     }
  1302.     size_t x      = strtoul(argv[1], NULL, 0);
  1303.     size_t y      = strtoul(argv[2], NULL, 0);
  1304.     ssize_t xsize = strtol(argv[3], NULL, 0);
  1305.     ssize_t ysize = strtol(argv[4], NULL, 0);
  1306.     COVERAGE_ON();
  1307.     umka_sys_move_window(x, y, xsize, ysize);
  1308.     COVERAGE_OFF();
  1309. }
  1310.  
  1311. static void
  1312. shell_blit_bitmap(int argc, char **argv) {
  1313.     const char *usage = \
  1314.         "usage: blit_bitmap <dstx> <dsty> <dstxsize> <dstysize> <srcx> <srcy>"
  1315.             " <srcxsize> <srcysize> <operation> <background> <transparent>"
  1316.             " <client_relative> <row_length>\n"
  1317.         "  dstx             dst rect x offset, window-relative\n"
  1318.         "  dsty             dst rect y offset, window-relative\n"
  1319.         "  dstxsize         dst rect width\n"
  1320.         "  dstysize         dst rect height\n"
  1321.         "  srcx             src rect x offset, window-relative\n"
  1322.         "  srcy             src rect y offset, window-relative\n"
  1323.         "  srcxsize         src rect width\n"
  1324.         "  srcysize         src rect height\n"
  1325.         "  operation        0 - copy\n"
  1326.         "  background       0/1 - blit into background surface\n"
  1327.         "  transparent      0/1\n"
  1328.         "  client_relative  0/1\n"
  1329.         "  row_length       in bytes";
  1330.     if (argc != 15) {
  1331.         fputs(usage, fout);
  1332.         return;
  1333.     }
  1334.     const char *fname = argv[1];
  1335.     FILE *f = fopen(fname, "rb");
  1336.     if (!f) {
  1337.         fprintf(fout, "[!] can't open file '%s': %s\n", fname, strerror(errno));
  1338.         return;
  1339.     }
  1340.     fseek(f, 0, SEEK_END);
  1341.     size_t fsize = ftell(f);
  1342.     rewind(f);
  1343.     uint8_t *image = (uint8_t*)malloc(fsize);
  1344.     fread(image, fsize, 1, f);
  1345.     fclose(f);
  1346.     size_t dstx     = strtoul(argv[2], NULL, 0);
  1347.     size_t dsty     = strtoul(argv[3], NULL, 0);
  1348.     size_t dstxsize = strtoul(argv[4], NULL, 0);
  1349.     size_t dstysize = strtoul(argv[5], NULL, 0);
  1350.     size_t srcx     = strtoul(argv[6], NULL, 0);
  1351.     size_t srcy     = strtoul(argv[7], NULL, 0);
  1352.     size_t srcxsize = strtoul(argv[8], NULL, 0);
  1353.     size_t srcysize = strtoul(argv[9], NULL, 0);
  1354.     int operation   = strtoul(argv[10], NULL, 0);
  1355.     int background  = strtoul(argv[11], NULL, 0);
  1356.     int transparent = strtoul(argv[12], NULL, 0);
  1357.     int client_relative = strtoul(argv[13], NULL, 0);
  1358.     int row_length = strtoul(argv[14], NULL, 0);
  1359.     uint32_t params[] = {dstx, dsty, dstxsize, dstysize, srcx, srcy, srcxsize,
  1360.                          srcysize, (uintptr_t)image, row_length};
  1361.     COVERAGE_ON();
  1362.     umka_sys_blit_bitmap(operation, background, transparent, client_relative,
  1363.                          params);
  1364.     COVERAGE_OFF();
  1365.     free(image);
  1366. }
  1367.  
  1368. static void
  1369. shell_scrot(int argc, char **argv) {
  1370.     const char *usage = \
  1371.         "usage: scrot <file>\n"
  1372.         "  file             path/to/file in png format";
  1373.     if (argc != 2) {
  1374.         fputs(usage, fout);
  1375.         return;
  1376.     }
  1377.     uint32_t xsize, ysize;
  1378.     COVERAGE_ON();
  1379.     umka_sys_get_screen_size(&xsize, &ysize);
  1380.     COVERAGE_OFF();
  1381.  
  1382.     uint32_t *lfb = (uint32_t*)kos_lfb_base;    // assume 32bpp
  1383.     for (size_t y = 0; y < ysize; y++) {
  1384.         for (size_t x = 0; x < xsize; x++) {
  1385.             *lfb++ |= 0xff000000;
  1386.         }
  1387.     }
  1388.  
  1389.     unsigned error = lodepng_encode32_file(argv[1], kos_lfb_base, xsize, ysize);
  1390.     if(error) fprintf(fout, "error %u: %s\n", error, lodepng_error_text(error));
  1391. }
  1392.  
  1393. static void
  1394. shell_cd(int argc, char **argv) {
  1395.     const char *usage = \
  1396.         "usage: cd <path>\n"
  1397.         "  path             path/to/dir";
  1398.     if (argc != 2) {
  1399.         fputs(usage, fout);
  1400.         return;
  1401.     }
  1402.     COVERAGE_ON();
  1403.     umka_sys_set_cwd(argv[1]);
  1404.     COVERAGE_OFF();
  1405.     cur_dir_changed = true;
  1406. }
  1407.  
  1408. static void
  1409. ls_range(f7080s1arg_t *fX0, f70or80_t f70or80) {
  1410.     f7080ret_t r;
  1411.     size_t bdfe_len = (fX0->encoding == CP866) ? BDFE_LEN_CP866 :
  1412.                                                  BDFE_LEN_UNICODE;
  1413.     uint32_t requested = fX0->size;
  1414.     if (fX0->size > MAX_DIRENTS_TO_READ) {
  1415.         fX0->size = MAX_DIRENTS_TO_READ;
  1416.     }
  1417.     for (; requested; requested -= fX0->size) {
  1418.         if (fX0->size > requested) {
  1419.             fX0->size = requested;
  1420.         }
  1421.         COVERAGE_ON();
  1422.         umka_sys_lfn(fX0, &r, f70or80);
  1423.         COVERAGE_OFF();
  1424.         fX0->offset += fX0->size;
  1425.         print_f70_status(&r, 1);
  1426.         f7080s1info_t *dir = fX0->buf;
  1427.         int ok = (r.count <= fX0->size);
  1428.         ok &= (dir->cnt == r.count);
  1429.         ok &= (r.status == ERROR_SUCCESS && r.count == fX0->size)
  1430.               || (r.status == ERROR_END_OF_FILE && r.count < fX0->size);
  1431.         assert(ok);
  1432.         if (!ok)
  1433.             break;
  1434.         bdfe_t *bdfe = dir->bdfes;
  1435.         for (size_t i = 0; i < dir->cnt; i++) {
  1436.             char fattr[KF_ATTR_CNT+1];
  1437.             convert_f70_file_attr(bdfe->attr, fattr);
  1438.             fprintf(fout, "%s %s\n", fattr, bdfe->name);
  1439.             bdfe = (bdfe_t*)((uintptr_t)bdfe + bdfe_len);
  1440.         }
  1441.         if (r.status == ERROR_END_OF_FILE) {
  1442.             break;
  1443.         }
  1444.     }
  1445. }
  1446.  
  1447. static void
  1448. ls_all(f7080s1arg_t *fX0, f70or80_t f70or80) {
  1449.     f7080ret_t r;
  1450.     size_t bdfe_len = (fX0->encoding == CP866) ? BDFE_LEN_CP866 :
  1451.                                                  BDFE_LEN_UNICODE;
  1452.     while (true) {
  1453.         COVERAGE_ON();
  1454.         umka_sys_lfn(fX0, &r, f70or80);
  1455.         COVERAGE_OFF();
  1456.         print_f70_status(&r, 1);
  1457.         assert((r.status == ERROR_SUCCESS && r.count == fX0->size)
  1458.               || (r.status == ERROR_END_OF_FILE && r.count < fX0->size));
  1459.         f7080s1info_t *dir = fX0->buf;
  1460.         fX0->offset += dir->cnt;
  1461.         int ok = (r.count <= fX0->size);
  1462.         ok &= (dir->cnt == r.count);
  1463.         ok &= (r.status == ERROR_SUCCESS && r.count == fX0->size)
  1464.               || (r.status == ERROR_END_OF_FILE && r.count < fX0->size);
  1465.         assert(ok);
  1466.         if (!ok)
  1467.             break;
  1468.         fprintf(fout, "total = %"PRIi32"\n", dir->total_cnt);
  1469.         bdfe_t *bdfe = dir->bdfes;
  1470.         for (size_t i = 0; i < dir->cnt; i++) {
  1471.             char fattr[KF_ATTR_CNT+1];
  1472.             convert_f70_file_attr(bdfe->attr, fattr);
  1473.             fprintf(fout, "%s %s\n", fattr, bdfe->name);
  1474.             bdfe = (bdfe_t*)((uintptr_t)bdfe + bdfe_len);
  1475.         }
  1476.         if (r.status == ERROR_END_OF_FILE) {
  1477.             break;
  1478.         }
  1479.     }
  1480. }
  1481.  
  1482. static fs_enc_t
  1483. parse_encoding(const char *str) {
  1484.     fs_enc_t enc;
  1485.     if (!strcmp(str, "default")) {
  1486.         enc = DEFAULT_ENCODING;
  1487.     } else if (!strcmp(str, "cp866")) {
  1488.         enc = CP866;
  1489.     } else if (!strcmp(str, "utf16")) {
  1490.         enc = UTF16;
  1491.     } else if (!strcmp(str, "utf8")) {
  1492.         enc = UTF8;
  1493.     } else {
  1494.         enc = INVALID_ENCODING;
  1495.     }
  1496.     return enc;
  1497. }
  1498.  
  1499. static void
  1500. shell_exec(int argc, char **argv) {
  1501.     const char *usage = \
  1502.         "usage: exec <file>\n"
  1503.         "  file           executable to run";
  1504.     if (!argc) {
  1505.         fputs(usage, fout);
  1506.         return;
  1507.     }
  1508.     f7080s7arg_t fX0 = {.sf = 7};
  1509.     f7080ret_t r;
  1510.     int opt = 1;
  1511.     fX0.u.f70.zero = 0;
  1512.     fX0.u.f70.path = argv[opt++];
  1513.     fX0.flags = 0;
  1514.     fX0.params = "test";
  1515.  
  1516.     COVERAGE_ON();
  1517.     umka_sys_lfn(&fX0, &r, F70);
  1518.     COVERAGE_OFF();
  1519.     if (r.status < 0) {
  1520.         r.status = -r.status;
  1521.     } else {
  1522.         fprintf(fout, "pid: %" PRIu32 "\n", r.status);
  1523.         r.status = 0;
  1524.     }
  1525.     print_f70_status(&r, 1);
  1526. }
  1527.  
  1528. static void
  1529. shell_ls(int argc, char **argv, const char *usage, f70or80_t f70or80) {
  1530.     if (!argc) {
  1531.         fputs(usage, fout);
  1532.         return;
  1533.     }
  1534.     int opt;
  1535.     optind = 1;
  1536.     const char *optstring = (f70or80 == F70) ? "f:c:e:" : "f:c:e:p:";
  1537.     const char *path = ".";
  1538.     uint32_t readdir_enc = DEFAULT_READDIR_ENCODING;
  1539.     uint32_t path_enc = DEFAULT_PATH_ENCODING;
  1540.     uint32_t from_idx = 0, count = MAX_DIRENTS_TO_READ;
  1541.     if (argc > 1 && *argv[optind] != '-') {
  1542.         path = argv[optind++];
  1543.     }
  1544.     while ((opt = getopt(argc, argv, optstring)) != -1) {
  1545.         switch (opt) {
  1546.         case 'f':
  1547.             from_idx = strtoul(optarg, NULL, 0);
  1548.             break;
  1549.         case 'c':
  1550.             count = strtoul(optarg, NULL, 0);
  1551.             break;
  1552.         case 'e':
  1553.             readdir_enc = parse_encoding(optarg);
  1554.             break;
  1555.         case 'p':
  1556.             path_enc = parse_encoding(optarg);
  1557.             break;
  1558.         default:
  1559.             fputs(usage, fout);
  1560.             return;
  1561.         }
  1562.     }
  1563.  
  1564.     size_t bdfe_len = (readdir_enc <= CP866) ? BDFE_LEN_CP866 :
  1565.                                                BDFE_LEN_UNICODE;
  1566.     f7080s1info_t *dir = (f7080s1info_t*)malloc(sizeof(f7080s1info_t) +
  1567.                                                 bdfe_len * MAX_DIRENTS_TO_READ);
  1568.     f7080s1arg_t fX0 = {.sf = 1, .offset = from_idx, .encoding = readdir_enc,
  1569.                         .size = count, .buf = dir};
  1570.     if (f70or80 == F70) {
  1571.         fX0.u.f70.zero = 0;
  1572.         fX0.u.f70.path = path;
  1573.     } else {
  1574.         fX0.u.f80.path_encoding = path_enc;
  1575.         fX0.u.f80.path = path;
  1576.     }
  1577.     if (count != MAX_DIRENTS_TO_READ) {
  1578.         ls_range(&fX0, f70or80);
  1579.     } else {
  1580.         ls_all(&fX0, f70or80);
  1581.     }
  1582.     free(dir);
  1583.     return;
  1584. }
  1585.  
  1586. static void
  1587. shell_ls70(int argc, char **argv) {
  1588.     const char *usage = \
  1589.         "usage: ls70 [dir] [option]...\n"
  1590.         "  -f number        index of the first dir entry to read\n"
  1591.         "  -c number        number of dir entries to read\n"
  1592.         "  -e encoding      cp866|utf16|utf8\n"
  1593.         "                   return directory listing in this encoding";
  1594.     shell_ls(argc, argv, usage, F70);
  1595. }
  1596.  
  1597. static void
  1598. shell_ls80(int argc, char **argv) {
  1599.     const char *usage = \
  1600.         "usage: ls80 [dir] [option]...\n"
  1601.         "  -f number        index of the first dir entry to read\n"
  1602.         "  -c number        number of dir entries to read\n"
  1603.         "  -e encoding      cp866|utf16|utf8\n"
  1604.         "                   return directory listing in this encoding\n"
  1605.         "  -p encoding      cp866|utf16|utf8\n"
  1606.         "                   path to dir is specified in this encoding";
  1607.     shell_ls(argc, argv, usage, F80);
  1608. }
  1609.  
  1610. static void
  1611. shell_stat(int argc, char **argv, f70or80_t f70or80) {
  1612.     const char *usage = \
  1613.         "usage: stat <file>\n"
  1614.         "  file             path/to/file";
  1615.     if (argc != 2) {
  1616.         fputs(usage, fout);
  1617.         return;
  1618.     }
  1619.     f7080s5arg_t fX0 = {.sf = 5, .flags = 0};
  1620.     f7080ret_t r;
  1621.     bdfe_t file;
  1622.     fX0.buf = &file;
  1623.     if (f70or80 == F70) {
  1624.         fX0.u.f70.zero = 0;
  1625.         fX0.u.f70.path = argv[1];
  1626.     } else {
  1627.         fX0.u.f80.path_encoding = DEFAULT_PATH_ENCODING;
  1628.         fX0.u.f80.path = argv[1];
  1629.     }
  1630.     COVERAGE_ON();
  1631.     umka_sys_lfn(&fX0, &r, f70or80);
  1632.     COVERAGE_OFF();
  1633.     print_f70_status(&r, 0);
  1634.     if (r.status != ERROR_SUCCESS)
  1635.         return;
  1636.     char fattr[KF_ATTR_CNT+1];
  1637.     convert_f70_file_attr(file.attr, fattr);
  1638.     fprintf(fout, "attr: %s\n", fattr);
  1639.     if ((file.attr & KF_FOLDER) == 0) {   // don't show size for dirs
  1640.         fprintf(fout, "size: %llu\n", file.size);
  1641.     }
  1642.  
  1643. #if PRINT_DATE_TIME == 1    // TODO: runtime, argv flag
  1644.     time_t time;
  1645.     struct tm *t;
  1646.     time = kos_time_to_epoch(&file.ctime);
  1647.     t = localtime(&time);
  1648.     fprintf(fout, "ctime: %4.4i.%2.2i.%2.2i %2.2i:%2.2i:%2.2i\n",
  1649.            t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
  1650.            t->tm_hour, t->tm_min, t->tm_sec);
  1651.     time = kos_time_to_epoch(&file.atime);
  1652.     t = localtime(&time);
  1653.     fprintf(fout, "atime: %4.4i.%2.2i.%2.2i %2.2i:%2.2i:%2.2i\n",
  1654.            t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
  1655.            t->tm_hour, t->tm_min, t->tm_sec);
  1656.     time = kos_time_to_epoch(&file.mtime);
  1657.     t = localtime(&time);
  1658.     fprintf(fout, "mtime: %4.4i.%2.2i.%2.2i %2.2i:%2.2i:%2.2i\n",
  1659.            t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
  1660.            t->tm_hour, t->tm_min, t->tm_sec);
  1661. #endif
  1662.     return;
  1663. }
  1664.  
  1665. static void
  1666. shell_stat70(int argc, char **argv) {
  1667.     shell_stat(argc, argv, F70);
  1668. }
  1669.  
  1670. static void
  1671. shell_stat80(int argc, char **argv) {
  1672.     shell_stat(argc, argv, F80);
  1673. }
  1674.  
  1675. static void
  1676. shell_read(int argc, char **argv, f70or80_t f70or80, const char *usage) {
  1677.     if (argc < 3) {
  1678.         fputs(usage, fout);
  1679.         return;
  1680.     }
  1681.     f7080s0arg_t fX0 = {.sf = 0};
  1682.     f7080ret_t r;
  1683.     bool dump_bytes = false, dump_hash = false;
  1684.     int opt = 1;
  1685.     if (f70or80 == F70) {
  1686.         fX0.u.f70.zero = 0;
  1687.         fX0.u.f70.path = argv[opt++];
  1688.     } else {
  1689.         fX0.u.f80.path_encoding = DEFAULT_PATH_ENCODING;
  1690.         fX0.u.f80.path = argv[opt++];
  1691.     }
  1692.     if ((opt >= argc) || !parse_uint64(argv[opt++], &fX0.offset))
  1693.         return;
  1694.     if ((opt >= argc) || !parse_uint32(argv[opt++], &fX0.count))
  1695.         return;
  1696.     for (; opt < argc; opt++) {
  1697.         if (!strcmp(argv[opt], "-b")) {
  1698.             dump_bytes = true;
  1699.         } else if (!strcmp(argv[opt], "-h")) {
  1700.             dump_hash = true;
  1701.         } else if (!strcmp(argv[opt], "-e")) {
  1702.             if (f70or80 == F70) {
  1703.                 fprintf(fout, "f70 doesn't accept encoding parameter,"
  1704.                         " use f80\n");
  1705.                 return;
  1706.             }
  1707.         } else {
  1708.             fprintf(fout, "invalid option: '%s'\n", argv[opt]);
  1709.             return;
  1710.         }
  1711.     }
  1712.     fX0.buf = (uint8_t*)malloc(fX0.count);
  1713.  
  1714.     COVERAGE_ON();
  1715.     umka_sys_lfn(&fX0, &r, f70or80);
  1716.     COVERAGE_OFF();
  1717.  
  1718.     print_f70_status(&r, 1);
  1719.     if (r.status == ERROR_SUCCESS || r.status == ERROR_END_OF_FILE) {
  1720.         if (dump_bytes)
  1721.             print_bytes(fX0.buf, r.count);
  1722.         if (dump_hash)
  1723.             print_hash(fX0.buf, r.count);
  1724.     }
  1725.  
  1726.     free(fX0.buf);
  1727.     return;
  1728. }
  1729.  
  1730. static void
  1731. shell_read70(int argc, char **argv) {
  1732.     const char *usage = \
  1733.         "usage: read70 <file> <offset> <length> [-b] [-h]\n"
  1734.         "  file             path/to/file\n"
  1735.         "  offset           in bytes\n"
  1736.         "  length           in bytes\n"
  1737.         "  -b               dump bytes in hex\n"
  1738.         "  -h               print hash of data read";
  1739.  
  1740.     shell_read(argc, argv, F70, usage);
  1741. }
  1742.  
  1743. static void
  1744. shell_read80(int argc, char **argv) {
  1745.     const char *usage = \
  1746.         "usage: read80 <file> <offset> <length> [-b] [-h]"
  1747.             " [-e cp866|utf8|utf16]\n"
  1748.         "  file             path/to/file\n"
  1749.         "  offset           in bytes\n"
  1750.         "  length           in bytes\n"
  1751.         "  -b               dump bytes in hex\n"
  1752.         "  -h               print hash of data read\n"
  1753.         "  -e               encoding";
  1754.     shell_read(argc, argv, F80, usage);
  1755. }
  1756.  
  1757. static void
  1758. shell_acpi_preload_table(int argc, char **argv) {
  1759.     const char *usage = \
  1760.         "usage: acpi_preload_table <file>\n"
  1761.         "  file             path/to/local/file.aml";
  1762.     if (argc != 2) {
  1763.         fputs(usage, fout);
  1764.         return;
  1765.     }
  1766.     FILE *f = fopen(argv[1], "rb");
  1767.     if (!f) {
  1768.         fprintf(fout, "[umka] can't open file: %s\n", argv[1]);
  1769.         return;
  1770.     }
  1771.     fseek(f, 0, SEEK_END);
  1772.     size_t fsize = ftell(f);
  1773.     rewind(f);
  1774.     uint8_t *table = (uint8_t*)malloc(fsize);
  1775.     fread(table, fsize, 1, f);
  1776.     fclose(f);
  1777.     fprintf(fout, "table #%zu\n", kos_acpi_ssdt_cnt);
  1778.     kos_acpi_ssdt_base[kos_acpi_ssdt_cnt] = table;
  1779.     kos_acpi_ssdt_size[kos_acpi_ssdt_cnt] = fsize;
  1780.     kos_acpi_ssdt_cnt++;
  1781. }
  1782.  
  1783. static void
  1784. shell_bg_set_size(int argc, char **argv) {
  1785.     const char *usage = \
  1786.         "usage: bg_set_size <xsize> <ysize>\n"
  1787.         "  xsize          in pixels\n"
  1788.         "  ysize          in pixels";
  1789.     if (argc != 3) {
  1790.         fputs(usage, fout);
  1791.         return;
  1792.     }
  1793.     uint32_t xsize = strtoul(argv[1], NULL, 0);
  1794.     uint32_t ysize = strtoul(argv[2], NULL, 0);
  1795.     umka_sys_bg_set_size(xsize, ysize);
  1796. }
  1797.  
  1798. static void
  1799. shell_bg_put_pixel(int argc, char **argv) {
  1800.     const char *usage = \
  1801.         "usage: bg_put_pixel <offset> <color>\n"
  1802.         "  offset         in bytes, (x+y*xsize)*3\n"
  1803.         "  color          in hex";
  1804.     if (argc != 3) {
  1805.         fputs(usage, fout);
  1806.         return;
  1807.     }
  1808.     size_t offset = strtoul(argv[1], NULL, 0);
  1809.     uint32_t color = strtoul(argv[2], NULL, 0);
  1810.     umka_sys_bg_put_pixel(offset, color);
  1811. }
  1812.  
  1813. static void
  1814. shell_bg_redraw(int argc, char **argv) {
  1815.     (void)argv;
  1816.     const char *usage = \
  1817.         "usage: bg_redraw";
  1818.     if (argc != 1) {
  1819.         fputs(usage, fout);
  1820.         return;
  1821.     }
  1822.     umka_sys_bg_redraw();
  1823. }
  1824.  
  1825. static void
  1826. shell_bg_set_mode(int argc, char **argv) {
  1827.     const char *usage = \
  1828.         "usage: bg_set_mode <mode>\n"
  1829.         "  mode           1 = tile, 2 = stretch";
  1830.     if (argc != 3) {
  1831.         fputs(usage, fout);
  1832.         return;
  1833.     }
  1834.     uint32_t mode = strtoul(argv[1], NULL, 0);
  1835.     umka_sys_bg_set_mode(mode);
  1836. }
  1837.  
  1838. static void
  1839. shell_bg_put_img(int argc, char **argv) {
  1840.     const char *usage = \
  1841.         "usage: bg_put_img <image> <offset>\n"
  1842.         "  image          file\n"
  1843.         "  offset         in bytes, (x+y*xsize)*3\n";
  1844.     if (argc != 4) {
  1845.         fputs(usage, fout);
  1846.         return;
  1847.     }
  1848.     FILE *f = fopen(argv[1], "rb");
  1849.     fseek(f, 0, SEEK_END);
  1850.     size_t fsize = ftell(f);
  1851.     rewind(f);
  1852.     uint8_t *image = (uint8_t*)malloc(fsize);
  1853.     fread(image, fsize, 1, f);
  1854.     fclose(f);
  1855.     size_t offset = strtoul(argv[2], NULL, 0);
  1856.     umka_sys_bg_put_img(image, offset, fsize);
  1857. }
  1858.  
  1859. static void
  1860. shell_bg_map(int argc, char **argv) {
  1861.     (void)argv;
  1862.     const char *usage = \
  1863.         "usage: bg_map";
  1864.     if (argc != 1) {
  1865.         fputs(usage, fout);
  1866.         return;
  1867.     }
  1868.     void *addr = umka_sys_bg_map();
  1869.     fprintf(fout, "%p\n", addr);
  1870. }
  1871.  
  1872. static void
  1873. shell_bg_unmap(int argc, char **argv) {
  1874.     const char *usage = \
  1875.         "usage: bg_unmap <addr>\n"
  1876.         "  addr           return value of bg_map";
  1877.     if (argc != 2) {
  1878.         fputs(usage, fout);
  1879.         return;
  1880.     }
  1881.     void *addr = (void*)strtoul(argv[1], NULL, 0);
  1882.     uint32_t status = umka_sys_bg_unmap(addr);
  1883.     fprintf(fout, "status = %d\n", status);
  1884. }
  1885.  
  1886. static void shell_help(int argc, char **argv);
  1887.  
  1888. func_table_t shell_cmds[] = {
  1889.     { "umka_init",               shell_umka_init },
  1890.     { "umka_set_boot_params",    shell_umka_set_boot_params },
  1891.     { "acpi_preload_table",      shell_acpi_preload_table },
  1892.     { "bg_map",                  shell_bg_map },
  1893.     { "bg_put_img",              shell_bg_put_img },
  1894.     { "bg_put_pixel",            shell_bg_put_pixel },
  1895.     { "bg_redraw",               shell_bg_redraw },
  1896.     { "bg_set_mode",             shell_bg_set_mode },
  1897.     { "bg_set_size",             shell_bg_set_size },
  1898.     { "bg_unmap",                shell_bg_unmap },
  1899.     { "blit_bitmap",             shell_blit_bitmap },
  1900.     { "button",                  shell_button },
  1901.     { "cd",                      shell_cd },
  1902.     { "set",                     shell_set },
  1903.     { "disk_add",                shell_disk_add },
  1904.     { "disk_del",                shell_disk_del },
  1905.     { "display_number",          shell_display_number },
  1906.     { "draw_line",               shell_draw_line },
  1907.     { "draw_rect",               shell_draw_rect },
  1908.     { "draw_window",             shell_draw_window },
  1909.     { "dump_appdata",            shell_dump_appdata },
  1910.     { "dump_taskdata",           shell_dump_taskdata },
  1911.     { "dump_win_pos",            shell_dump_win_pos },
  1912.     { "dump_win_stack",          shell_dump_win_stack },
  1913.     { "dump_win_map",            shell_dump_win_map },
  1914.     { "exec",                    shell_exec },
  1915.     { "get_font_size",           shell_get_font_size },
  1916.     { "get_font_smoothing",      shell_get_font_smoothing },
  1917.     { "get_screen_area",         shell_get_screen_area },
  1918.     { "get_screen_size",         shell_get_screen_size },
  1919.     { "get_skin_height",         shell_get_skin_height },
  1920.     { "get_skin_margins",        shell_get_skin_margins },
  1921.     { "get_window_colors",       shell_get_window_colors },
  1922.     { "help",                    shell_help },
  1923.     { "i40",                     shell_i40 },
  1924.     { "ls70",                    shell_ls70 },
  1925.     { "ls80",                    shell_ls80 },
  1926.     { "move_window",             shell_move_window },
  1927.     { "mouse_move",              shell_mouse_move },
  1928.     { "process_info",            shell_process_info },
  1929.     { "put_image",               shell_put_image },
  1930.     { "put_image_palette",       shell_put_image_palette },
  1931.     { "pwd",                     shell_pwd },
  1932.     { "ramdisk_init",            shell_ramdisk_init },
  1933.     { "read70",                  shell_read70 },
  1934.     { "read80",                  shell_read80 },
  1935.     { "scrot",                   shell_scrot },
  1936.     { "set_button_style",        shell_set_button_style },
  1937.     { "set_cwd",                 shell_cd },
  1938.     { "set_font_size",           shell_set_font_size },
  1939.     { "set_font_smoothing",      shell_set_font_smoothing },
  1940.     { "set_pixel",               shell_set_pixel },
  1941.     { "set_screen_area",         shell_set_screen_area },
  1942.     { "set_skin",                shell_set_skin },
  1943.     { "set_window_caption",      shell_set_window_caption },
  1944.     { "set_window_colors",       shell_set_window_colors },
  1945.     { "stat70",                  shell_stat70 },
  1946.     { "stat80",                  shell_stat80 },
  1947.     { "window_redraw",           shell_window_redraw },
  1948.     { "write_text",              shell_write_text },
  1949.     { "switch_to_thread",        shell_switch_to_thread },
  1950.     { "new_sys_thread",          shell_new_sys_thread },
  1951. };
  1952.  
  1953. static void
  1954. shell_help(int argc, char **argv) {
  1955.     const char *usage = \
  1956.         "usage: help [command]\n"
  1957.         "  command        help on this command usage";
  1958.     switch (argc) {
  1959.     case 1:
  1960.         fputs(usage, fout);
  1961.         fputs("\navailable commands:\n", fout);
  1962.         for (func_table_t *ft = shell_cmds;
  1963.              ft < shell_cmds + sizeof(shell_cmds) / sizeof(*shell_cmds);
  1964.              ft++) {
  1965.             fprintf(fout, "  %s\n", ft->name);
  1966.         }
  1967.         break;
  1968.     case 2: {
  1969.         const char *cmd_name = argv[1];
  1970.         size_t i;
  1971.         for (i = 0; i < sizeof(shell_cmds) / sizeof(*shell_cmds); i++) {
  1972.             if (!strcmp(shell_cmds[i].name, cmd_name)) {
  1973.                 shell_cmds[i].func(0, NULL);
  1974.                 return;
  1975.             }
  1976.         }
  1977.         fprintf(fout, "no such command: %s\n", cmd_name);
  1978.         break;
  1979.     }
  1980.     default:
  1981.         fputs(usage, fout);
  1982.         return;
  1983.     }
  1984. }
  1985.  
  1986. void *
  1987. run_test(FILE *in, FILE *out) {
  1988.     fin = in;
  1989.     fout = out;
  1990.     int is_tty = 0; // isatty(fileno(fin));
  1991.     char **argv = (char**)malloc(sizeof(char*) * (MAX_COMMAND_ARGS + 1));
  1992.     while(next_line(is_tty)) {
  1993.         if (cmd_buf[0] == '#' || cmd_buf[0] == '\n' || cmd_buf[0] == '\0' ||
  1994.             cmd_buf[0] == '\r') {
  1995.             fprintf(fout, "%s", cmd_buf);
  1996.             continue;
  1997.         }
  1998.         if (cmd_buf[0] == 'X') break;
  1999.         if (!is_tty) {
  2000.             prompt();
  2001.             fprintf(fout, "%s", cmd_buf);
  2002.             fflush(fout);
  2003.         }
  2004.         int argc = split_args(cmd_buf, argv);
  2005.         func_table_t *ft;
  2006.         for (ft = shell_cmds;
  2007.              ft < shell_cmds + sizeof(shell_cmds) / sizeof(*shell_cmds);
  2008.              ft++) {
  2009.             if (!strcmp(argv[0], ft->name)) {
  2010.                 break;
  2011.             }
  2012.         }
  2013.         if (ft->name) {
  2014.             ft->func(argc, argv);
  2015.         } else {
  2016.             fprintf(fout, "unknown command: %s\n", argv[0]);
  2017.         }
  2018.     }
  2019.     free(argv);
  2020.  
  2021.     return NULL;
  2022. }
  2023.