MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at mir/inline-method 204 lines 5.6 kB view raw
1#include <compat.h> // IWYU pragma: keep 2 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6 7#ifdef _WIN32 8#define popen _popen 9#define pclose _pclose 10#else 11#include <sys/wait.h> 12#endif 13 14#include "ant.h" 15#include "errors.h" 16#include "internal.h" 17#include "modules/symbol.h" 18 19static ant_value_t builtin_shell_text(ant_t *js, ant_value_t *args, int nargs); 20static ant_value_t builtin_shell_lines(ant_t *js, ant_value_t *args, int nargs); 21 22static ant_value_t shell_exec(ant_t *js, const char *cmd, size_t cmd_len) { 23 ant_value_t result = js_mkobj(js); 24 25 FILE *fp = popen(cmd, "r"); 26 if (!fp) { 27 js_set(js, result, "stdout", js_mkstr(js, "", 0)); 28 js_set(js, result, "stderr", js_mkstr(js, "Failed to execute command", 25)); 29 js_set(js, result, "exitCode", js_mknum(1)); 30 return result; 31 } 32 33 char *output = NULL; 34 size_t output_size = 0; 35 size_t output_capacity = 4096; 36 output = malloc(output_capacity); 37 38 if (!output) { 39 pclose(fp); 40 return js_mkerr(js, "Out of memory"); 41 } 42 43 char buffer[4096]; 44 while (fgets(buffer, sizeof(buffer), fp) != NULL) { 45 size_t len = strlen(buffer); 46 if (output_size + len >= output_capacity) { 47 output_capacity *= 2; 48 char *new_output = realloc(output, output_capacity); 49 if (!new_output) { 50 free(output); 51 pclose(fp); 52 return js_mkerr(js, "Out of memory"); 53 } 54 output = new_output; 55 } 56 memcpy(output + output_size, buffer, len); 57 output_size += len; 58 } 59 60 int status = pclose(fp); 61#ifdef _WIN32 62 int exit_code = status; 63#else 64 int exit_code = WIFEXITED(status) ? WEXITSTATUS(status) : -1; 65#endif 66 if (output_size > 0 && output[output_size - 1] == '\n') output_size--; 67 68 ant_value_t stdout_val = js_mkstr(js, output, output_size); 69 free(output); 70 71 js_set(js, result, "exitCode", js_mknum(exit_code)); 72 js_set(js, result, "text", js_heavy_mkfun(js, builtin_shell_text, stdout_val)); 73 js_set(js, result, "lines", js_heavy_mkfun(js, builtin_shell_lines, stdout_val)); 74 75 return result; 76} 77 78static ant_value_t builtin_shell_text(ant_t *js, ant_value_t *args, int nargs) { 79 (void)args; 80 (void)nargs; 81 82 ant_value_t fn = js_getcurrentfunc(js); 83 return js_get_slot(fn, SLOT_DATA); 84} 85 86static ant_value_t builtin_shell_lines(ant_t *js, ant_value_t *args, int nargs) { 87 (void)args; 88 (void)nargs; 89 90 ant_value_t fn = js_getcurrentfunc(js); 91 ant_value_t stdout_val = js_get_slot(fn, SLOT_DATA); 92 93 size_t text_len; 94 char *text = js_getstr(js, stdout_val, &text_len); 95 if (!text) return js_mkarr(js); 96 97 ant_value_t lines_array = js_mkarr(js); 98 size_t line_start = 0; 99 100 for (size_t i = 0; i <= text_len; i++) { 101 if (i == text_len || text[i] == '\n') { 102 size_t line_len = i - line_start; 103 ant_value_t line_val = js_mkstr(js, text + line_start, line_len); 104 js_arr_push(js, lines_array, line_val); 105 line_start = i + 1; 106 } 107 } 108 109 return lines_array; 110} 111 112static ant_value_t builtin_shell_dollar(ant_t *js, ant_value_t *args, int nargs) { 113 if (nargs < 1) return js_mkerr(js, "$() requires at least one argument"); 114 115 if (!is_special_object(args[0])) { 116 if (vtype(args[0]) == T_STR) { 117 size_t cmd_len; 118 char *cmd = js_getstr(js, args[0], &cmd_len); 119 if (!cmd) return js_mkerr(js, "Failed to get command string"); 120 return shell_exec(js, cmd, cmd_len); 121 } 122 123 return js_mkerr(js, "$() requires a template string"); 124 } 125 126 ant_value_t strings_array = args[0]; 127 128 char *command = malloc(4096); 129 if (!command) return js_mkerr(js, "Out of memory"); 130 131 size_t cmd_pos = 0; 132 size_t cmd_capacity = 4096; 133 134 ant_value_t length_val = js_get(js, strings_array, "length"); 135 int length = (int)js_getnum(length_val); 136 137 for (int i = 0; i < length; i++) { 138 char idx_str[32]; 139 snprintf(idx_str, sizeof(idx_str), "%d", i); 140 141 ant_value_t str_val = js_get(js, strings_array, idx_str); 142 if (vtype(str_val) == T_STR) { 143 size_t str_len; 144 char *str = js_getstr(js, str_val, &str_len); 145 146 if (cmd_pos + str_len >= cmd_capacity) { 147 cmd_capacity *= 2; 148 char *new_cmd = realloc(command, cmd_capacity); 149 if (!new_cmd) { 150 free(command); 151 return js_mkerr(js, "Out of memory"); 152 } 153 command = new_cmd; 154 } 155 156 memcpy(command + cmd_pos, str, str_len); 157 cmd_pos += str_len; 158 } 159 160 if (i + 1 < nargs) { 161 ant_value_t val = args[i + 1]; 162 char val_str[256]; 163 size_t val_len = 0; 164 165 if (vtype(val) == T_STR) { 166 size_t len; 167 char *s = js_getstr(js, val, &len); 168 val_len = len < sizeof(val_str) - 1 ? len : sizeof(val_str) - 1; 169 memcpy(val_str, s, val_len); 170 } else if (vtype(val) == T_NUM) { 171 val_len = snprintf(val_str, sizeof(val_str), "%g", js_getnum(val)); 172 } 173 174 if (cmd_pos + val_len >= cmd_capacity) { 175 cmd_capacity *= 2; 176 char *new_cmd = realloc(command, cmd_capacity); 177 if (!new_cmd) { 178 free(command); 179 return js_mkerr(js, "Out of memory"); 180 } 181 command = new_cmd; 182 } 183 184 memcpy(command + cmd_pos, val_str, val_len); 185 cmd_pos += val_len; 186 } 187 } 188 189 command[cmd_pos] = '\0'; 190 191 ant_value_t result = shell_exec(js, command, cmd_pos); 192 free(command); 193 194 return result; 195} 196 197ant_value_t shell_library(ant_t *js) { 198 ant_value_t lib = js_mkobj(js); 199 200 js_set(js, lib, "$", js_mkfun(builtin_shell_dollar)); 201 js_set_sym(js, lib, get_toStringTag_sym(), js_mkstr(js, "shell", 5)); 202 203 return lib; 204}