add compile command
This commit is contained in:
parent
ece1e95de7
commit
078d024e1e
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
|||||||
zig-cache
|
zig-cache
|
||||||
zig-out
|
zig-out
|
||||||
|
compile_commands.json
|
||||||
|
.cache
|
||||||
|
32
README.md
32
README.md
@ -1,11 +1,37 @@
|
|||||||
# Brainfuck interpreter
|
# Brainfuck interpreter & compiler
|
||||||
|
|
||||||
https://en.wikipedia.org/wiki/Brainfuck
|
https://en.wikipedia.org/wiki/Brainfuck
|
||||||
|
|
||||||
## Building & Usage
|
## Building & Usage
|
||||||
|
|
||||||
```
|
To compile CLI
|
||||||
|
```shell
|
||||||
zig build -Doptimize=ReleaseFast
|
zig build -Doptimize=ReleaseFast
|
||||||
./zig-out/bin/brainfuck <filename>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Will run using emulator
|
||||||
|
```shell
|
||||||
|
./zig-out/bin/brainfuck run <filename>
|
||||||
|
```
|
||||||
|
|
||||||
|
Will compile program to executable
|
||||||
|
```shell
|
||||||
|
./zig-out/bin/brainfuck compile <filename> <output>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Developing
|
||||||
|
|
||||||
|
This command will create a `compile_commands.json` file which an IDE can use to more smartly say from where
|
||||||
|
each file is included. If you don't do this, some defines not be defined and then what you see in the IDE
|
||||||
|
wont match what the compiler is doing.
|
||||||
|
```
|
||||||
|
zig build cdb
|
||||||
|
```
|
||||||
|
|
||||||
|
## Feature wishlist
|
||||||
|
|
||||||
|
* Update TinyCC backend, so host would not need to have it installed. Relies on host having include paths used by TinyCC.
|
||||||
|
* Add more backends. Maybe LLVM, nasm or create my own
|
||||||
|
* Perform optimizations? Like removing not needed `[]` blocks which are known never to be ran? Idk, what could be optimized
|
||||||
|
* Add WASM/Web build
|
||||||
|
|
||||||
|
33
build.zig
33
build.zig
@ -1,4 +1,5 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const zcc = @import("compile_commands");
|
||||||
const Build = std.Build;
|
const Build = std.Build;
|
||||||
|
|
||||||
pub fn build(b: *Build) !void {
|
pub fn build(b: *Build) !void {
|
||||||
@ -11,9 +12,41 @@ pub fn build(b: *Build) !void {
|
|||||||
.target = target
|
.target = target
|
||||||
});
|
});
|
||||||
exe.addIncludePath(.{ .path = "src" });
|
exe.addIncludePath(.{ .path = "src" });
|
||||||
|
exe.addIncludePath(.{ .path = "include" });
|
||||||
exe.addCSourceFile(.{ .file = b.path("src/main.c") });
|
exe.addCSourceFile(.{ .file = b.path("src/main.c") });
|
||||||
|
exe.addCSourceFile(.{ .file = b.path("src/bf_compiler.c") });
|
||||||
|
exe.addCSourceFile(.{ .file = b.path("src/bf_emulator.c") });
|
||||||
exe.linkLibC();
|
exe.linkLibC();
|
||||||
|
|
||||||
|
if (b.option(bool, "tinycc", "Toggle 'tinycc' compiler backend (Enabled by default)") orelse true) {
|
||||||
|
if (b.lazyDependency("tinycc", .{})) |tinycc| {
|
||||||
|
const tinycc_source = tinycc.path(".");
|
||||||
|
|
||||||
|
const configure_cmd = b.addSystemCommand(&.{ "./configure", "--config-musl" });
|
||||||
|
_ = configure_cmd.captureStdOut();
|
||||||
|
configure_cmd.setCwd(tinycc_source);
|
||||||
|
|
||||||
|
const make_cmd = b.addSystemCommand(&.{ "make", "libtcc.a" });
|
||||||
|
_ = make_cmd.captureStdOut();
|
||||||
|
make_cmd.setCwd(tinycc_source);
|
||||||
|
make_cmd.step.dependOn(&configure_cmd.step);
|
||||||
|
|
||||||
|
const install_cmd = b.addSystemCommand(&.{ "make", "install" });
|
||||||
|
_ = install_cmd.captureStdOut();
|
||||||
|
install_cmd.setEnvironmentVariable("DESTDIR", "build");
|
||||||
|
install_cmd.setCwd(tinycc_source);
|
||||||
|
install_cmd.step.dependOn(&make_cmd.step);
|
||||||
|
|
||||||
|
exe.step.dependOn(&install_cmd.step);
|
||||||
|
exe.addObjectFile(tinycc.path("libtcc.a"));
|
||||||
|
exe.addIncludePath(tinycc.path("build/usr/local/include"));
|
||||||
|
|
||||||
|
exe.root_module.addCMacro("BF_BACKEND_TINYCC", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zcc.createStep(b, "cdb", .{ .target = exe });
|
||||||
|
|
||||||
b.installArtifact(exe);
|
b.installArtifact(exe);
|
||||||
|
|
||||||
const run_exe = b.addRunArtifact(exe);
|
const run_exe = b.addRunArtifact(exe);
|
||||||
|
17
build.zig.zon
Normal file
17
build.zig.zon
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
.{
|
||||||
|
.name = "brainfuck",
|
||||||
|
.version = "0.1.0",
|
||||||
|
.minimum_zig_version = "0.12.0",
|
||||||
|
.dependencies = .{
|
||||||
|
.tinycc = .{
|
||||||
|
.url = "https://github.com/TinyCC/tinycc/archive/refs/tags/release_0_9_27.tar.gz",
|
||||||
|
.hash = "122015b387754b02f220e29c9cb163d9c395c5928e6e50efe72df0734debd95c0b22",
|
||||||
|
.lazy = true
|
||||||
|
},
|
||||||
|
.compile_commands = .{
|
||||||
|
.url = "https://github.com/bcrist/zig-compile-commands/archive/a64abd947b58655f118884709d939645871e94fc.tar.gz",
|
||||||
|
.hash = "1220d3150db10226f4d853eb519468de5c49cb820f08c722608a500b9f7d64e4c780",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.paths = .{ "" }
|
||||||
|
}
|
20
include/bf_compiler.h
Normal file
20
include/bf_compiler.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef BF_COMPILER_H_
|
||||||
|
#define BF_COMPILER_H_
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
enum bf_compiler_backend {
|
||||||
|
BF_COMPILER_TINYCC
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bf_compiler {
|
||||||
|
enum bf_compiler_backend backend;
|
||||||
|
uint32_t data_len;
|
||||||
|
uint32_t cell_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
void bf_compiler_init(struct bf_compiler *compiler, uint32_t cell_size, uint32_t data_len);
|
||||||
|
int bf_compiler_compile(struct bf_compiler *compiler, const char *output_filename, const char *program, size_t program_len);
|
||||||
|
|
||||||
|
#endif //BF_COMPILER_H_
|
31
include/bf_emulator.h
Normal file
31
include/bf_emulator.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef BF_EMULATOR_H_
|
||||||
|
#define BF_EMULATOR_H_
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
enum bf_step_result {
|
||||||
|
BF_STEP_OK,
|
||||||
|
BF_STEP_FINISHED,
|
||||||
|
BF_STEP_ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bf_emulator {
|
||||||
|
uint32_t data_pointer;
|
||||||
|
|
||||||
|
void *data;
|
||||||
|
uint32_t data_len;
|
||||||
|
uint32_t cell_size;
|
||||||
|
|
||||||
|
const char *program;
|
||||||
|
size_t program_len;
|
||||||
|
size_t program_pointer;
|
||||||
|
};
|
||||||
|
|
||||||
|
void bf_emulator_init(struct bf_emulator *emulator, uint32_t cell_size, uint32_t data_len);
|
||||||
|
void bf_emulator_deinit(struct bf_emulator *emulator);
|
||||||
|
enum bf_step_result bf_emulator_step(struct bf_emulator *emulator);
|
||||||
|
enum bf_step_result bf_emulator_continue(struct bf_emulator *emulator);
|
||||||
|
enum bf_step_result bf_emulator_run(struct bf_emulator *emulator, const char *program, size_t program_len);
|
||||||
|
|
||||||
|
#endif //BF_EMULATOR_H_
|
26
src/bf_compiler.c
Normal file
26
src/bf_compiler.c
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "bf_compiler.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#ifdef BF_BACKEND_TINYCC
|
||||||
|
#include "bf_compiler_tinycc.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void bf_compiler_init(struct bf_compiler *compiler, uint32_t cell_size, uint32_t data_len)
|
||||||
|
{
|
||||||
|
assert(cell_size == 8 || cell_size == 16 || cell_size == 32);
|
||||||
|
compiler->cell_size = cell_size;
|
||||||
|
compiler->data_len = data_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bf_compiler_compile(struct bf_compiler *compiler, const char *output_filename, const char *program, size_t program_len)
|
||||||
|
{
|
||||||
|
#ifdef BF_BACKEND_TINYCC
|
||||||
|
if (compiler->backend == BF_COMPILER_TINYCC) {
|
||||||
|
return bf_compiler_compile_tinycc(compiler, output_filename, program, program_len);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
133
src/bf_compiler_tinycc.c
Normal file
133
src/bf_compiler_tinycc.c
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#include "bf_compiler.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <libtcc.h>
|
||||||
|
|
||||||
|
struct str_buffer {
|
||||||
|
char *data;
|
||||||
|
size_t len;
|
||||||
|
size_t capacity;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void str_buffer_init(struct str_buffer *buffer, size_t capacity)
|
||||||
|
{
|
||||||
|
buffer->data = malloc(capacity);
|
||||||
|
assert(buffer->data != NULL);
|
||||||
|
buffer->len = 0;
|
||||||
|
buffer->capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void str_buffer_deinit(struct str_buffer *buffer)
|
||||||
|
{
|
||||||
|
free(buffer->data);
|
||||||
|
buffer->data = NULL;
|
||||||
|
buffer->capacity = 0;
|
||||||
|
buffer->len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void str_buffer_append_with_len(struct str_buffer *buffer, const char *text, size_t text_len)
|
||||||
|
{
|
||||||
|
if (buffer->len + text_len > buffer->capacity) {
|
||||||
|
while (buffer->len + text_len > buffer->capacity) {
|
||||||
|
buffer->capacity *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->data = realloc(buffer->data, buffer->capacity);
|
||||||
|
assert(buffer->data != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer->data + buffer->len, text, text_len);
|
||||||
|
buffer->len += text_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void str_buffer_append(struct str_buffer *buffer, const char *text)
|
||||||
|
{
|
||||||
|
str_buffer_append_with_len(buffer, text, strlen(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bf_compiler_compile_tinycc(struct bf_compiler *compiler, const char *output_filename, const char *program, size_t program_len)
|
||||||
|
{
|
||||||
|
struct str_buffer c_program = { 0 };
|
||||||
|
str_buffer_init(&c_program, 128);
|
||||||
|
|
||||||
|
int rc = -1;
|
||||||
|
TCCState *state = tcc_new();
|
||||||
|
if (!state) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cell_type = NULL;
|
||||||
|
if (compiler->cell_size == 8) {
|
||||||
|
cell_type = "uint8_t";
|
||||||
|
} else if (compiler->cell_size == 16) {
|
||||||
|
cell_type = "uint16_t";
|
||||||
|
} else if (compiler->cell_size == 32) {
|
||||||
|
cell_type = "uint32_t";
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char line_buffer[256] = { 0 };
|
||||||
|
|
||||||
|
str_buffer_append(&c_program, "#include <inttypes.h>\n");
|
||||||
|
str_buffer_append(&c_program, "#include <stdlib.h>\n");
|
||||||
|
str_buffer_append(&c_program, "#include <assert.h>\n");
|
||||||
|
|
||||||
|
snprintf(line_buffer, sizeof(line_buffer), "typedef %s cell_t;\n", cell_type);
|
||||||
|
str_buffer_append(&c_program, line_buffer);
|
||||||
|
|
||||||
|
str_buffer_append(&c_program, "int main()\n");
|
||||||
|
str_buffer_append(&c_program, "{\n");
|
||||||
|
|
||||||
|
snprintf(line_buffer, sizeof(line_buffer), "size_t data_len = %d;\n", compiler->data_len);
|
||||||
|
str_buffer_append(&c_program, line_buffer);
|
||||||
|
|
||||||
|
str_buffer_append(&c_program, "cell_t data_pointer = 0;\n");
|
||||||
|
str_buffer_append(&c_program, "cell_t *data = calloc(data_len, sizeof(cell_t));\n");
|
||||||
|
str_buffer_append(&c_program, "assert(data != NULL);\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < program_len; i++) {
|
||||||
|
char inst = program[i];
|
||||||
|
|
||||||
|
if (inst == '>') {
|
||||||
|
str_buffer_append(&c_program, "data_pointer++;\n");
|
||||||
|
} else if (inst == '<') {
|
||||||
|
str_buffer_append(&c_program, "data_pointer--;\n");
|
||||||
|
} else if (inst == '+') {
|
||||||
|
str_buffer_append(&c_program, "data[data_pointer]++;\n");
|
||||||
|
} else if (inst == '-') {
|
||||||
|
str_buffer_append(&c_program, "data[data_pointer]--;\n");
|
||||||
|
} else if (inst == '.') {
|
||||||
|
str_buffer_append(&c_program, "putchar(data[data_pointer]); fflush(0);\n");
|
||||||
|
} else if (inst == ',') {
|
||||||
|
str_buffer_append(&c_program, "data[data_pointer] = getchar();\n");
|
||||||
|
} else if (inst == '[') {
|
||||||
|
str_buffer_append(&c_program, "while (data[data_pointer] != 0) {\n");
|
||||||
|
} else if (inst == ']') {
|
||||||
|
str_buffer_append(&c_program, "}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str_buffer_append(&c_program, "free(data);\n");
|
||||||
|
str_buffer_append(&c_program, "return 0;\n");
|
||||||
|
str_buffer_append(&c_program, "}\n");
|
||||||
|
str_buffer_append_with_len(&c_program, "\0", 1);
|
||||||
|
|
||||||
|
tcc_set_output_type(state, TCC_OUTPUT_EXE);
|
||||||
|
tcc_set_options(state, "-w");
|
||||||
|
if (tcc_compile_string(state, c_program.data) == -1) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcc_output_file(state, output_filename)) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = 0;
|
||||||
|
err:
|
||||||
|
tcc_delete(state);
|
||||||
|
str_buffer_deinit(&c_program);
|
||||||
|
return rc;
|
||||||
|
}
|
@ -1,28 +1,10 @@
|
|||||||
#include <inttypes.h>
|
#include "bf_emulator.h"
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
enum bf_step_result {
|
|
||||||
BF_STEP_OK,
|
|
||||||
BF_STEP_FINISHED,
|
|
||||||
BF_STEP_ERROR,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct bf_emulator {
|
|
||||||
uint32_t data_pointer;
|
|
||||||
|
|
||||||
void *data;
|
|
||||||
uint32_t data_len;
|
|
||||||
uint32_t cell_size;
|
|
||||||
|
|
||||||
const char *program;
|
|
||||||
size_t program_len;
|
|
||||||
size_t program_pointer;
|
|
||||||
};
|
|
||||||
|
|
||||||
void bf_emulator_init(struct bf_emulator *emulator, uint32_t cell_size, uint32_t data_len)
|
void bf_emulator_init(struct bf_emulator *emulator, uint32_t cell_size, uint32_t data_len)
|
||||||
{
|
{
|
||||||
assert(cell_size == 8 || cell_size == 16 || cell_size == 32);
|
assert(cell_size == 8 || cell_size == 16 || cell_size == 32);
|
||||||
|
106
src/main.c
106
src/main.c
@ -2,9 +2,11 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "bf_emulator.c"
|
#include "bf_emulator.h"
|
||||||
|
#include "bf_compiler.h"
|
||||||
|
|
||||||
uint64_t get_file_size(const char *filename) {
|
uint64_t get_file_size(const char *filename) {
|
||||||
struct stat result;
|
struct stat result;
|
||||||
@ -12,37 +14,49 @@ uint64_t get_file_size(const char *filename) {
|
|||||||
return result.st_size;
|
return result.st_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
char *read_file(const char *filename, size_t *file_len)
|
||||||
if (argc < 2) {
|
{
|
||||||
printf("Usage: %s <filename>\n", argv[0]);
|
char *result = NULL;
|
||||||
return 1;
|
|
||||||
|
*file_len = get_file_size(filename);
|
||||||
|
char *contents = calloc(*file_len, sizeof(uint8_t));
|
||||||
|
if (contents == NULL) {
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *filename = argv[1];
|
FILE *f = fopen(filename, "r");
|
||||||
size_t program_len = get_file_size(filename);
|
if (f == NULL) {
|
||||||
char *program = calloc(program_len, sizeof(uint8_t));
|
printf("ERROR: Failed to open file\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t read_amount = 0;
|
||||||
|
while (read_amount < *file_len) {
|
||||||
|
int result = fread(contents + read_amount, 1, *file_len - read_amount, f);
|
||||||
|
if (result <= 0) {
|
||||||
|
printf("ERROR: Failed to read everything from file\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
read_amount += result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
result = contents;
|
||||||
|
err:
|
||||||
|
if (!result) {
|
||||||
|
free(contents);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int run_command(int argc, const char **argv) {
|
||||||
|
const char *filename = argv[0];
|
||||||
|
|
||||||
|
size_t program_len = 0;
|
||||||
|
char *program = read_file(filename, &program_len);
|
||||||
assert(program != NULL);
|
assert(program != NULL);
|
||||||
|
|
||||||
{ // Read program from file
|
|
||||||
FILE *f = fopen(filename, "r");
|
|
||||||
if (f == NULL) {
|
|
||||||
printf("ERROR: Failed to open file\n");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t read_amount = 0;
|
|
||||||
while (read_amount < program_len) {
|
|
||||||
int result = fread(program + read_amount, 1, program_len - read_amount, f);
|
|
||||||
if (result <= 0) {
|
|
||||||
printf("ERROR: Failed to read everything from file\n");
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
read_amount += result;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct bf_emulator emulator = { 0 };
|
struct bf_emulator emulator = { 0 };
|
||||||
bf_emulator_init(&emulator, 16, 4096);
|
bf_emulator_init(&emulator, 16, 4096);
|
||||||
|
|
||||||
@ -55,3 +69,39 @@ int main(int argc, const char **argv) {
|
|||||||
bf_emulator_deinit(&emulator);
|
bf_emulator_deinit(&emulator);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int compile_command(int argc, const char **argv) {
|
||||||
|
const char *input_filename = argv[0];
|
||||||
|
const char *output_filename = argv[1];
|
||||||
|
|
||||||
|
size_t program_len = 0;
|
||||||
|
char *program = read_file(input_filename, &program_len);
|
||||||
|
assert(program != NULL);
|
||||||
|
|
||||||
|
struct bf_compiler compiler = { 0 };
|
||||||
|
bf_compiler_init(&compiler, 16, 4096);
|
||||||
|
|
||||||
|
if (bf_compiler_compile(&compiler, output_filename, program, program_len)) {
|
||||||
|
printf("ERROR: Failed to compile program\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_usage() {
|
||||||
|
printf("Usage: brainfuck run <filename>\n");
|
||||||
|
printf(" brainfuck compile <input-file> <output-file>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char **argv) {
|
||||||
|
if (argc >= 3 && !strncmp(argv[1], "run", sizeof("run"))) {
|
||||||
|
return run_command(argc - 2, argv + 2);
|
||||||
|
|
||||||
|
} else if (argc >= 4 && !strncmp(argv[1], "compile", sizeof("compile"))) {
|
||||||
|
return compile_command(argc - 2, argv + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
show_usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user