diff --git a/Fennix Userspace.code-workspace b/Fennix Userspace.code-workspace index f0b2c3c3..42164709 100644 --- a/Fennix Userspace.code-workspace +++ b/Fennix Userspace.code-workspace @@ -20,7 +20,8 @@ "userspace/libs", "userspace/apps/test", "userspace/apps/usr", - "userspace" + "userspace", + "coreutils" ] } } diff --git a/Userspace/.editorconfig b/Userspace/.editorconfig index 784b867b..591828a8 100644 --- a/Userspace/.editorconfig +++ b/Userspace/.editorconfig @@ -11,3 +11,7 @@ indent_size = 4 [Makefile] indent_style = tab + +[{CMakeLists.txt,*.cmake}] +indent_size = 2 +indent_style = space diff --git a/Userspace/.vscode/c_boilerplates.code-snippets b/Userspace/.vscode/c_boilerplates.code-snippets index 6942dbf6..711453fe 100644 --- a/Userspace/.vscode/c_boilerplates.code-snippets +++ b/Userspace/.vscode/c_boilerplates.code-snippets @@ -160,5 +160,30 @@ "*/" ], "description": "Create libc license." + }, + "Core Utilities License": { + "isFileTemplate": true, + "prefix": [ + "license_coreutils", + ], + "body": [ + "/*", + "\tThis file is part of Fennix Core Utilities.", + "", + "\tFennix Core Utilities is free software: you can redistribute it and/or", + "\tmodify it under the terms of the GNU General Public License as", + "\tpublished by the Free Software Foundation, either version 3 of", + "\tthe License, or (at your option) any later version.", + "", + "\tFennix Core Utilities is distributed in the hope that it will be useful,", + "\tbut WITHOUT ANY WARRANTY; without even the implied warranty of", + "\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "\tGNU General Public License for more details.", + "", + "\tYou should have received a copy of the GNU General Public License", + "\talong with Fennix Core Utilities. If not, see .", + "*/" + ], + "description": "Create coreutils license." } } diff --git a/Userspace/.vscode/c_cpp_properties.json b/Userspace/.vscode/c_cpp_properties.json index a6c44b52..8079dd31 100644 --- a/Userspace/.vscode/c_cpp_properties.json +++ b/Userspace/.vscode/c_cpp_properties.json @@ -4,6 +4,7 @@ "name": "Fennix x64 (Linux, GCC, debug)", "includePath": [ "${workspaceFolder}/libc/include/**", + "${workspaceFolder}/coreutils/include/**", "${workspaceFolder}/libs/include/**" ], "defines": [ @@ -45,6 +46,7 @@ "name": "Fennix x32 (Linux, GCC, debug)", "includePath": [ "${workspaceFolder}/libc/include/**", + "${workspaceFolder}/coreutils/include/**", "${workspaceFolder}/libs/include/**" ], "defines": [ @@ -86,6 +88,7 @@ "name": "Fennix Arm (Linux, GCC, debug)", "includePath": [ "${workspaceFolder}/libc/include/**", + "${workspaceFolder}/coreutils/include/**", "${workspaceFolder}/libs/include/**" ], "defines": [ @@ -107,6 +110,7 @@ "name": "Fennix Aarch64 (Linux, GCC, debug)", "includePath": [ "${workspaceFolder}/libc/include/**", + "${workspaceFolder}/coreutils/include/**", "${workspaceFolder}/libs/include/**" ], "defines": [ @@ -126,4 +130,4 @@ } ], "version": 4 -} \ No newline at end of file +} diff --git a/Userspace/Makefile b/Userspace/Makefile index 1b5d48a4..bfe84f86 100644 --- a/Userspace/Makefile +++ b/Userspace/Makefile @@ -37,9 +37,22 @@ create_out: mkdir -p out/usr/include cp $(WORKSPACE_DIR)/../Kernel/include/interface/* $(WORKSPACE_DIR)/out/include/fennix/ +build_coreutils: + mkdir -p cache/coreutils + cd cache/coreutils && \ + cmake $(WORKSPACE_DIR)/coreutils \ + -DCMAKE_INSTALL_PREFIX:PATH=$(WORKSPACE_DIR)/out \ + -DCMAKE_SYSROOT=$(WORKSPACE_DIR)/out \ + -DCMAKE_C_STANDARD_INCLUDE_DIRECTORIES=$(WORKSPACE_DIR)/out/include \ + -DCMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES=$(WORKSPACE_DIR)/out/include \ + && \ + make -j$(shell nproc) && \ + make install + build: create_out make -C libc build make -C libs build + $(MAKE) build_coreutils make -C apps build prepare: diff --git a/Userspace/coreutils/.gitignore b/Userspace/coreutils/.gitignore new file mode 100644 index 00000000..378eac25 --- /dev/null +++ b/Userspace/coreutils/.gitignore @@ -0,0 +1 @@ +build diff --git a/Userspace/coreutils/CMakeLists.txt b/Userspace/coreutils/CMakeLists.txt new file mode 100644 index 00000000..5f5fe17c --- /dev/null +++ b/Userspace/coreutils/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_minimum_required(VERSION 3.10) +project(FennixCoreUtilities VERSION 1.0.0) + +if(NOT DEFINED ENV{WORKSPACE_DIR}) + set(STANDALONE_BUILD ON) + message(STATUS "Compiling standalone") +else() + set(STANDALONE_BUILD OFF) + message(STATUS "Compiling within workspace") +endif() + +set(CMAKE_C_COMPILER "$ENV{CC}") +set(CMAKE_CXX_COMPILER "$ENV{CXX}") +set(CMAKE_ASM_COMPILER "$ENV{AS}") +set(CMAKE_AR "$ENV{AR}") +set(CMAKE_LINKER "$ENV{LD}") + +if(DEFINED ENV{DEBUG} AND "$ENV{DEBUG}" STREQUAL "1") + set(CMAKE_C_FLAGS "-ggdb3 -O0 -DDEBUG") +else() + set(CMAKE_C_FLAGS "-O2") +endif() + +include_directories(${CMAKE_SOURCE_DIR}/include) + +file(GLOB SINGLE_SOURCE "src/*.c") +foreach(file ${SINGLE_SOURCE}) + get_filename_component(name ${file} NAME_WE) + add_executable(${name} ${file}) + target_compile_definitions(${name} PRIVATE + PROGRAM_NAME="${name}" + PROGRAM_VERSION="${PROJECT_VERSION}" + ) + install(TARGETS ${name} DESTINATION bin) +endforeach() + +file(GLOB_RECURSE GROUP_SOURCES "src/*/*.c") +foreach(file ${GROUP_SOURCES}) + get_filename_component(name ${file} DIRECTORY) + get_filename_component(name ${name} NAME) + list(APPEND GROUP_MAP_${name} ${file}) +endforeach() + +foreach(name IN LISTS GROUP_MAP_) + add_executable(${name} ${GROUP_MAP_${name}}) + target_compile_definitions(${name} PRIVATE + PROGRAM_NAME="${name}" + PROGRAM_VERSION="${PROJECT_VERSION}" + ) + install(TARGETS ${name} DESTINATION bin) +endforeach() diff --git a/Userspace/coreutils/include/coreutils.h b/Userspace/coreutils/include/coreutils.h new file mode 100644 index 00000000..3a7cb142 --- /dev/null +++ b/Userspace/coreutils/include/coreutils.h @@ -0,0 +1,38 @@ +/* + This file is part of Fennix Core Utilities. + + Fennix Core Utilities is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Core Utilities is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Core Utilities. If not, see . +*/ + +#ifndef _COREUTILS_H +#define _COREUTILS_H + +#ifndef PROGRAM_NAME +#define PROGRAM_NAME "" +#endif + +#ifndef PROGRAM_VERSION +#define PROGRAM_VERSION "" +#endif + +#define BUILD_YEAR (__DATE__ + 7) + +#define PRINTF_VERSION \ + printf("%s %s\n", PROGRAM_NAME, PROGRAM_VERSION); \ + printf("Fennix Core Utilities Copyright (C) %s EnderIce2\n", BUILD_YEAR); \ + printf("This program comes with ABSOLUTELY NO WARRANTY\n"); \ + printf("This is free software, and you are welcome to redistribute it\n"); \ + printf("under certain conditions\n") + +#endif // _COREUTILS_H diff --git a/Userspace/coreutils/src/echo.c b/Userspace/coreutils/src/echo.c new file mode 100644 index 00000000..204ade67 --- /dev/null +++ b/Userspace/coreutils/src/echo.c @@ -0,0 +1,183 @@ +/* + This file is part of Fennix Core Utilities. + + Fennix Core Utilities is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Core Utilities is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Core Utilities. If not, see . +*/ + +#include +#include +#include +#include +#include + +void PrintHelp() +{ + printf("Usage: echo [OPTION]... [STRING]...\n"); + printf("Echo the STRING(s) to standard output.\n\n"); + printf(" -n do not output the trailing newline\n"); + printf(" -e enable interpretation of backslash escapes\n"); + printf(" -E disable interpretation of backslash escapes (default)\n"); + printf(" --help display this help and exit\n"); + printf(" --version output version information and exit\n\n"); + printf("If -e is specified, the following sequences are recognized:\n"); + printf(" \\\\ backslash\n"); + printf(" \\a alert (BEL)\n"); + printf(" \\b backspace\n"); + printf(" \\c produce no further output\n"); + printf(" \\e escape\n"); + printf(" \\f form feed\n"); + printf(" \\n new line\n"); + printf(" \\r carriage return\n"); + printf(" \\t horizontal tab\n"); + printf(" \\v vertical tab\n"); +} + +static void PrintEscaped(const char *str) +{ + while (*str) + { + if (*str == '\\') + { + str++; + switch (*str) + { + case 'n': + putchar('\n'); + break; + case 't': + putchar('\t'); + break; + case '\\': + putchar('\\'); + break; + case 'a': + putchar('\a'); + break; + case 'b': + putchar('\b'); + break; + case 'r': + putchar('\r'); + break; + case 'v': + putchar('\v'); + break; + case 'f': + putchar('\f'); + break; + case '0' ... '7': + { + int octal = 0; + for (int i = 0; i < 3 && *str >= '0' && *str <= '7'; i++, str++) + { + octal = octal * 8 + (*str - '0'); + } + putchar(octal); + str--; + break; + } + case 'x': + { + int hex = 0; + str++; + for (int i = 0; i < 2 && ((*str >= '0' && *str <= '9') || + (*str >= 'a' && *str <= 'f') || + (*str >= 'A' && *str <= 'F')); + i++, str++) + { + if (*str >= '0' && *str <= '9') + hex = hex * 16 + (*str - '0'); + else if (*str >= 'a' && *str <= 'f') + hex = hex * 16 + (*str - 'a' + 10); + else if (*str >= 'A' && *str <= 'F') + hex = hex * 16 + (*str - 'A' + 10); + } + putchar(hex); + str--; + break; + } + default: + putchar(*str); + break; + } + } + else + { + putchar(*str); + } + str++; + } +} + +int main(int argc, char *argv[]) +{ + bool newline = true; + bool interpret_escapes = false; + int arg_start = 1; + + if (argc == 2) + { + if (strcmp(argv[1], "--help") == 0) + { + PrintHelp(); + exit(EXIT_SUCCESS); + } + else if (strcmp(argv[1], "--version") == 0) + { + PRINTF_VERSION; + exit(EXIT_SUCCESS); + } + } + + if (argc > 1) + { + for (int i = 1; i < argc; i++) + { + if (argv[i][0] == '-' && argv[i][1] != '\0') + { + for (size_t j = 1; argv[i][j] != '\0'; j++) + { + if (argv[i][j] == 'n') + newline = false; + else if (argv[i][j] == 'e') + interpret_escapes = true; + else if (argv[i][j] == 'E') + interpret_escapes = false; + else + goto print_args; + } + arg_start++; + } + else + { + break; + } + } + } + +print_args: + for (int i = arg_start; i < argc; i++) + { + if (interpret_escapes) + PrintEscaped(argv[i]); + else + fputs(argv[i], stdout); + if (i < argc - 1) + putchar(' '); + } + + if (newline) + putchar('\n'); + return 0; +}