main.c (5948B)
1 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <errno.h> 6 7 #include "stack.h" 8 #include "script.h" 9 #include "alloc.h" 10 #include "util.h" 11 12 extern int yyparse(); 13 extern FILE* yyin; 14 15 char * g_reader_buf; 16 char * g_reader_buf_top; 17 struct stack g_reader_stack; 18 u32 g_reader_buf_cap; 19 int yy_scan_string(const char *); 20 21 22 void yyerror(const char* s); 23 24 #define streq(a,b) strcmp(a,b) == 0 25 26 27 void parse_error(char* err) { 28 fprintf(stderr, "[btcs] parse error: %s\n", err); 29 exit(1); 30 } 31 32 #define COMPILE_SHOW_SCRIPT (1 << 0) 33 #define COMPILE_SHOW_SCRIPT_HEX (1 << 1) 34 #define COMPILE_SHOW_STACK (1 << 2) 35 #define COMPILE_SHOW_STACK_HEX (1 << 3) 36 #define COMPILE_SHOW_RESULTS (1 << 4) 37 #define COMPILE_SHOW_LABELS (1 << 5) 38 #define COMPILE_SHOW_ALL 0x3F 39 40 static int compile(int compile_options, int argc, const char *argv[]) 41 { 42 yyin = stdin; 43 44 struct result result; 45 /* size_t size; */ 46 size_t bufsize = MAX_STACK_SIZE * MAX_STACK_SIZE; 47 int i; 48 int compiled_len; 49 u8 *buf = (u8*)malloc(bufsize); 50 struct stack tmp_stack; 51 alloc_arenas(); 52 stack_init(&tmp_stack); 53 stack_init(&g_reader_stack); 54 55 if (argc > 1) { 56 for (i = 1; i < argc; ++i) { 57 yy_scan_string(argv[i]); 58 yyparse(); 59 } 60 } 61 else { 62 do { 63 yyparse(); 64 } while(!feof(yyin)); 65 } 66 67 bool nol = (compile_options & COMPILE_SHOW_LABELS) == 0; 68 69 /* size = g_reader_buf_top - g_reader_buf; */ 70 if (compile_options & COMPILE_SHOW_SCRIPT) { 71 if (compile_options & COMPILE_SHOW_LABELS) 72 printf("script "); 73 script_print_vals(&g_reader_stack); 74 } 75 76 script_serialize(&g_reader_stack, buf, bufsize, &compiled_len); 77 script_eval(buf, compiled_len, &tmp_stack, &result); 78 79 if (compile_options & COMPILE_SHOW_SCRIPT_HEX) { 80 if (compile_options & COMPILE_SHOW_LABELS) 81 printf("script_hex "); 82 for(i = 0; i < compiled_len; ++i) 83 printf("%02x", buf[i]); 84 printf("\n"); 85 } 86 87 if (compile_options & COMPILE_SHOW_STACK) { 88 if (compile_options & COMPILE_SHOW_LABELS) 89 printf("stack "); 90 script_print_vals(&tmp_stack); 91 } 92 93 stack_serialize(&tmp_stack, buf, bufsize, &compiled_len); 94 95 if (compile_options & COMPILE_SHOW_STACK_HEX) { 96 if (compile_options & COMPILE_SHOW_LABELS) 97 printf("stack_hex "); 98 for(i = 0; i < compiled_len; ++i) 99 printf("%02x", buf[i]); 100 printf("\n"); 101 } 102 103 if (compile_options & COMPILE_SHOW_RESULTS) { 104 if (compile_options & COMPILE_SHOW_LABELS) 105 printf("results "); 106 if (result.error) 107 printf("error:%d:%s:%s", result.op_count, result.error, 108 op_name(result.last_op)); 109 else 110 printf("success"); 111 printf("\n"); 112 } 113 114 stack_free(&g_reader_stack); 115 stack_free(&tmp_stack); 116 free_arenas(0); 117 118 return !!result.error; 119 } 120 121 static void fail(int err, const char *msg) 122 { 123 fprintf(stderr, "error: %s\n", msg); 124 exit(err); 125 } 126 127 128 static int decompile(const char *str, size_t *strlen, bool abbrev_data) 129 { 130 static u8 buf[10000]; 131 132 hex_decode(str, strlen, buf, sizeof(buf)); 133 134 if (*strlen % 2 != 0) 135 return 0; 136 137 size_t nbytes = *strlen / 2; 138 139 script_print(buf, nbytes, abbrev_data); 140 141 return 1; 142 } 143 144 145 static void usage() 146 { 147 fprintf(stderr, "usage: btcs [OPTIONS] <script>\n\n"); 148 fprintf(stderr, " OPTIONS\n\n"); 149 fprintf(stderr, " -d,--decompile decompile a base16 string to bitcoin script\n"); 150 exit(1); 151 } 152 153 static u32 count_bits(u32 n) 154 { 155 u32 count = 0; 156 while (n) { 157 n &= (n-1) ; 158 count++; 159 } 160 return count; 161 } 162 163 int main(int argc, const char *argv[]) 164 { 165 static u8 buf[20000]; 166 167 bool is_decompile = false; 168 const char *input = NULL; 169 size_t written; 170 bool abbrev_data = false; 171 int compile_options = 0; 172 int last_opt = 0; 173 int hide_labels = -1; 174 175 if (argc == 2 && (streq(argv[1], "-h") || streq(argv[1], "--help"))) 176 usage(); 177 178 for (int i = 1; i < argc; i++) { 179 if (streq(argv[i], "-d") || streq(argv[i], "--decompile")) 180 is_decompile = true; 181 else if (streq(argv[i], "-sh") || streq(argv[i], "--script-hex")) 182 compile_options |= COMPILE_SHOW_SCRIPT_HEX; 183 else if (streq(argv[i], "-s") || streq(argv[i], "--script")) 184 compile_options |= COMPILE_SHOW_SCRIPT; 185 else if (streq(argv[i], "-t") || streq(argv[i], "--stack")) 186 compile_options |= COMPILE_SHOW_STACK; 187 else if (streq(argv[i], "-th") || streq(argv[i], "--stack-hex")) 188 compile_options |= COMPILE_SHOW_STACK_HEX; 189 else if (streq(argv[i], "-r") || streq(argv[i], "--results")) 190 compile_options |= COMPILE_SHOW_RESULTS; 191 else if (streq(argv[i], "-l") || streq(argv[i], "--hide-labels")) 192 hide_labels = 1; 193 else if (streq(argv[i], "+l") || streq(argv[i], "--show-labels")) 194 hide_labels = 0; 195 else if (streq(argv[i], "-a") || streq(argv[i], "--abbreviate-data")) 196 abbrev_data = true; 197 else { 198 last_opt = i-1; 199 input = argv[i]; 200 break; 201 } 202 } 203 204 if (is_decompile) { 205 // we have stdin 206 char *line = NULL; 207 ssize_t len = 0, prevlen; 208 size_t n; 209 int ok; 210 bool failed = false; 211 212 if (input == NULL) { 213 while ((len = getline(&line, &n, stdin)) != -1) { 214 len--; 215 prevlen = len; 216 ok = decompile(line, (size_t*)&len, abbrev_data); 217 218 printf("%.*s\n", (int)(prevlen - len), line+len); 219 220 if (!ok) { 221 failed = true; 222 fprintf(stderr, "failed to decompile\n"); 223 } 224 } 225 } 226 else { 227 ok = read_arg_or_stdin(input, buf, sizeof(buf), &written); 228 229 if (!ok) 230 fail(4, "failed to read input arg (too big?)"); 231 232 ok = decompile((const char *)buf, &written, abbrev_data); 233 printf("\n"); 234 235 if (!ok) { 236 fprintf(stderr, "failed to decompile\n"); 237 failed = true; 238 } 239 } 240 241 if (failed) 242 exit(5); 243 244 245 } 246 else { 247 if (!compile_options) 248 compile_options = COMPILE_SHOW_ALL; 249 250 if (hide_labels == -1) 251 hide_labels = count_bits(compile_options) == 1; 252 253 if (hide_labels) 254 compile_options &= ~COMPILE_SHOW_LABELS; 255 else 256 compile_options |= COMPILE_SHOW_LABELS; 257 258 exit( compile(compile_options, argc - last_opt, argv + last_opt) ); 259 } 260 } 261 262 void yyerror(const char* s) { 263 fprintf(stderr, "Parse error: %s\n", s); 264 exit(1); 265 }