diff --git a/userspace/CMakeLists.txt b/userspace/CMakeLists.txt index cb4a6542e0..facadf4677 100644 --- a/userspace/CMakeLists.txt +++ b/userspace/CMakeLists.txt @@ -10,6 +10,7 @@ set(USERSPACE_PROJECTS dd dhcp-client echo + getopt id image init diff --git a/userspace/getopt/CMakeLists.txt b/userspace/getopt/CMakeLists.txt new file mode 100644 index 0000000000..83509b7748 --- /dev/null +++ b/userspace/getopt/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.26) + +project(getopt CXX) + +set(SOURCES + main.cpp +) + +add_executable(getopt ${SOURCES}) +target_compile_options(getopt PUBLIC -O2 -g) +target_link_libraries(getopt PUBLIC libc ban) + +add_custom_target(getopt-install + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/getopt ${BANAN_BIN}/ + DEPENDS getopt +) diff --git a/userspace/getopt/main.cpp b/userspace/getopt/main.cpp new file mode 100644 index 0000000000..a5f379a050 --- /dev/null +++ b/userspace/getopt/main.cpp @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + if (argc < 2) + { + fprintf(stderr, "usage: %s OPTSTRING [PARAMETERS]...", argv[0]); + return 1; + } + + BAN::Vector argv_copy(argc - 1); + argv_copy[0] = argv[0]; + for (int i = 2; i < argc; i++) + argv_copy[i - 1] = argv[i]; + + int opt; + BAN::String parsed; + while ((opt = getopt(argc - 1, argv_copy.data(), argv[1])) != -1) + { + if (opt == ':' || opt == '?') + continue; + + MUST(parsed.append(" -")); + MUST(parsed.push_back(opt)); + + if (optarg) + { + MUST(parsed.push_back(' ')); + MUST(parsed.append(optarg)); + } + + optarg = nullptr; + } + + printf("%s --", parsed.data()); + for (; optind < argc - 1; optind++) + printf(" %s", argv_copy[optind]); + printf("\n"); + + return 0; +}