├── Testcase ├── Statistics.bat ├── Alias.bat ├── Folder.bat ├── Fibonacci.bat ├── Process.bat ├── BaseSystem.bat ├── Function.bat ├── Directory.bat ├── File.bat ├── Variable.bat ├── Tree.bat ├── Expression.bat ├── Condition.bat └── Utility.bat ├── Document ├── report.pdf ├── handout.pdf ├── Template │ ├── images │ │ ├── 01.png │ │ ├── 03.png │ │ ├── 04.png │ │ ├── 05.png │ │ ├── 06.png │ │ ├── 07.png │ │ ├── 08.png │ │ ├── 09.png │ │ ├── 10.png │ │ ├── 11.png │ │ ├── 12.png │ │ ├── 13.png │ │ ├── 21.png │ │ └── 22.png │ ├── macro.tex │ ├── setup.tex │ └── main.tex └── AnalysisAndSolutionsForCriticalSectionManagement.pdf ├── Process ├── child.cpp ├── CMakeLists.txt ├── counter.c ├── duck.cpp ├── countdown.cpp ├── tictactoe.cpp └── unistd.h ├── Feature ├── exit_shell.h ├── dancing.h ├── clear_screen.h ├── features.h ├── scheduler.h ├── navigation.h ├── history.h ├── loop.h ├── set_color.h ├── manage_threads.h ├── run_script.h ├── bookmark.h ├── base_conversion.h ├── alias.h ├── conditional.h ├── variables.h ├── directory.h ├── system_utils.h ├── environment.h ├── help.h ├── function.h ├── file.h └── process.h ├── .gitignore ├── CMakeLists.txt ├── .github └── workflows │ └── release.yml ├── README.md ├── bug.txt └── main.cpp /Testcase/Statistics.bat: -------------------------------------------------------------------------------- 1 | time 2 | date 3 | uptime 4 | cpuinfo 5 | meminfo 6 | diskinfo C 7 | calculator -------------------------------------------------------------------------------- /Document/report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/report.pdf -------------------------------------------------------------------------------- /Document/handout.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/handout.pdf -------------------------------------------------------------------------------- /Process/child.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | Sleep(10000); 6 | return 0; 7 | } -------------------------------------------------------------------------------- /Testcase/Alias.bat: -------------------------------------------------------------------------------- 1 | alias h = function 2 | h f(x) = x 3 | alias h = help 4 | h 5 | alias h = history 6 | h 7 | alias 8 | h 9 | -------------------------------------------------------------------------------- /Document/Template/images/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/Template/images/01.png -------------------------------------------------------------------------------- /Document/Template/images/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/Template/images/03.png -------------------------------------------------------------------------------- /Document/Template/images/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/Template/images/04.png -------------------------------------------------------------------------------- /Document/Template/images/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/Template/images/05.png -------------------------------------------------------------------------------- /Document/Template/images/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/Template/images/06.png -------------------------------------------------------------------------------- /Document/Template/images/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/Template/images/07.png -------------------------------------------------------------------------------- /Document/Template/images/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/Template/images/08.png -------------------------------------------------------------------------------- /Document/Template/images/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/Template/images/09.png -------------------------------------------------------------------------------- /Document/Template/images/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/Template/images/10.png -------------------------------------------------------------------------------- /Document/Template/images/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/Template/images/11.png -------------------------------------------------------------------------------- /Document/Template/images/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/Template/images/12.png -------------------------------------------------------------------------------- /Document/Template/images/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/Template/images/13.png -------------------------------------------------------------------------------- /Document/Template/images/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/Template/images/21.png -------------------------------------------------------------------------------- /Document/Template/images/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/Template/images/22.png -------------------------------------------------------------------------------- /Document/AnalysisAndSolutionsForCriticalSectionManagement.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaiAu2501/Operating-System-Project/HEAD/Document/AnalysisAndSolutionsForCriticalSectionManagement.pdf -------------------------------------------------------------------------------- /Testcase/Folder.bat: -------------------------------------------------------------------------------- 1 | create "New Folder" 2 | create "New Folder\Folder 1" 3 | create "Folder 2" 4 | copy "New Folder\Folder 1" "New Folder\Folder 3" 5 | move "Folder 2" "New Folder\Folder 2" 6 | delete "New Folder" -------------------------------------------------------------------------------- /Testcase/Fibonacci.bat: -------------------------------------------------------------------------------- 1 | set_env a = 1 2 | set_env b = 1 3 | loop 10 set_env c = a + b & set_env a = b & set_env b = c 4 | print_env c 5 | unset_env a 6 | unset_env b 7 | unset_env c 8 | print_env a 9 | print_env b 10 | print_env c -------------------------------------------------------------------------------- /Feature/exit_shell.h: -------------------------------------------------------------------------------- 1 | #ifndef EXIT_SHELL_H 2 | #define EXIT_SHELL_H 3 | 4 | #include 5 | 6 | void exitShell() 7 | { 8 | std::cout << "Exiting Tiny Shell." << std::endl; 9 | exit(0); 10 | } 11 | 12 | #endif // EXIT_SHELL_H 13 | -------------------------------------------------------------------------------- /Testcase/Process.bat: -------------------------------------------------------------------------------- 1 | add_path Process\ 2 | is_in_path Process\ 3 | start_foreground countdown.exe 4 | start_foreground child_process.exe 5 | start_background countdown.exe 6 | start_background child_process.exe 7 | remove_path Proccess\ 8 | is_in_path Process\ -------------------------------------------------------------------------------- /Testcase/BaseSystem.bat: -------------------------------------------------------------------------------- 1 | convert 123 from 10 to 2 2 | convert 234 from 10 to 16 3 | convert 999 from 10 to 16 4 | convert 3E7 from 16 to 10 5 | convert 321 from 10 to 3 6 | convert 101010010101 from 2 to 10 7 | convert FFF from 16 to 10 8 | convert FFF from 16 to 2 9 | convert 2024 from 10 to 16 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ẩn tất cả các file có đuôi .exe (file thực thi) 2 | *.exe 3 | 4 | # Ẩn thư mục .vscode 5 | .vscode/ 6 | 7 | # Ẩn file lịch sử và mọi thứ liên quan 8 | history.txt 9 | hello.txt 10 | 11 | # Ẩn các thu mục không cần thiết 12 | .image/ 13 | 14 | # Ẩn thư mục Private 15 | Private/ 16 | 17 | build/ 18 | out/ 19 | install/ -------------------------------------------------------------------------------- /Testcase/Function.bat: -------------------------------------------------------------------------------- 1 | function f(x, y, z) = x*y*z 2 | set_env a = 2 3 | set_env b = 3 4 | set_env c = 4 5 | evaluate f 2 3 4 6 | evaluate f a b c 7 | evaluate f a 3 4 8 | set_env m = 10 9 | function g(x) = x*(m + 1) 10 | evaluate g 5 11 | evaluate g a 12 | evaluate g m 13 | unset_env m 14 | evaluate g 5 15 | set_env x = 5 16 | function h(x) = x + x*x 17 | evaluate h 3 18 | evaluate h x 19 | unset_env a 20 | unset_env b 21 | unset_env c 22 | unset_env x -------------------------------------------------------------------------------- /Testcase/Directory.bat: -------------------------------------------------------------------------------- 1 | pwd 2 | create "New Folder" 3 | cd "New Folder" 4 | create "Child Folder" 5 | cd .. 6 | pwd 7 | delete "New Folder\Child Folder" 8 | cd "New Folder" 9 | cd "Child Folder" 10 | cd .. 11 | pwd 12 | delete "New Folder" 13 | cd "New Folder" 14 | pwd 15 | create "Level 1" 16 | cd "Level 1" 17 | create "Level 2" 18 | cd "Level 2" 19 | create "Level 3" 20 | cd "Level 3" 21 | pwd 22 | cd .. 23 | pwd 24 | cd .. 25 | pwd 26 | cd .. 27 | pwd 28 | delete "Level 1" 29 | cd "Level 1" 30 | 31 | -------------------------------------------------------------------------------- /Testcase/File.bat: -------------------------------------------------------------------------------- 1 | write_file 2 number.txt 2 | write_file 5 number.txt 3 | write_file 3 number.txt ~LINE 2 4 | write_file 4 number.txt ~LINE 3 5 | write_file 1 number.txt ~HEAD 6 | write_file 6 number.txt 7 | write_file 8 number.txt 8 | write_file 7 number.txt ~LINE 7 9 | read_file number.txt 10 | read_file number.txt ~LINE 1 11 | read_file number.txt ~HEAD 3 12 | read_file number.txt ~RANGE 4 6 13 | read_file number.txt ~FOOT 3 14 | loop 12 write_file 9 number.txt 15 | file_size number.txt 16 | delete number.txt 17 | -------------------------------------------------------------------------------- /Process/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10.2) 2 | 3 | file(GLOB PROCESS_SOURCES *.cpp *.c) 4 | 5 | foreach(SOURCE_FILE ${PROCESS_SOURCES}) 6 | get_filename_component(EXECUTABLE_NAME ${SOURCE_FILE} NAME_WE) 7 | 8 | add_executable(${EXECUTABLE_NAME} ${SOURCE_FILE}) 9 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 10 | 11 | install(TARGETS ${EXECUTABLE_NAME} RUNTIME DESTINATION Process) 12 | endforeach() 13 | 14 | set_target_properties(countdown PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS") -------------------------------------------------------------------------------- /Testcase/Variable.bat: -------------------------------------------------------------------------------- 1 | set_env TRUE 1 2 | print_env TRUE 3 | set_env FALSE 0 4 | print_env FALSE 5 | if (1 + 1 == 2): print_env TRUE else print_env FALSE 6 | if ((1 + 1)*2 == 4): print_env TRUE else print_env FALSE 7 | if ((1 + 1 + (1 + 1)*2)*2 == 12): print_env TRUE else print_env FALSE 8 | if ((TRUE + TRUE)*2 == 4): print_env TRUE else print_env FALSE 9 | if ((TRUE + TRUE + (TRUE + TRUE)*2)*2 == 12): print_env TRUE else print_env FALSE 10 | if ((TRUE + TRUE*2 + TRUE*3 + TRUE*4)*FALSE == 0): print_env TRUE else print_env FALSE 11 | unset_env TRUE 12 | print_env TRUE 13 | unset_env FALSE 14 | print_env FALSE -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10.2) 2 | 3 | project(Operating-System-Project VERSION 1.0.0) 4 | 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED True) 7 | 8 | set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install") 9 | 10 | add_executable(Operating-System-Project main.cpp) 11 | add_definitions(-DNOMINMAX) 12 | 13 | install(TARGETS Operating-System-Project RUNTIME DESTINATION .) 14 | 15 | add_subdirectory(Process) 16 | 17 | install(DIRECTORY Testcase/ DESTINATION Testcase FILES_MATCHING PATTERN "*") 18 | 19 | install(DIRECTORY Document/ DESTINATION Document FILES_MATCHING PATTERN "*") -------------------------------------------------------------------------------- /Feature/dancing.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include // Để sử dụng std::this_thread::sleep_for 3 | #include // Để sử dụng std::chrono::milliseconds 4 | 5 | void dancing() 6 | { 7 | const char *dance[] = { 8 | " ~~(^-^~~)", 9 | " ~~(^-^)~~", 10 | " (~~^-^)~~"}; 11 | 12 | const int numDanceMoves = sizeof(dance) / sizeof(dance[0]); 13 | const int numLines = 30; 14 | const int delayMilliseconds = 500; 15 | 16 | for (int i = 0; i < numLines; ++i) 17 | { 18 | std::cout << dance[i % numDanceMoves] << '\r'; 19 | std::this_thread::sleep_for(std::chrono::milliseconds(delayMilliseconds)); 20 | } 21 | } -------------------------------------------------------------------------------- /Testcase/Tree.bat: -------------------------------------------------------------------------------- 1 | create "Parent\Child\Grandchild" 2 | list_tree Parent 3 | cd Parent\ 4 | cd Child\ 5 | cd Grandchild\ 6 | write_file "Hello World from Grandchild" "Hello.txt" 7 | read_file "Hello.txt" 8 | cd ..\..\.. 9 | pwd 10 | cd Parent 11 | create "AnotherChild" 12 | cd AnotherChild 13 | create "AnotherGrandchild" 14 | cd .. 15 | pwd 16 | cd .. 17 | list_tree Parent 18 | copy "Parent\Child" "Parent\Child (Copy)" 19 | copy "Parent\Child\Grandchild" "Parent\Child\Grandchild (Copy)" 20 | copy "Parent\AnotherChild" "Parent\AnotherChild (Copy)" 21 | copy "Parent\AnotherChild\AnotherGrandchild" "Parent\AnotherChild\AnotherGrandchild (Copy)" 22 | list_tree Parent 23 | delete "Parent" -------------------------------------------------------------------------------- /Testcase/Expression.bat: -------------------------------------------------------------------------------- 1 | calculate (3 + 5) * 2 - 16 2 | calculate ((2 + 3) * 4) / (6 - 2) - 5 3 | calculate 5 * (6 / (2 + 1)) - 10 4 | calculate (8 / 4) + (3 * (2 + 1)) - 11 5 | calculate (3 + 4 * 2) / (1 - 5) * (6 - 2) + 11 6 | calculate (1 + 3) * ((2 + 4) / 2) - 12 7 | calculate 10 - (2 * (3 + 4)) + 5 - 1 8 | calculate (12 / (2 + 1)) * (5 - 3) - 8 9 | calculate 4 + (3 * (2 - 1) / (4 / 4)) - 7 10 | calculate (5 * (4 + 3) - 2) / 3 - 11 11 | calculate ((3 + 2) * (5 - 1)) / (6 / 3) - 10 12 | calculate (8 / 2) * (3 + (4 - 1)) - 24 13 | calculate (7 - 4) * (2 + (3 * (5 / (4 - 1)))) - 21 14 | calculate (5 + (2 * 3)) - (7 / (1 * 1)) - 4 15 | calculate ((8 / 4) + (2 * 3)) - (5 - 1) - 4 16 | calculate (121 + 232 + 322 * 411 + 42 / 50 + (10 + 24 + (33 + 47) * 21) * 100) * 0 -------------------------------------------------------------------------------- /Document/Template/macro.tex: -------------------------------------------------------------------------------- 1 | % Định nghĩa macro 2 | \newcommand{\orange}[1]{\textbf{\textcolor{orange}{#1}}} 3 | \newcommand{\cyan}[1]{\textbf{\textcolor{cyan}{#1}}} 4 | \newcommand{\red}[1]{\textcolor{red}{\texttt{#1}}} 5 | 6 | \newcommand{\mc}[1]{\ensuremath{\mathcal{#1}}} 7 | \newcommand{\mb}[1]{\ensuremath{\mathbb{#1}}} 8 | 9 | \newcommand{\br}[1]{\ensuremath{\left( #1 \right)}} 10 | \newcommand{\brr}[1]{\ensuremath{\left[ #1 \right]}} 11 | \newcommand{\brrr}[1]{\ensuremath{\left\{ #1 \right\}}} 12 | \newcommand{\norm}[1]{\ensuremath{\lVert #1 \rVert_2}} 13 | 14 | \newcommand{\vs}{\vspace{5pt}} 15 | \newcommand{\rnn}[2]{\ensuremath{\mathbb{R}^{{#1}\times{#2}}}} 16 | \newcommand{\rnnn}[3]{\ensuremath{\mathbb{R}^{{#1}\times{#2}\times{#3}}}} 17 | 18 | \renewcommand{\v}[1]{\mathbf{#1}} 19 | 20 | \renewcommand{\t}[1]{\texttt{#1}} -------------------------------------------------------------------------------- /Testcase/Condition.bat: -------------------------------------------------------------------------------- 1 | set_env TRUE = 1 2 | print_env TRUE 3 | set_env FALSE = 0 4 | print_env FALSE 5 | set_env x = 1 6 | print_env x 7 | set_env y = 2 8 | print_env y 9 | set_env z = 3 10 | print_env z 11 | if (x + y == z): print_env TRUE else print_env FALSE 12 | if (x + y == 3): print_env TRUE else print_env FALSE 13 | if (1 + y == z): print_env TRUE else print_env FALSE 14 | if (x + 2 == z): print_env TRUE else print_env FALSE 15 | if (x + y != z): print_env TRUE else print_env FALSE 16 | if (x + y > z): print_env TRUE else print_env FALSE 17 | if (x + y >= z): print_env TRUE else print_env FALSE 18 | if (x + y < z): print_env TRUE else print_env FALSE 19 | if (x + y <= z): print_env TRUE else print_env FALSE 20 | unset_env x 21 | print_env x 22 | unset_env y 23 | print_env y 24 | unset_env z 25 | print_env z 26 | unset_env TRUE 27 | print_env TRUE 28 | unset_env FALSE 29 | print_env FALSE -------------------------------------------------------------------------------- /Testcase/Utility.bat: -------------------------------------------------------------------------------- 1 | set_env CURRENT_COLOR color 2 | change_color black 3 | print_env CURRENT_COLOR 4 | change_color blue 5 | print_env CURRENT_COLOR 6 | change_color green 7 | print_env CURRENT_COLOR 8 | change_color cyan 9 | print_env CURRENT_COLOR 10 | change_color red 11 | print_env CURRENT_COLOR 12 | change_color magenta 13 | print_env CURRENT_COLOR 14 | change_color yellow 15 | print_env CURRENT_COLOR 16 | change_color white 17 | print_env CURRENT_COLOR 18 | change_color gray 19 | print_env CURRENT_COLOR 20 | change_color light_blue 21 | print_env CURRENT_COLOR 22 | change_color light_green 23 | print_env CURRENT_COLOR 24 | change_color light_cyan 25 | print_env CURRENT_COLOR 26 | change_color light_red 27 | print_env CURRENT_COLOR 28 | change_color light_magenta 29 | print_env CURRENT_COLOR 30 | change_color light_yellow 31 | print_env CURRENT_COLOR 32 | change_color bright_white 33 | print_env CURRENT_COLOR 34 | change_color while 35 | print_env CURRENT_COLOR 36 | unset_env CURRENT_COLOR 37 | print_env CURRENT_COLOR -------------------------------------------------------------------------------- /Process/counter.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const int SPAN = 2; 5 | const int BASE = 10; 6 | 7 | void sleep_for(unsigned int secs); 8 | 9 | int main(int argc, char *argv[]) { 10 | if(argc != 2) { 11 | printf("Usage: counter \n"); 12 | return 1; 13 | } 14 | 15 | int n = 0; 16 | char *endptr = NULL; 17 | 18 | n = (int)strtol(argv[1], &endptr, BASE); 19 | 20 | if(*endptr != '\0') { 21 | printf("Invalid argument: %s\n", argv[1]); 22 | return 1; 23 | } 24 | 25 | for(int i = 0; i <= n; ++i) { 26 | printf("Second %d.\n", i); 27 | sleep_for(SPAN); 28 | } 29 | return 0; 30 | } 31 | 32 | #ifdef _WIN32 33 | #include 34 | void sleep_for(unsigned int seconds) { 35 | static const unsigned int milli_per_sec = 1000; 36 | Sleep(seconds * milli_per_sec); 37 | } 38 | #elif defined(__linux__) 39 | # include 40 | void sleep_for(unsigned int seconds) { 41 | sleep(seconds); // NOLINT 42 | } 43 | #endif -------------------------------------------------------------------------------- /Feature/clear_screen.h: -------------------------------------------------------------------------------- 1 | // clear_screen.h 2 | #ifndef CLEAR_SCREEN_H 3 | #define CLEAR_SCREEN_H 4 | 5 | #include 6 | 7 | // Hàm xóa màn hình 8 | void clearScreen() 9 | { 10 | HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); 11 | CONSOLE_SCREEN_BUFFER_INFO csbi; 12 | DWORD count; 13 | DWORD cellCount; 14 | COORD homeCoords = {0, 0}; 15 | 16 | if (hStdOut == INVALID_HANDLE_VALUE) 17 | return; 18 | 19 | // Lấy thông tin buffer hiện tại 20 | if (!GetConsoleScreenBufferInfo(hStdOut, &csbi)) 21 | return; 22 | cellCount = csbi.dwSize.X * csbi.dwSize.Y; 23 | 24 | // Lấp đầy màn hình với khoảng trắng 25 | if (!FillConsoleOutputCharacter(hStdOut, (TCHAR)' ', cellCount, homeCoords, &count)) 26 | return; 27 | 28 | // Đặt lại các thuộc tính màn hình hiện tại 29 | if (!FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count)) 30 | return; 31 | 32 | // Đặt lại con trỏ về vị trí đầu tiên 33 | SetConsoleCursorPosition(hStdOut, homeCoords); 34 | } 35 | 36 | #endif // CLEAR_SCREEN_H 37 | -------------------------------------------------------------------------------- /Feature/features.h: -------------------------------------------------------------------------------- 1 | #ifndef FEATURES_H 2 | #define FEATURES_H 3 | 4 | // QUẢN LÝ TỆP VÀ THƯ MỤC (9) 5 | #include "directory.h" // 4 lệnh 6 | #include "file.h" // 5 lệnh 7 | 8 | // QUẢN LÝ TIẾN TRÌNH (11) 9 | #include "process.h" // 11 lệnh 10 | #include "manage_threads.h" // 1 lệnh 11 | 12 | // HỆ THỐNG VÀ TIỆN ÍCH (17) 13 | #include "run_script.h" // 1 lệnh 14 | #include "system_utils.h" // 7 lệnh 15 | #include "scheduler.h" // 1 lệnh 16 | #include "alias.h" // 3 lệnh 17 | #include "bookmark.h" // 4 lệnh 18 | #include "set_color.h" // 1 lệnh 19 | 20 | // TÍNH TOÁN NÂNG CAO (18) 21 | #include "variables.h" // 0 lệnh 22 | #include "dancing.h" // 0 lệnh 23 | #include "function.h" // 2 lệnh 24 | #include "conditional.h" // 1 lệnh 25 | #include "environment.h" // 9 lệnh 26 | #include "loop.h" // 1 lệnh 27 | #include "base_conversion.h" // 1 lệnh 28 | 29 | // ĐIỀU HƯỚNG VÀ GIAO DIỆN (10) 30 | #include "navigation.h" // 5 lệnh 31 | #include "exit_shell.h" // 1 lệnh 32 | #include "help.h" // 1 lệnh 33 | #include "history.h" // 2 lệnh 34 | #include "clear_screen.h" // 1 lệnh 35 | 36 | #endif // FEATURES_H 37 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | release: 13 | runs-on: windows-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | 19 | - name: Setup MSVC Developer Command Prompt 20 | uses: TheMrMilchmann/setup-msvc-dev@v3 21 | with: 22 | arch: x64 23 | 24 | - name: Install ninja-build tool 25 | uses: seanmiddleditch/gha-setup-ninja@v5 26 | 27 | - name: Build project 28 | run: | 29 | mkdir build 30 | cd build 31 | cmake .. -G Ninja -DCMAKE_BUILD_TYPE=MinSizeRel 32 | cmake --build . --target install --config MinSizeRel 33 | 34 | - name: Zip the build 35 | run: | 36 | cd install 37 | 7z a ../Operating-System-Project.x64.zip * 38 | 39 | - name: GH Release 40 | uses: softprops/action-gh-release@v2 41 | with: 42 | name: Operating-System-Project 43 | tag_name: 1.0.0 44 | files: | 45 | Operating-System-Project.x64.zip 46 | -------------------------------------------------------------------------------- /Feature/scheduler.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEDULER_H 2 | #define SCHEDULER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void executeCommand(const std::string &command, const std::vector &args); 12 | 13 | void scheduleCommand(const std::vector &args) 14 | { 15 | if (args.size() < 3 || args[1] != "s") 16 | { 17 | std::cerr << "Usage: after s " << std::endl; 18 | return; 19 | } 20 | 21 | int delay; 22 | try 23 | { 24 | delay = std::stoi(args[0]); 25 | } 26 | catch (const std::exception &e) 27 | { 28 | std::cerr << "Invalid number: " << args[0] << std::endl; 29 | return; 30 | } 31 | 32 | std::string command = args[2]; 33 | std::vector commandArgs(args.begin() + 3, args.end()); 34 | 35 | std::thread([=]() 36 | { 37 | std::this_thread::sleep_for(std::chrono::seconds(delay)); 38 | std::cout << "\nThe thread is completed!" << std::endl; 39 | executeCommand(command, commandArgs); }) 40 | .detach(); 41 | 42 | std::cout << "Scheduled command '" << command << "' to run after " << delay << " seconds." << std::endl; 43 | } 44 | 45 | #endif // SCHEDULER_H 46 | -------------------------------------------------------------------------------- /Feature/navigation.h: -------------------------------------------------------------------------------- 1 | #ifndef NAVIGATION_H 2 | #define NAVIGATION_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void changeDirectory(const std::vector &args) 9 | { 10 | if (args.size() != 1) 11 | { 12 | std::cout << "Usage: cd " << std::endl; 13 | return; 14 | } 15 | std::filesystem::path dirPath = args[0]; 16 | if (!std::filesystem::exists(dirPath) || !std::filesystem::is_directory(dirPath)) 17 | { 18 | std::cout << "Directory does not exist: " << dirPath << std::endl; 19 | return; 20 | } 21 | std::filesystem::current_path(dirPath); 22 | std::cout << "Changed directory to " << dirPath << std::endl; 23 | } 24 | 25 | void listDirectoryContents(const std::vector &args) 26 | { 27 | std::filesystem::path dirPath = "."; 28 | if (args.size() == 1) 29 | { 30 | dirPath = args[0]; 31 | } 32 | if (!std::filesystem::exists(dirPath) || !std::filesystem::is_directory(dirPath)) 33 | { 34 | std::cout << "Directory does not exist: " << dirPath << std::endl; 35 | return; 36 | } 37 | for (const auto &entry : std::filesystem::directory_iterator(dirPath)) 38 | { 39 | std::cout << entry.path().filename().string() << (entry.is_directory() ? "/" : "") << std::endl; 40 | } 41 | } 42 | 43 | void printWorkingDirectory(const std::vector &args) 44 | { 45 | std::cout << std::filesystem::current_path().string() << std::endl; 46 | } 47 | 48 | #endif // NAVIGATION_H 49 | -------------------------------------------------------------------------------- /Process/duck.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "unistd.h" 3 | #include 4 | #include 5 | 6 | void clearScreen() 7 | { 8 | printf("\033[H\033[J"); 9 | } 10 | 11 | void printDuck(int position, int quack) 12 | { 13 | for (int i = 0; i < position; i++) 14 | { 15 | printf(" "); 16 | } 17 | if (quack % 10 == 0) 18 | { 19 | printf("__(.)< QUACK\n"); 20 | } 21 | else 22 | { 23 | printf("__(.)<\n"); 24 | } 25 | for (int i = 0; i < position; i++) 26 | { 27 | printf(" "); 28 | } 29 | printf("\\___) \n"); 30 | for (int i = 0; i < position - 6; i++) 31 | { // Dịch làn sóng sang trái một chút 32 | printf(" "); 33 | } 34 | printf("~~~~~~~~~~~~~~~~~~\n"); 35 | } 36 | 37 | void usleep(unsigned int usec) 38 | { 39 | HANDLE timer; 40 | LARGE_INTEGER ft; 41 | 42 | ft.QuadPart = -(10 * (__int64)usec); 43 | 44 | timer = CreateWaitableTimer(NULL, TRUE, NULL); 45 | SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); 46 | WaitForSingleObject(timer, INFINITE); 47 | CloseHandle(timer); 48 | } 49 | 50 | int main() 51 | { 52 | int width = 80; // Width of the terminal 53 | int position = 0; 54 | int quack = 0; 55 | 56 | while (1) 57 | { 58 | clearScreen(); 59 | printDuck(position, quack); 60 | position++; 61 | quack++; 62 | if (position >= width) 63 | { 64 | position = 0; 65 | } 66 | usleep(100000); // Delay for 100 milliseconds 67 | } 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /Feature/history.h: -------------------------------------------------------------------------------- 1 | // history.h 2 | #ifndef HISTORY_H 3 | #define HISTORY_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // Lưu trữ lịch sử các câu lệnh đã nhập vào 11 | class CommandHistory 12 | { 13 | private: 14 | std::vector history; 15 | const std::string historyFile = "history.txt"; 16 | 17 | public: 18 | // Thêm câu lệnh vào lịch sử 19 | void add(const std::string &command) 20 | { 21 | history.push_back(command); 22 | // Ghi lịch sử vào file 23 | std::ofstream outFile(historyFile, std::ios::app); 24 | if (outFile.is_open()) 25 | { 26 | outFile << command << std::endl; 27 | outFile.close(); 28 | } 29 | } 30 | 31 | // Hiển thị lịch sử các câu lệnh 32 | void show() const 33 | { 34 | for (const std::string &cmd : history) 35 | { 36 | std::cout << cmd << std::endl; 37 | } 38 | } 39 | 40 | // Tải lịch sử từ file (nếu có) 41 | void load() 42 | { 43 | std::ifstream inFile(historyFile); 44 | if (inFile.is_open()) 45 | { 46 | std::string line; 47 | while (std::getline(inFile, line)) 48 | { 49 | history.push_back(line); 50 | } 51 | inFile.close(); 52 | } 53 | } 54 | 55 | // Xóa lịch sử 56 | void clear() 57 | { 58 | history.clear(); 59 | // Xóa nội dung của file 60 | std::ofstream outFile(historyFile, std::ios::trunc); 61 | if (outFile.is_open()) 62 | { 63 | outFile.close(); 64 | } 65 | } 66 | }; 67 | 68 | #endif // HISTORY_H 69 | -------------------------------------------------------------------------------- /Feature/loop.h: -------------------------------------------------------------------------------- 1 | #ifndef LOOP_H 2 | #define LOOP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void executeCommand(const std::string &command, const std::vector &args); 10 | 11 | // Hàm tách các lệnh bằng dấu '&' 12 | std::vector> splitCommands(const std::vector &args) 13 | { 14 | std::vector> commands; 15 | std::vector currentCommand; 16 | 17 | for (const std::string &arg : args) 18 | { 19 | if (arg == "&") 20 | { 21 | if (!currentCommand.empty()) 22 | { 23 | commands.push_back(currentCommand); 24 | currentCommand.clear(); 25 | } 26 | } 27 | else 28 | { 29 | currentCommand.push_back(arg); 30 | } 31 | } 32 | 33 | if (!currentCommand.empty()) 34 | { 35 | commands.push_back(currentCommand); 36 | } 37 | 38 | return commands; 39 | } 40 | 41 | void handleLoop(const std::vector &args) 42 | { 43 | if (args.size() < 2) 44 | { 45 | throw std::runtime_error("Usage: loop & & ..."); 46 | } 47 | 48 | int iterations; 49 | try 50 | { 51 | iterations = std::stoi(args[0]); 52 | } 53 | catch (const std::exception &) 54 | { 55 | throw std::runtime_error("Invalid number of iterations."); 56 | } 57 | 58 | std::vector> commands = splitCommands(std::vector(args.begin() + 1, args.end())); 59 | 60 | for (int i = 0; i < iterations; ++i) 61 | { 62 | for (const auto &command : commands) 63 | { 64 | if (!command.empty()) 65 | { 66 | std::string cmd = command[0]; 67 | std::vector cmdArgs(command.begin() + 1, command.end()); 68 | executeCommand(cmd, cmdArgs); 69 | } 70 | } 71 | } 72 | } 73 | 74 | #endif // LOOP_H 75 | -------------------------------------------------------------------------------- /Feature/set_color.h: -------------------------------------------------------------------------------- 1 | #ifndef SET_COLOR_H 2 | #define SET_COLOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | enum class ConsoleColor 9 | { 10 | BLACK = 0, 11 | BLUE = 1, 12 | GREEN = 2, 13 | CYAN = 3, 14 | RED = 4, 15 | MAGENTA = 5, 16 | YELLOW = 6, 17 | WHITE = 7, 18 | GRAY = 8, 19 | LIGHT_BLUE = 9, 20 | LIGHT_GREEN = 10, 21 | LIGHT_CYAN = 11, 22 | LIGHT_RED = 12, 23 | LIGHT_MAGENTA = 13, 24 | LIGHT_YELLOW = 14, 25 | BRIGHT_WHITE = 15 26 | }; 27 | 28 | void setColor(ConsoleColor color) 29 | { 30 | HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 31 | SetConsoleTextAttribute(hConsole, static_cast(color)); 32 | } 33 | 34 | void resetColor() 35 | { 36 | setColor(ConsoleColor::WHITE); 37 | } 38 | 39 | ConsoleColor parseColor(const std::string &colorName) 40 | { 41 | if (colorName == "black") 42 | return ConsoleColor::BLACK; 43 | if (colorName == "blue") 44 | return ConsoleColor::BLUE; 45 | if (colorName == "green") 46 | return ConsoleColor::GREEN; 47 | if (colorName == "cyan") 48 | return ConsoleColor::CYAN; 49 | if (colorName == "red") 50 | return ConsoleColor::RED; 51 | if (colorName == "magenta") 52 | return ConsoleColor::MAGENTA; 53 | if (colorName == "yellow") 54 | return ConsoleColor::YELLOW; 55 | if (colorName == "white") 56 | return ConsoleColor::WHITE; 57 | if (colorName == "gray") 58 | return ConsoleColor::GRAY; 59 | if (colorName == "light_blue") 60 | return ConsoleColor::LIGHT_BLUE; 61 | if (colorName == "light_green") 62 | return ConsoleColor::LIGHT_GREEN; 63 | if (colorName == "light_cyan") 64 | return ConsoleColor::LIGHT_CYAN; 65 | if (colorName == "light_red") 66 | return ConsoleColor::LIGHT_RED; 67 | if (colorName == "light_magenta") 68 | return ConsoleColor::LIGHT_MAGENTA; 69 | if (colorName == "light_yellow") 70 | return ConsoleColor::LIGHT_YELLOW; 71 | if (colorName == "bright_white") 72 | return ConsoleColor::BRIGHT_WHITE; 73 | 74 | return ConsoleColor::WHITE; // Default color if no match 75 | } 76 | 77 | #endif // SET_COLOR_H 78 | -------------------------------------------------------------------------------- /Feature/manage_threads.h: -------------------------------------------------------------------------------- 1 | #ifndef MANAGE_THREADS_H 2 | #define MANAGE_THREADS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // Biến chung (critical resource) 10 | int sharedVariable = 0; 11 | 12 | // Semaphore để kiểm soát truy cập vào biến chung 13 | HANDLE semaphore; 14 | 15 | // Hàm để mỗi luồng sử dụng tài nguyên găng 16 | DWORD WINAPI threadFunction(LPVOID lpParam) 17 | { 18 | int threadId = *reinterpret_cast(lpParam); 19 | 20 | for (int i = 0; i < 5; ++i) 21 | { 22 | // Chờ để lấy quyền truy cập vào tài nguyên găng 23 | WaitForSingleObject(semaphore, INFINITE); 24 | 25 | // Sử dụng tài nguyên găng 26 | std::cout << "Thread " << threadId << " is accessing the shared variable." << std::endl; 27 | sharedVariable++; 28 | std::cout << "Shared variable is now: " << sharedVariable << std::endl; 29 | 30 | // Nhả quyền truy cập vào tài nguyên găng 31 | ReleaseSemaphore(semaphore, 1, NULL); 32 | 33 | // Giả lập thời gian xử lý 34 | Sleep(1000); 35 | } 36 | 37 | return 0; 38 | } 39 | 40 | // Hàm để tạo và quản lý các luồng 41 | void createAndManageThreads(int numThreads) 42 | { 43 | // Tạo Semaphore với giá trị ban đầu là 1 và giới hạn là 1 44 | semaphore = CreateSemaphore(NULL, 1, 1, NULL); 45 | if (semaphore == NULL) 46 | { 47 | std::cerr << "CreateSemaphore error: " << GetLastError() << std::endl; 48 | return; 49 | } 50 | 51 | std::vector threads(numThreads); 52 | std::vector threadIds(numThreads); 53 | 54 | // Tạo các luồng 55 | for (int i = 0; i < numThreads; ++i) 56 | { 57 | threadIds[i] = i + 1; 58 | threads[i] = CreateThread(NULL, 0, threadFunction, &threadIds[i], 0, NULL); 59 | if (threads[i] == NULL) 60 | { 61 | std::cerr << "CreateThread error: " << GetLastError() << std::endl; 62 | return; 63 | } 64 | } 65 | 66 | // Chờ tất cả các luồng kết thúc 67 | WaitForMultipleObjects(numThreads, threads.data(), TRUE, INFINITE); 68 | 69 | // Đóng các handle của luồng 70 | for (int i = 0; i < numThreads; ++i) 71 | { 72 | CloseHandle(threads[i]); 73 | } 74 | 75 | // Đóng Semaphore 76 | CloseHandle(semaphore); 77 | } 78 | 79 | // Hàm xử lý lệnh manage_threads 80 | void handleManageThreadsCommand(const std::vector &args) 81 | { 82 | if (args.size() != 1) 83 | { 84 | std::cout << "Usage: manage_threads " << std::endl; 85 | } 86 | else 87 | { 88 | int numThreads = std::stoi(args[0]); 89 | createAndManageThreads(numThreads); 90 | } 91 | } 92 | 93 | #endif // MANAGE_THREADS_H 94 | -------------------------------------------------------------------------------- /Feature/run_script.h: -------------------------------------------------------------------------------- 1 | #ifndef RUN_SCRIPT_H 2 | #define RUN_SCRIPT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include // For std::getenv 10 | 11 | void executeCommand(const std::string &command, const std::vector &args); 12 | 13 | std::vector splitInput(const std::string &input); 14 | 15 | std::string resolvePath(const std::string &path) 16 | { 17 | // Check if the path is absolute 18 | if (std::filesystem::path(path).is_absolute()) 19 | { 20 | return path; 21 | } 22 | 23 | // Check if the file exists in the current directory 24 | if (std::filesystem::exists(path)) 25 | { 26 | return std::filesystem::absolute(path).string(); 27 | } 28 | 29 | // Check in PATH environment variable 30 | const char *pathEnv = std::getenv("PATH"); 31 | if (pathEnv) 32 | { 33 | std::vector paths; 34 | std::string pathEnvStr(pathEnv); 35 | std::string delimiter = ";"; // Use ';' as the delimiter for Windows PATH 36 | 37 | size_t pos = 0; 38 | std::string token; 39 | while ((pos = pathEnvStr.find(delimiter)) != std::string::npos) 40 | { 41 | token = pathEnvStr.substr(0, pos); 42 | paths.push_back(token); 43 | pathEnvStr.erase(0, pos + delimiter.length()); 44 | } 45 | paths.push_back(pathEnvStr); 46 | 47 | for (const auto &p : paths) 48 | { 49 | std::filesystem::path filePath = std::filesystem::path(p) / path; 50 | if (std::filesystem::exists(filePath)) 51 | { 52 | return std::filesystem::absolute(filePath).string(); 53 | } 54 | } 55 | } 56 | 57 | // Return the original path if no resolution found 58 | return path; 59 | } 60 | 61 | void runScript(const std::vector &args) 62 | { 63 | if (args.size() != 1) 64 | { 65 | std::cout << "Usage: run " << std::endl; 66 | return; 67 | } 68 | 69 | std::string scriptPath = resolvePath(args[0]); 70 | std::ifstream scriptFile(scriptPath); 71 | if (!scriptFile) 72 | { 73 | std::cout << "Unable to open script file: " << scriptPath << std::endl; 74 | return; 75 | } 76 | 77 | std::string line; 78 | while (std::getline(scriptFile, line)) 79 | { 80 | std::vector tokens = splitInput(line); 81 | if (!tokens.empty()) 82 | { 83 | std::string command = tokens[0]; 84 | tokens.erase(tokens.begin()); 85 | executeCommand(command, tokens); 86 | } 87 | } 88 | scriptFile.close(); 89 | } 90 | 91 | #endif // RUN_SCRIPT_H 92 | -------------------------------------------------------------------------------- /Feature/bookmark.h: -------------------------------------------------------------------------------- 1 | #ifndef BOOKMARK_H 2 | #define BOOKMARK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class BookmarkManager 10 | { 11 | public: 12 | BookmarkManager() 13 | { 14 | initialDirectory = std::filesystem::current_path(); 15 | } 16 | 17 | // Hàm để thêm bookmark 18 | void addBookmark(const std::string &name, const std::string &path) 19 | { 20 | if (!std::filesystem::exists(path)) 21 | { 22 | std::cerr << "Error: Path does not exist: " << path << std::endl; 23 | return; 24 | } 25 | bookmarks[name] = path; 26 | std::cout << "Bookmark added: " << name << " -> " << path << std::endl; 27 | } 28 | 29 | // Hàm để xóa bookmark 30 | void removeBookmark(const std::string &name) 31 | { 32 | if (bookmarks.erase(name)) 33 | { 34 | std::cout << "Bookmark removed: " << name << std::endl; 35 | } 36 | else 37 | { 38 | std::cerr << "Error: Bookmark not found: " << name << std::endl; 39 | } 40 | } 41 | 42 | // Hàm để liệt kê tất cả các bookmark 43 | void listBookmarks() const 44 | { 45 | if (bookmarks.empty()) 46 | { 47 | std::cout << "No bookmarks available." << std::endl; 48 | return; 49 | } 50 | for (const auto &bookmark : bookmarks) 51 | { 52 | std::cout << bookmark.first << " -> " << bookmark.second << std::endl; 53 | } 54 | } 55 | 56 | // Hàm để chuyển đến thư mục đã được bookmark 57 | void goBookmark(const std::string &name) 58 | { 59 | auto it = bookmarks.find(name); 60 | if (it != bookmarks.end()) 61 | { 62 | if (std::filesystem::exists(it->second)) 63 | { 64 | std::filesystem::current_path(it->second); 65 | std::cout << "Changed directory to: " << it->second << std::endl; 66 | } 67 | else 68 | { 69 | std::cerr << "Error: Path does not exist: " << it->second << std::endl; 70 | } 71 | } 72 | else 73 | { 74 | std::cerr << "Error: Bookmark not found: " << name << std::endl; 75 | } 76 | } 77 | 78 | // Hàm để chuyển đến thư mục gốc 79 | void goHomeDirectory() 80 | { 81 | if (std::filesystem::exists(initialDirectory)) 82 | { 83 | std::filesystem::current_path(initialDirectory); 84 | std::cout << "Changed directory to initial directory: " << initialDirectory << std::endl; 85 | } 86 | else 87 | { 88 | std::cerr << "Error: Initial directory does not exist: " << initialDirectory << std::endl; 89 | } 90 | } 91 | 92 | private: 93 | std::unordered_map bookmarks; 94 | std::filesystem::path initialDirectory; 95 | }; 96 | 97 | #endif // BOOKMARK_H 98 | -------------------------------------------------------------------------------- /Feature/base_conversion.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_CONVERSION_H 2 | #define BASE_CONVERSION_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Hàm kiểm tra tính hợp lệ của số theo hệ cơ số 13 | bool isValidNumberForBase(const std::string &number, int base) 14 | { 15 | for (char digit : number) 16 | { 17 | if (std::isdigit(digit)) 18 | { 19 | if (digit - '0' >= base) 20 | { 21 | return false; 22 | } 23 | } 24 | else 25 | { 26 | if (std::toupper(digit) - 'A' + 10 >= base) 27 | { 28 | return false; 29 | } 30 | } 31 | } 32 | return true; 33 | } 34 | 35 | // Hàm chuyển đổi số từ hệ cơ số này sang hệ cơ số khác 36 | std::string convertBase(const std::string &number, int fromBase, int toBase) 37 | { 38 | // Kiểm tra tính hợp lệ của số theo hệ cơ số ban đầu 39 | if (!isValidNumberForBase(number, fromBase)) 40 | { 41 | throw std::runtime_error("Invalid number for the given base: " + number + " for base " + std::to_string(fromBase)); 42 | } 43 | 44 | // Hàm trợ giúp chuyển đổi số từ bất kỳ hệ cơ số nào sang hệ cơ số 10 45 | auto toDecimal = [](const std::string &num, int base) -> long long 46 | { 47 | long long value = 0; 48 | for (char digit : num) 49 | { 50 | if (std::isdigit(digit)) 51 | value = value * base + (digit - '0'); 52 | else 53 | value = value * base + (std::toupper(digit) - 'A' + 10); 54 | } 55 | return value; 56 | }; 57 | 58 | // Hàm trợ giúp chuyển đổi số từ hệ cơ số 10 sang bất kỳ hệ cơ số nào khác 59 | auto fromDecimal = [](long long num, int base) -> std::string 60 | { 61 | std::string result; 62 | const char digits[] = "0123456789ABCDEF"; 63 | while (num > 0) 64 | { 65 | result += digits[num % base]; 66 | num /= base; 67 | } 68 | std::reverse(result.begin(), result.end()); 69 | return result.empty() ? "0" : result; 70 | }; 71 | 72 | long long decimalValue = toDecimal(number, fromBase); 73 | return fromDecimal(decimalValue, toBase); 74 | } 75 | 76 | // Hàm xử lý lệnh chuyển đổi hệ cơ số 77 | void handleBaseConversion(const std::vector &args) 78 | { 79 | if (args.size() != 5 || args[1] != "from" || args[3] != "to") 80 | { 81 | std::cerr << "Usage: convert from to " << std::endl; 82 | return; 83 | } 84 | 85 | std::string number = args[0]; 86 | int fromBase = std::stoi(args[2]); 87 | int toBase = std::stoi(args[4]); 88 | 89 | if (fromBase < 2 || fromBase > 36 || toBase < 2 || toBase > 36) 90 | { 91 | std::cerr << "Base must be between 2 and 36." << std::endl; 92 | return; 93 | } 94 | 95 | try 96 | { 97 | std::string result = convertBase(number, fromBase, toBase); 98 | std::cout << "Result: " << result << std::endl; 99 | } 100 | catch (const std::exception &e) 101 | { 102 | std::cerr << "Error: " << e.what() << std::endl; 103 | } 104 | } 105 | 106 | #endif // BASE_CONVERSION_H 107 | -------------------------------------------------------------------------------- /Process/countdown.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // To compile: g++ -o countdown countdown.cpp -lgdi32 6 | 7 | #define IDT_TIMER1 1 8 | 9 | LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 10 | { 11 | static int counter = 10; 12 | static HFONT hFont; 13 | 14 | switch (uMsg) 15 | { 16 | case WM_CREATE: 17 | // Set a timer to update the counter every second 18 | SetTimer(hwnd, IDT_TIMER1, 1000, (TIMERPROC)NULL); 19 | // Create a font for the text 20 | hFont = CreateFont(72, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, 21 | OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, 22 | _T("Arial")); 23 | break; 24 | case WM_TIMER: 25 | if (wParam == IDT_TIMER1) 26 | { 27 | // Decrement the counter 28 | counter--; 29 | // Invalidate the window to force a redraw 30 | InvalidateRect(hwnd, NULL, TRUE); 31 | // Close the window when the counter reaches 0 32 | if (counter < 0) 33 | { 34 | KillTimer(hwnd, IDT_TIMER1); 35 | PostMessage(hwnd, WM_CLOSE, 0, 0); 36 | } 37 | } 38 | break; 39 | case WM_PAINT: 40 | { 41 | PAINTSTRUCT ps; 42 | HDC hdc = BeginPaint(hwnd, &ps); 43 | // Set the background color 44 | SetBkColor(hdc, RGB(255, 255, 255)); 45 | // Set the text color 46 | SetTextColor(hdc, RGB(0, 0, 0)); 47 | // Select the font into the DC 48 | SelectObject(hdc, hFont); 49 | // Convert the counter to a string 50 | TCHAR szCounter[3]; 51 | _stprintf(szCounter, _T("%d"), counter); 52 | // Get the dimensions of the window 53 | RECT rect; 54 | GetClientRect(hwnd, &rect); 55 | // Draw the text in the center of the window 56 | DrawText(hdc, szCounter, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); 57 | EndPaint(hwnd, &ps); 58 | } 59 | break; 60 | case WM_DESTROY: 61 | DeleteObject(hFont); 62 | PostQuitMessage(0); 63 | break; 64 | default: 65 | return DefWindowProc(hwnd, uMsg, wParam, lParam); 66 | } 67 | return 0; 68 | } 69 | 70 | int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) 71 | { 72 | const TCHAR szWindowClass[] = _T("CountdownApp"); 73 | const TCHAR szTitle[] = _T("Countdown Timer"); 74 | 75 | WNDCLASS wc = {}; 76 | wc.lpfnWndProc = WindowProc; 77 | wc.hInstance = hInstance; 78 | wc.lpszClassName = szWindowClass; 79 | wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 80 | 81 | RegisterClass(&wc); 82 | 83 | HWND hwnd = CreateWindowEx( 84 | 0, 85 | szWindowClass, 86 | szTitle, 87 | WS_OVERLAPPEDWINDOW, 88 | CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, 89 | NULL, 90 | NULL, 91 | hInstance, 92 | NULL); 93 | 94 | if (!hwnd) 95 | { 96 | return 0; 97 | } 98 | 99 | ShowWindow(hwnd, nCmdShow); 100 | UpdateWindow(hwnd); 101 | 102 | MSG msg = {}; 103 | while (GetMessage(&msg, NULL, 0, 0)) 104 | { 105 | TranslateMessage(&msg); 106 | DispatchMessage(&msg); 107 | } 108 | 109 | return (int)msg.wParam; 110 | } 111 | -------------------------------------------------------------------------------- /Feature/alias.h: -------------------------------------------------------------------------------- 1 | #ifndef ALIAS_H 2 | #define ALIAS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class AliasManager 10 | { 11 | public: 12 | AliasManager() 13 | { 14 | // Danh sách các lệnh hỗ trợ 15 | validCommands = { 16 | "delete", 17 | "move", 18 | "list_tree", 19 | "create", 20 | "copy", 21 | "open", 22 | "rename", 23 | "start_foreground", 24 | "start_background", 25 | "terminate", 26 | "list_processes", 27 | "child", 28 | "manage_threads", 29 | "list_children", 30 | "suspend", 31 | "resume", 32 | "after", 33 | "run", 34 | "calculator", 35 | "time", 36 | "date", 37 | "uptime", 38 | "cpuinfo", 39 | "meminfo", 40 | "diskinfo", 41 | "change_color", 42 | "calculate", 43 | "function", 44 | "evaluate", 45 | "if else", 46 | "loop", 47 | "convert", 48 | "alias", 49 | "unalias", 50 | "bookmark", 51 | "add_path", 52 | "remove_path", 53 | "print_env", 54 | "set_env", 55 | "unset_env", 56 | "is_in_path", 57 | "list_env", 58 | "save_env", 59 | "load_env", 60 | "write_file", 61 | "read_file", 62 | "file_size", 63 | "dancing", 64 | "tictactoe", 65 | "duck", 66 | "cd", 67 | "dir", 68 | "pwd", 69 | "exit", 70 | "help", 71 | "history", 72 | "clear", 73 | "clear_history"}; 74 | } 75 | 76 | // Hàm để thêm alias 77 | void addAlias(const std::string &name, const std::string &command) 78 | { 79 | if (validCommands.find(command) == validCommands.end()) 80 | { 81 | std::cerr << "Error: Command '" << command << "' is not supported." << std::endl; 82 | return; 83 | } 84 | 85 | if (validCommands.find(name) != validCommands.end()) 86 | { 87 | std::cerr << "Error: Alias name '" << name << "' conflicts with an existing command." << std::endl; 88 | return; 89 | } 90 | 91 | aliases[name] = command; 92 | std::cout << "Alias added: " << name << " -> " << command << std::endl; 93 | } 94 | 95 | // Hàm để xóa alias 96 | void removeAlias(const std::string &name) 97 | { 98 | if (aliases.erase(name)) 99 | { 100 | std::cout << "Alias removed: " << name << std::endl; 101 | } 102 | else 103 | { 104 | std::cerr << "Alias not found: " << name << std::endl; 105 | } 106 | } 107 | 108 | // Hàm để hiển thị tất cả các alias 109 | void listAliases() const 110 | { 111 | for (const auto &alias : aliases) 112 | { 113 | std::cout << alias.first << " -> " << alias.second << std::endl; 114 | } 115 | } 116 | 117 | // Hàm để tìm và thay thế alias trong lệnh 118 | std::string resolveAlias(const std::string &command) const 119 | { 120 | auto it = aliases.find(command); 121 | if (it != aliases.end()) 122 | { 123 | return it->second; 124 | } 125 | return command; 126 | } 127 | 128 | private: 129 | std::unordered_map aliases; 130 | std::unordered_set validCommands; 131 | }; 132 | 133 | #endif // ALIAS_H 134 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bài tập lớn Nguyên lý Hệ điều hành 2 | 3 |
4 | Typing SVG 5 |
6 | 7 |
8 | Static Badge 9 | GitHub code size in bytes 10 |
11 | 12 | ## Giới thiệu 13 | 14 | Tiny Shell là một chương trình mô phỏng giao diện dòng lệnh đơn giản, được phát triển bằng ngôn ngữ lập trình C++. Chương trình này cung cấp các tính năng cơ bản giúp người dùng tương tác với hệ điều hành Windows thông qua các lệnh nhập từ bàn phím. Tiny Shell được thiết kế để hỗ trợ các thao tác với tệp, thư mục, tiến trình và một số tiện ích khác. 15 | 16 | Tiny Shell là một dự án hữu ích cho những ai muốn tìm hiểu về lập trình hệ điều hành và các giao diện dòng lệnh, cũng như cách sử dụng các thư viện và API của hệ điều hành Windows để thao tác với hệ thống tệp tin. 17 | 18 | ## Thành viên 19 | 20 | - Nguyễn Viết Tuấn Kiệt 21 | - Bùi Quang Phong 22 | - Lưu Thịnh Khang 23 | - Nguyễn Thanh Tuyển 24 | - Nguyễn Thái Hòa (Hỗ trợ kĩ thuật) 25 | 26 | ### Người đóng góp 27 | 28 |
29 | 30 | 31 | 32 |
33 | 34 | ## Cài đặt và triển khai 35 | 36 | ### Yêu cầu 37 | 38 | - Hệ điều hành Windows 10 hoặc mới hơn. 39 | - CMake phiên bản 3.10.2 trở lên. 40 | - MSVC hoặc MinGW để biên dịch mã nguồn C++. 41 | 42 | ### Cài đặt 43 | 44 | - **Bước 1:** Tạo bản sao của dự án trên máy tính của bạn. 45 | 46 | ```bash 47 | git clone https://github.com/HaiAu2501/Operating-System-Projects.git 48 | ``` 49 | 50 | - **Bước 2:** Tạo folder build cho CMake và chuyển đến thư mục này. 51 | 52 | ```bash 53 | mkdir build 54 | cd build 55 | ``` 56 | 57 | - **Bước 3:** Sử dụng CMake để tạo file Makefile hoặc Visual Studio project. 58 | 59 | ```bash 60 | cmake .. 61 | ``` 62 | 63 | - **Bước 4:** Biên dịch mã nguồn bằng trình biên dịch C++ mà bạn đã cài đặt. 64 | 65 | ```bash 66 | cmake --build . --target install --config Debug 67 | ``` 68 | 69 | - **Bước 5:** Chạy chương trình `Operating-System-Project.exe` từ thư mục `install`. Bạn nên nhập lệnh `help` để xem danh sách các lệnh hỗ trợ. 70 | 71 | ```bash 72 | cd install 73 | Operating-System-Project.exe 74 | ``` 75 | 76 | Nếu không biên dịch thì cũng không sao, bạn có thể tải file thực thi từ [đây](https://github.com/HaiAu2501/Operating-System-Project/releases/download/1.0.0/Operating-System-Project.x64.zip). Nếu chạy bị lỗi, hãy cài đặt [Visual C++ Redistributable](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads). 77 | 78 | ### Giải thích 79 | 80 | - **Feature:** Thư mục chứa các file header của các tính năng mà Tiny Shell hỗ trợ. 81 | - `features.h`: Tổng hợp các file header của các tính năng. 82 | - `help.h`: Hiển thị thông tin hướng dẫn sử dụng Tiny Shell. 83 | - **Process:** Thư mục chứa các chương trình có thể khởi chạy từ Tiny Shell. 84 | - `child_process.cpp`: Chương trình con đơn giản. 85 | - `countdown.cpp`: Chương trình đếm ngược. 86 | - `duck.cpp`: Chương trình vẽ hình con vịt. 87 | - `tictactoe.cpp`: Chương trình chơi cờ caro. 88 | - **Testcase:** Thư mục chứa các kịch bản kiểm thử cho Tiny Shell nhằm đảm bảo tính ổn định và đúng đắn của chương trình. 89 | - Mỗi _kịch bản_ là dãy lệnh được lưu thành một file `.bat`. 90 | - Dãy lệnh sẽ có độ khó nhất định và là một quy trình hoàn toàn khép kín. 91 | - Tên file sẽ phản ánh nội dung tính năng kiểm thử của kịch bản. 92 | - Tiny Shell chạy kịch bản kiểm thử bằng cách nhập lệnh `run Testcase\` từ bàn phím. 93 | - Hoặc đơn giản hơn là `add_path Testcase\` rồi nhập `run ` để chạy kịch bản kiểm thử. 94 | -------------------------------------------------------------------------------- /Feature/conditional.h: -------------------------------------------------------------------------------- 1 | #ifndef CONDITIONAL_H 2 | #define CONDITIONAL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "variables.h" 8 | 9 | // Hàm này sẽ kiểm tra điều kiện và thực thi các lệnh tương ứng với kết quả của điều kiện 10 | void handleIfElse(const std::vector &args, VariableManager &variableManager) 11 | { 12 | if (args.empty() || args[0] != "(") 13 | { 14 | throw std::runtime_error("Syntax error: Expected '(' after 'if'"); 15 | } 16 | 17 | // Xác định các phần của câu lệnh if-else 18 | std::vector leftExpression; 19 | std::vector rightExpression; 20 | std::string op; 21 | std::vector ifCommand; 22 | std::vector elseCommand; 23 | 24 | size_t i = 1; 25 | while (i < args.size() && args[i] != "!" && args[i] != "<" && args[i] != ">" && args[i] != "=" && args[i] != "==" && args[i] != "!=" && args[i] != "<=" && args[i] != ">=") 26 | { 27 | leftExpression.push_back(args[i]); 28 | ++i; 29 | } 30 | 31 | if (i == args.size()) 32 | { 33 | throw std::runtime_error("Syntax error: Expected comparison operator in if condition"); 34 | } 35 | 36 | op = args[i]; 37 | if (op == "<" || op == ">") 38 | { 39 | if (i + 1 < args.size() && args[i + 1] == "=") 40 | { 41 | op += "="; 42 | ++i; 43 | } 44 | } 45 | else if (op == "=") 46 | { 47 | if (i + 1 < args.size() && args[i + 1] == "=") 48 | { 49 | op += "="; 50 | ++i; 51 | } 52 | else 53 | { 54 | throw std::runtime_error("Syntax error: Expected '=' after '='"); 55 | } 56 | } 57 | 58 | ++i; 59 | 60 | while (i < args.size() && args[i] != ")") 61 | { 62 | rightExpression.push_back(args[i]); 63 | ++i; 64 | } 65 | 66 | if (i == args.size() || args[i] != ")") 67 | { 68 | throw std::runtime_error("Syntax error: Expected ')' in if condition"); 69 | } 70 | 71 | ++i; 72 | 73 | if (i == args.size() || args[i] != ":") 74 | { 75 | throw std::runtime_error("Syntax error: Expected ':' after if condition"); 76 | } 77 | 78 | ++i; 79 | 80 | while (i < args.size() && args[i] != "else") 81 | { 82 | ifCommand.push_back(args[i]); 83 | ++i; 84 | } 85 | 86 | if (i < args.size() && args[i] == "else") 87 | { 88 | ++i; 89 | while (i < args.size()) 90 | { 91 | elseCommand.push_back(args[i]); 92 | ++i; 93 | } 94 | } 95 | 96 | // Tính giá trị của biểu thức điều kiện 97 | double leftValue = variableManager.evaluateExpression(leftExpression); 98 | double rightValue = variableManager.evaluateExpression(rightExpression); 99 | 100 | bool conditionResult = false; 101 | if (op == "==") 102 | { 103 | conditionResult = (leftValue == rightValue); 104 | } 105 | else if (op == "!=") 106 | { 107 | conditionResult = (leftValue != rightValue); 108 | } 109 | else if (op == "<") 110 | { 111 | conditionResult = (leftValue < rightValue); 112 | } 113 | else if (op == "<=") 114 | { 115 | conditionResult = (leftValue <= rightValue); 116 | } 117 | else if (op == ">") 118 | { 119 | conditionResult = (leftValue > rightValue); 120 | } 121 | else if (op == ">=") 122 | { 123 | conditionResult = (leftValue >= rightValue); 124 | } 125 | 126 | if (conditionResult) 127 | { 128 | if (!ifCommand.empty()) 129 | { 130 | std::string ifCommandStr = ifCommand[0]; 131 | ifCommand.erase(ifCommand.begin()); 132 | executeCommand(ifCommandStr, ifCommand); 133 | } 134 | } 135 | else 136 | { 137 | if (!elseCommand.empty()) 138 | { 139 | std::string elseCommandStr = elseCommand[0]; 140 | elseCommand.erase(elseCommand.begin()); 141 | executeCommand(elseCommandStr, elseCommand); 142 | } 143 | } 144 | } 145 | 146 | #endif // CONDITIONAL_H 147 | -------------------------------------------------------------------------------- /Process/tictactoe.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | enum class Player 9 | { 10 | None, 11 | X, 12 | O 13 | }; 14 | 15 | class TicTacToe 16 | { 17 | public: 18 | TicTacToe(); 19 | void playGame(); 20 | 21 | private: 22 | void printBoard(); 23 | bool makeMove(int row, int col); 24 | Player checkWinner(); 25 | void switchPlayer(); 26 | 27 | vector> board; 28 | Player currentPlayer; 29 | 30 | static void signalHandler(int signal); 31 | static atomic stopFlag; // Cờ dừng 32 | }; 33 | 34 | atomic TicTacToe::stopFlag(false); // Khởi tạo cờ dừng 35 | 36 | TicTacToe::TicTacToe() 37 | : board(3, vector(3, Player::None)), currentPlayer(Player::X) {} 38 | 39 | void TicTacToe::playGame() 40 | { 41 | // Đăng ký xử lý tín hiệu 42 | signal(SIGINT, TicTacToe::signalHandler); 43 | 44 | Player winner = Player::None; 45 | int moveCount = 0; 46 | 47 | while (winner == Player::None && moveCount < 9 && !stopFlag) 48 | { 49 | printBoard(); 50 | if (stopFlag) // Kiểm tra cờ sau khi in bảng 51 | { 52 | break; 53 | } 54 | 55 | int row, col; 56 | cout << "Player " << (currentPlayer == Player::X ? "X" : "O") << ", enter your move (row and column): "; 57 | cin >> row >> col; 58 | 59 | if (stopFlag) // Kiểm tra cờ sau khi nhận nhập liệu 60 | { 61 | break; 62 | } 63 | 64 | // Chuyển đổi từ chỉ mục người dùng nhập (1-3) sang chỉ mục mảng (0-2) 65 | if (makeMove(row - 1, col - 1)) 66 | { 67 | winner = checkWinner(); 68 | if (winner == Player::None) 69 | { 70 | switchPlayer(); 71 | moveCount++; 72 | } 73 | } 74 | else 75 | { 76 | cout << "Invalid move. Try again." << endl; 77 | } 78 | } 79 | 80 | if (stopFlag) 81 | { 82 | cout << "\nGame interrupted. Exiting..." << endl; 83 | return; 84 | } 85 | 86 | printBoard(); 87 | if (winner != Player::None) 88 | { 89 | cout << "Player " << (winner == Player::X ? "X" : "O") << " wins!" << endl; 90 | } 91 | else 92 | { 93 | cout << "It's a draw!" << endl; 94 | } 95 | } 96 | 97 | void TicTacToe::printBoard() 98 | { 99 | cout << " 1 2 3" << endl; // Đánh số cột 100 | for (int i = 0; i < 3; ++i) 101 | { 102 | cout << i + 1 << " "; // Đánh số hàng 103 | for (int j = 0; j < 3; ++j) 104 | { 105 | char symbol = '.'; 106 | if (board[i][j] == Player::X) 107 | { 108 | symbol = 'X'; 109 | } 110 | else if (board[i][j] == Player::O) 111 | { 112 | symbol = 'O'; 113 | } 114 | cout << symbol << " "; 115 | } 116 | cout << endl; 117 | } 118 | } 119 | 120 | bool TicTacToe::makeMove(int row, int col) 121 | { 122 | if (row < 0 || row >= 3 || col < 0 || col >= 3 || board[row][col] != Player::None) 123 | { 124 | return false; 125 | } 126 | board[row][col] = currentPlayer; 127 | return true; 128 | } 129 | 130 | Player TicTacToe::checkWinner() 131 | { 132 | // Check rows 133 | for (int i = 0; i < 3; ++i) 134 | { 135 | if (board[i][0] != Player::None && board[i][0] == board[i][1] && board[i][1] == board[i][2]) 136 | { 137 | return board[i][0]; 138 | } 139 | } 140 | // Check columns 141 | for (int i = 0; i < 3; ++i) 142 | { 143 | if (board[0][i] != Player::None && board[0][i] == board[1][i] && board[1][i] == board[2][i]) 144 | { 145 | return board[0][i]; 146 | } 147 | } 148 | // Check diagonals 149 | if (board[0][0] != Player::None && board[0][0] == board[1][1] && board[1][1] == board[2][2]) 150 | { 151 | return board[0][0]; 152 | } 153 | if (board[0][2] != Player::None && board[0][2] == board[1][1] && board[1][1] == board[2][0]) 154 | { 155 | return board[0][2]; 156 | } 157 | return Player::None; 158 | } 159 | 160 | void TicTacToe::switchPlayer() 161 | { 162 | currentPlayer = (currentPlayer == Player::X) ? Player::O : Player::X; 163 | } 164 | 165 | void TicTacToe::signalHandler(int signal) 166 | { 167 | if (signal == SIGINT) 168 | { 169 | stopFlag = true; 170 | } 171 | } 172 | 173 | int main() 174 | { 175 | TicTacToe game; 176 | game.playGame(); 177 | return 0; 178 | } 179 | -------------------------------------------------------------------------------- /Feature/variables.h: -------------------------------------------------------------------------------- 1 | #ifndef VARIABLES_H 2 | #define VARIABLES_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "environment.h" 12 | 13 | class VariableManager 14 | { 15 | public: 16 | EnvironmentManager &envManager; 17 | 18 | VariableManager(EnvironmentManager &envMgr) : envManager(envMgr) {} 19 | 20 | double evaluateExpression(const std::vector &tokens) 21 | { 22 | std::vector infixExpression; 23 | 24 | // Bước 1: Duyệt qua tokens và thay thế các biến bằng giá trị của chúng 25 | for (const std::string &token : tokens) 26 | { 27 | if (isOperator(token) || isParenthesis(token)) 28 | { 29 | infixExpression.push_back(token); 30 | } 31 | else if (isNumber(token)) 32 | { 33 | infixExpression.push_back(token); 34 | } 35 | else 36 | { 37 | // Token là toán hạng (biến) 38 | std::string value = envManager.getEnv(token); 39 | if (value.empty()) 40 | { 41 | throw std::runtime_error("Error: Variable " + token + " not set."); 42 | } 43 | infixExpression.push_back(value); 44 | } 45 | } 46 | 47 | // Bước 2: Chuyển biểu thức infix sang postfix 48 | std::vector postfixExpression = infixToPostfix(infixExpression); 49 | 50 | // Bước 3: Tính giá trị biểu thức postfix 51 | return evaluatePostfix(postfixExpression); 52 | } 53 | 54 | private: 55 | bool isOperator(const std::string &token) 56 | { 57 | return token == "+" || token == "-" || token == "*" || token == "/"; 58 | } 59 | 60 | bool isParenthesis(const std::string &token) 61 | { 62 | return token == "(" || token == ")"; 63 | } 64 | 65 | bool isNumber(const std::string &token) 66 | { 67 | return !token.empty() && std::all_of(token.begin(), token.end(), ::isdigit); 68 | } 69 | 70 | int getPrecedence(const std::string &op) 71 | { 72 | if (op == "+" || op == "-") 73 | return 1; 74 | if (op == "*" || op == "/") 75 | return 2; 76 | return 0; 77 | } 78 | 79 | std::vector infixToPostfix(const std::vector &infix) 80 | { 81 | std::vector postfix; 82 | std::stack stack; 83 | 84 | for (const std::string &token : infix) 85 | { 86 | if (isOperator(token)) 87 | { 88 | while (!stack.empty() && getPrecedence(stack.top()) >= getPrecedence(token)) 89 | { 90 | postfix.push_back(stack.top()); 91 | stack.pop(); 92 | } 93 | stack.push(token); 94 | } 95 | else if (token == "(") 96 | { 97 | stack.push(token); 98 | } 99 | else if (token == ")") 100 | { 101 | while (!stack.empty() && stack.top() != "(") 102 | { 103 | postfix.push_back(stack.top()); 104 | stack.pop(); 105 | } 106 | stack.pop(); // Pop '(' 107 | } 108 | else 109 | { 110 | // Token là toán hạng 111 | postfix.push_back(token); 112 | } 113 | } 114 | 115 | while (!stack.empty()) 116 | { 117 | postfix.push_back(stack.top()); 118 | stack.pop(); 119 | } 120 | 121 | return postfix; 122 | } 123 | 124 | double evaluatePostfix(const std::vector &postfix) 125 | { 126 | std::stack stack; 127 | 128 | for (const std::string &token : postfix) 129 | { 130 | if (isOperator(token)) 131 | { 132 | double b = stack.top(); 133 | stack.pop(); 134 | double a = stack.top(); 135 | stack.pop(); 136 | 137 | if (token == "+") 138 | stack.push(a + b); 139 | else if (token == "-") 140 | stack.push(a - b); 141 | else if (token == "*") 142 | stack.push(a * b); 143 | else if (token == "/") 144 | stack.push(a / b); 145 | } 146 | else 147 | { 148 | stack.push(std::stod(token)); 149 | } 150 | } 151 | 152 | return stack.top(); 153 | } 154 | }; 155 | 156 | #endif // VARIABLES_H 157 | -------------------------------------------------------------------------------- /Feature/directory.h: -------------------------------------------------------------------------------- 1 | #ifndef DIRECTORY_H 2 | #define DIRECTORY_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class DirectoryManager 10 | { 11 | public: 12 | // Các lệnh hỗ trợ 13 | static const std::unordered_set supportedCommands; 14 | 15 | // Hàm lấy danh sách các lệnh hỗ trợ 16 | static const std::unordered_set &getSupportedCommands() 17 | { 18 | return supportedCommands; 19 | } 20 | 21 | void copyDirectory(const std::vector &args) 22 | { 23 | if (args.size() != 2) 24 | { 25 | std::cout << "Usage: copy " << std::endl; 26 | return; 27 | } 28 | std::filesystem::path sourcePath = args[0]; 29 | std::filesystem::path destinationPath = args[1]; 30 | if (!std::filesystem::exists(sourcePath) || !std::filesystem::is_directory(sourcePath)) 31 | { 32 | std::cout << "Source directory does not exist: " << sourcePath << std::endl; 33 | return; 34 | } 35 | if (std::filesystem::exists(destinationPath)) 36 | { 37 | std::cout << "Destination already exists: " << destinationPath << std::endl; 38 | return; 39 | } 40 | std::filesystem::copy(sourcePath, destinationPath, std::filesystem::copy_options::recursive); 41 | std::cout << "Directory copied from " << sourcePath << " to " << destinationPath << std::endl; 42 | } 43 | 44 | void createDirectory(const std::vector &args) 45 | { 46 | if (args.size() != 1) 47 | { 48 | std::cout << "Usage: create " << std::endl; 49 | return; 50 | } 51 | std::filesystem::path dirPath = args[0]; 52 | if (std::filesystem::exists(dirPath)) 53 | { 54 | std::cout << "Directory already exists: " << dirPath << std::endl; 55 | return; 56 | } 57 | std::filesystem::create_directories(dirPath); 58 | std::cout << "Directory created: " << dirPath << std::endl; 59 | } 60 | 61 | void deleteDirectory(const std::vector &args) 62 | { 63 | if (args.size() != 1) 64 | { 65 | std::cout << "Usage: delete " << std::endl; 66 | return; 67 | } 68 | std::filesystem::path dirPath = args[0]; 69 | if (!std::filesystem::exists(dirPath)) 70 | { 71 | std::cout << "Directory does not exist: " << dirPath << std::endl; 72 | return; 73 | } 74 | std::filesystem::remove_all(dirPath); 75 | std::cout << "Directory deleted: " << dirPath << std::endl; 76 | } 77 | 78 | void listDirectoryTree(const std::vector &args) 79 | { 80 | if (args.size() != 1) 81 | { 82 | std::cout << "Usage: list_tree " << std::endl; 83 | return; 84 | } 85 | std::filesystem::path dirPath = args[0]; 86 | if (!std::filesystem::exists(dirPath)) 87 | { 88 | std::cout << "Directory does not exist: " << dirPath << std::endl; 89 | return; 90 | } 91 | std::cout << dirPath.string() << std::endl; 92 | listDirectoryTreeHelper(dirPath, 1); 93 | } 94 | 95 | void moveDirectory(const std::vector &args) 96 | { 97 | if (args.size() != 2) 98 | { 99 | std::cout << "Usage: move " << std::endl; 100 | return; 101 | } 102 | std::filesystem::path sourcePath = args[0]; 103 | std::filesystem::path destinationPath = args[1]; 104 | if (!std::filesystem::exists(sourcePath)) 105 | { 106 | std::cout << "Source directory does not exist: " << sourcePath << std::endl; 107 | return; 108 | } 109 | std::filesystem::rename(sourcePath, destinationPath); 110 | std::cout << "Directory moved from " << sourcePath << " to " << destinationPath << std::endl; 111 | } 112 | 113 | private: 114 | void listDirectoryTreeHelper(const std::filesystem::path &path, int level) 115 | { 116 | if (!std::filesystem::exists(path) || !std::filesystem::is_directory(path)) 117 | { 118 | return; 119 | } 120 | 121 | for (const auto &entry : std::filesystem::directory_iterator(path)) 122 | { 123 | for (int i = 0; i < level; ++i) 124 | { 125 | std::cout << " "; 126 | } 127 | std::cout << entry.path().filename().string() << std::endl; 128 | if (entry.is_directory()) 129 | { 130 | listDirectoryTreeHelper(entry, level + 1); 131 | } 132 | } 133 | } 134 | }; 135 | 136 | const std::unordered_set DirectoryManager::supportedCommands = { 137 | "copy", 138 | "create", 139 | "delete", 140 | "list_tree", 141 | "move"}; 142 | 143 | #endif // DIRECTORY_H -------------------------------------------------------------------------------- /Feature/system_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef SYSTEM_UTILS_H 2 | #define SYSTEM_UTILS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class SystemUtils 10 | { 11 | public: 12 | // Danh sách các lệnh hỗ trợ 13 | static const std::unordered_set supportedCommands; 14 | 15 | // Hàm lấy danh sách các lệnh hỗ trợ 16 | static const std::unordered_set &getSupportedCommands() 17 | { 18 | return supportedCommands; 19 | } 20 | 21 | void showSystemTime(const std::vector &args) 22 | { 23 | if (!args.empty()) 24 | { 25 | std::cerr << "Usage: time" << std::endl; 26 | return; 27 | } 28 | 29 | std::time_t t = std::time(nullptr); 30 | std::tm *now = std::localtime(&t); 31 | 32 | std::cout << "Current system time: " 33 | << (now->tm_year + 1900) << '-' 34 | << (now->tm_mon + 1) << '-' 35 | << now->tm_mday << ' ' 36 | << now->tm_hour << ':' 37 | << now->tm_min << ':' 38 | << now->tm_sec 39 | << std::endl; 40 | } 41 | 42 | void showSystemDate(const std::vector &args) 43 | { 44 | if (!args.empty()) 45 | { 46 | std::cerr << "Usage: date" << std::endl; 47 | return; 48 | } 49 | 50 | std::time_t t = std::time(nullptr); 51 | std::tm *now = std::localtime(&t); 52 | 53 | std::cout << "Current system date: " 54 | << (now->tm_year + 1900) << '-' 55 | << (now->tm_mon + 1) << '-' 56 | << now->tm_mday 57 | << std::endl; 58 | } 59 | 60 | void showSystemUptime(const std::vector &args) 61 | { 62 | if (!args.empty()) 63 | { 64 | std::cerr << "Usage: uptime" << std::endl; 65 | return; 66 | } 67 | 68 | DWORD uptime = GetTickCount64() / 1000; // Get system uptime in seconds 69 | DWORD seconds = uptime % 60; 70 | DWORD minutes = (uptime / 60) % 60; 71 | DWORD hours = (uptime / 3600) % 24; 72 | DWORD days = uptime / 86400; 73 | 74 | std::cout << "System uptime: " 75 | << days << " days, " 76 | << hours << " hours, " 77 | << minutes << " minutes, " 78 | << seconds << " seconds" 79 | << std::endl; 80 | } 81 | 82 | void showCPUInfo(const std::vector &args) 83 | { 84 | if (!args.empty()) 85 | { 86 | std::cerr << "Usage: cpuinfo" << std::endl; 87 | return; 88 | } 89 | 90 | SYSTEM_INFO sysInfo; 91 | GetSystemInfo(&sysInfo); 92 | 93 | std::cout << "CPU Information:" << std::endl; 94 | std::cout << "Number of processors: " << sysInfo.dwNumberOfProcessors << std::endl; 95 | std::cout << "Processor type: " << sysInfo.dwProcessorType << std::endl; 96 | } 97 | 98 | void showMemoryInfo(const std::vector &args) 99 | { 100 | if (!args.empty()) 101 | { 102 | std::cerr << "Usage: meminfo" << std::endl; 103 | return; 104 | } 105 | 106 | MEMORYSTATUSEX statex; 107 | statex.dwLength = sizeof(statex); 108 | GlobalMemoryStatusEx(&statex); 109 | 110 | std::cout << "Memory Information:" << std::endl; 111 | std::cout << "Total physical memory: " << statex.ullTotalPhys / (1024 * 1024) << " MB" << std::endl; 112 | std::cout << "Available physical memory: " << statex.ullAvailPhys / (1024 * 1024) << " MB" << std::endl; 113 | std::cout << "Total virtual memory: " << statex.ullTotalPageFile / (1024 * 1024) << " MB" << std::endl; 114 | std::cout << "Available virtual memory: " << statex.ullAvailPageFile / (1024 * 1024) << " MB" << std::endl; 115 | } 116 | 117 | void showDiskInfo(const std::vector &args) 118 | { 119 | if (args.size() != 1) 120 | { 121 | std::cerr << "Usage: diskinfo " << std::endl; 122 | return; 123 | } 124 | 125 | std::string drive = args[0] + ":\\"; 126 | ULARGE_INTEGER freeBytesAvailableToCaller, totalNumberOfBytes, totalNumberOfFreeBytes; 127 | 128 | if (GetDiskFreeSpaceExA(drive.c_str(), &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes)) 129 | { 130 | std::cout << "Disk Information for drive " << drive << ":" << std::endl; 131 | std::cout << "Total space: " << totalNumberOfBytes.QuadPart / (1024 * 1024 * 1024) << " GB" << std::endl; 132 | std::cout << "Free space: " << totalNumberOfFreeBytes.QuadPart / (1024 * 1024 * 1024) << " GB" << std::endl; 133 | } 134 | else 135 | { 136 | std::cerr << "Failed to get disk information: " << GetLastError() << std::endl; 137 | } 138 | } 139 | 140 | void showCalculator(const std::vector &args) 141 | { 142 | if (!args.empty()) 143 | { 144 | std::cerr << "Usage: calculator" << std::endl; 145 | return; 146 | } 147 | 148 | STARTUPINFO si = {sizeof(si)}; 149 | PROCESS_INFORMATION pi; 150 | 151 | if (!CreateProcess(TEXT("C:\\Windows\\System32\\calc.exe"), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) 152 | { 153 | std::cerr << "Failed to start calculator: " << GetLastError() << std::endl; 154 | return; 155 | } 156 | 157 | CloseHandle(pi.hProcess); 158 | CloseHandle(pi.hThread); 159 | } 160 | }; 161 | 162 | const std::unordered_set SystemUtils::supportedCommands = { 163 | "time", 164 | "date", 165 | "uptime", 166 | "cpuinfo", 167 | "meminfo", 168 | "diskinfo", 169 | "calculator"}; 170 | 171 | #endif // SYSTEM_UTILS_H 172 | -------------------------------------------------------------------------------- /Document/Template/setup.tex: -------------------------------------------------------------------------------- 1 | \documentclass[aspectratio=1610,10pt]{beamer} 2 | \usepackage[T1]{fontenc} 3 | \usepackage[utf8]{vietnam} 4 | \usepackage{amsmath} 5 | \usefonttheme[onlymath]{serif} 6 | \usepackage{tikz} 7 | \usepackage[most]{tcolorbox} 8 | \usepackage{listingsutf8} 9 | \usepackage{comment} 10 | \usepackage{tabularx} 11 | \usepackage{mathtools} 12 | \usepackage{algpseudocode} 13 | \usepackage{xcolor} 14 | \setbeamertemplate{caption}[numbered] 15 | \usepackage{makecell} 16 | \usepackage{fnpct} 17 | \usepackage{multirow} 18 | \usepackage{bbm} 19 | \usepackage{pgfpages} 20 | \usepackage{handoutWithNotes} 21 | \usepackage{xcolor} 22 | \usepackage{calc} 23 | \usepackage{changepage} 24 | 25 | 26 | 27 | 28 | % Bỏ thanh mờ mờ góc phải 29 | \setbeamertemplate{navigation symbols}{} 30 | 31 | 32 | \setbeamercolor{section in head/foot}{bg=cyan!5, fg=cyan!50} 33 | \setbeamercolor{author in head/foot}{bg=cyan!5, fg=black} 34 | 35 | \setbeamerfont{section in head/foot}{size=\small} 36 | \setbeamerfont{author in head/foot}{size=\small} 37 | 38 | % \setbeamertemplate{footline}{ 39 | % \begin{beamercolorbox}[ht=3ex,dp=1.5ex,right]{author in head/foot} 40 | % \insertframenumber{} / \inserttotalframenumber\hspace*{2ex} 41 | % \end{beamercolorbox} 42 | % } 43 | 44 | % \setbeamertemplate{headline}{% 45 | % \begin{beamercolorbox}[wd=\paperwidth,ht=5ex,dp=2.5ex]{section in head/foot} 46 | % \hspace{5 ex} 47 | % \insertsectionhead 48 | % \ifx\insertsubsectionhead\empty 49 | % % Không có subsection, không hiển thị dấu gạch ngang 50 | % \else 51 | % % Có subsection, hiển thị dấu gạch ngang và tên của subsection 52 | % \,---\,\insertsubsectionhead 53 | % \fi 54 | % \end{beamercolorbox}% 55 | % \vspace{5 pt} 56 | % } 57 | 58 | \setbeamertemplate{footline}{ 59 | \begin{beamercolorbox}[ht=5ex,dp=3ex,right]{author in head/foot} % Tăng kích thước box 60 | \usebeamerfont{author in head/foot}\insertframenumber{} / \inserttotalframenumber\hspace*{2ex} 61 | \end{beamercolorbox} 62 | } 63 | 64 | \setbeamertemplate{headline}{ 65 | \begin{beamercolorbox}[wd=\paperwidth,ht=6ex,dp=3.5ex]{section in head/foot} % Tăng kích thước box 66 | \usebeamerfont{section in head/foot}\hspace{1 ex} 67 | \insertsectionhead 68 | \ifx\insertsubsectionhead\empty 69 | % Không có subsection, không hiển thị dấu gạch ngang 70 | \else 71 | % Có subsection, hiển thị dấu gạch ngang và tên của subsection 72 | \,---\,\insertsubsectionhead 73 | \fi 74 | \end{beamercolorbox}% 75 | } 76 | 77 | 78 | \everymath{\displaystyle} 79 | 80 | 81 | \setbeamerfont{title}{size=\fontsize{26}{12}} 82 | 83 | % Tạo màu cho các block 84 | \setbeamercolor{block title example}{fg=white, bg=teal!80!} 85 | \setbeamercolor{block body example}{ bg=teal!20} 86 | \setbeamercolor{block title alerted}{fg=white, bg=orange} 87 | \setbeamercolor{block body alerted}{ bg=orange!25} 88 | \setbeamercolor{block title}{bg=cyan, fg=white} 89 | \setbeamercolor{block body}{bg=cyan!10} 90 | 91 | % Dấu tròn trước item 92 | \setbeamertemplate{itemize item}{\textbullet} 93 | 94 | 95 | % Tên nè 96 | \title{Tiny Shell} 97 | \subtitle{ 98 | \Large Tương tác với hệ điều hành thông qua giao diện dòng lệnh\\ 99 | \vspace{5 pt}\small\textbf{Học phần:} IT3070 - Nguyên lý Hệ điều hành\\ \small\textbf{Giảng viên hướng dẫn:} TS. Phạm Đăng Hải} 100 | \author{N.~V.~T.~Kiệt \inst{1,2}, B.~Q~Phong \inst{1,2}, L.~T.~Khang \inst{1}, N.~T.Tuyển \inst{1}} 101 | 102 | 103 | \institute % 104 | { 105 | \inst{1}% 106 | Chương trình tài năng - Khoa học máy tính K67\\ 107 | Trường Công nghệ Thông tin và Truyền thông 108 | \and 109 | \inst{2}% 110 | Phòng thí nghiệm Mô hình hóa, Mô phỏng và Tối ưu hóa\\ 111 | Trung tâm nghiên cứu quốc tế về Trí tuệ nhân tạo, BKAI 112 | 113 | } 114 | \date{\today} 115 | 116 | % \setbeamertemplate{frametitle}{ 117 | % % Bọc tcolorbox bằng hbox để giới hạn chiều rộng theo nội dung 118 | % \begin{tcolorbox}[ 119 | % colback=cyan!10, 120 | % colframe=white, % Màu viền của hộp 121 | % boxrule=0mm, % Độ dày của viền, đặt là 0 nếu không muốn viền 122 | % arc=3mm, % Độ cong của góc Tự động làm cho các góc ngoài cong theo arc được đặt 123 | % boxsep=1mm, % Khoảng cách giữa viền và nội dung trong hộp 124 | % left=3mm, right=3mm, top=1mm, bottom=1mm % Padding bên trong hộp 125 | % ] 126 | % \insertframetitle % Chèn tiêu đề slide 127 | % \end{tcolorbox} 128 | 129 | % } 130 | \newlength{\customwidth} 131 | 132 | % \setbeamertemplate{frametitle}{ 133 | % % Xác định chiều rộng của tiêu đề để chỉ định chiều rộng của tcolorbox 134 | % \settowidth{\customwidth}{\insertframetitle\hspace{6mm}} 135 | 136 | % \begin{tcolorbox}[ 137 | % colback=orange!10, 138 | % colframe=white, 139 | % boxrule=0mm, % Độ dày của viền 140 | % arc=3mm, % Độ cong của góc 141 | % auto outer arc, 142 | % boxsep=1mm, 143 | % left=-1mm, right=2mm, top=0mm, bottom=1mm, 144 | % width=\customwidth % Đặt chiều rộng của tcolorbox bằng với chiều rộng của tiêu đề 145 | % ] 146 | % \color{orange}\insertframetitle 147 | % \end{tcolorbox} 148 | % } 149 | 150 | \setbeamertemplate{frametitle}{ 151 | \settowidth{\customwidth}{\insertframetitle\hspace{6mm}} 152 | \begin{tcolorbox}[ 153 | enhanced, 154 | colback=orange!10, 155 | colframe=white, 156 | boxrule=0mm, 157 | arc=3mm, 158 | auto outer arc, 159 | boxsep=1mm, 160 | left=0mm, right=1mm, top=5mm, bottom=1mm, 161 | width=\customwidth, % Đặt chiều rộng của tcolorbox bằng với chiều rộng giấy 162 | enlarge left by=-3mm, % Dịch chuyển toàn bộ tcolorbox sang trái 3mm 163 | overlay={ 164 | \node[anchor=west] at ([xshift=1mm]frame.west) {\color{orange}\insertframetitle}; 165 | } 166 | ] 167 | \end{tcolorbox} 168 | } 169 | 170 | 171 | -------------------------------------------------------------------------------- /Feature/environment.h: -------------------------------------------------------------------------------- 1 | #ifndef ENVIRONMENT_H 2 | #define ENVIRONMENT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class EnvironmentManager 13 | { 14 | public: 15 | // Các lệnh hỗ trợ 16 | static const std::unordered_set supportedCommands; 17 | 18 | // Hàm lấy danh sách các lệnh hỗ trợ 19 | static const std::unordered_set &getSupportedCommands() 20 | { 21 | return supportedCommands; 22 | } 23 | 24 | // Hàm để thêm đường dẫn vào biến môi trường PATH 25 | void addToPath(const std::string &path) 26 | { 27 | std::string currentPath = getEnv("PATH"); 28 | if (currentPath.find(path) == std::string::npos) 29 | { 30 | std::string newPath = currentPath + ";" + path; 31 | setEnv("PATH", newPath); 32 | std::cout << "Added " << path << " to PATH." << std::endl; 33 | } 34 | else 35 | { 36 | std::cout << path << " is already in PATH." << std::endl; 37 | } 38 | } 39 | 40 | // Hàm để xóa đường dẫn khỏi biến môi trường PATH 41 | void removeFromPath(const std::string &path) 42 | { 43 | std::string currentPath = getEnv("PATH"); 44 | size_t pos = currentPath.find(path); 45 | if (pos != std::string::npos) 46 | { 47 | std::string newPath; 48 | if (pos > 0 && currentPath[pos - 1] == ';') 49 | { 50 | newPath = currentPath.substr(0, pos - 1) + currentPath.substr(pos + path.length()); 51 | } 52 | else if (pos + path.length() < currentPath.length() && currentPath[pos + path.length()] == ';') 53 | { 54 | newPath = currentPath.substr(0, pos) + currentPath.substr(pos + path.length() + 1); 55 | } 56 | else 57 | { 58 | newPath = currentPath.substr(0, pos) + currentPath.substr(pos + path.length()); 59 | } 60 | setEnv("PATH", newPath); 61 | std::cout << "Removed " << path << " from PATH." << std::endl; 62 | } 63 | else 64 | { 65 | std::cout << path << " is not in PATH." << std::endl; 66 | } 67 | } 68 | 69 | // Hàm để in ra giá trị của biến môi trường 70 | void printEnv(const std::string &var) 71 | { 72 | std::string value = getEnv(var); 73 | if (!value.empty()) 74 | { 75 | std::cout << var << " = " << value << std::endl; 76 | } 77 | else 78 | { 79 | std::cout << var << " is not set." << std::endl; 80 | } 81 | } 82 | 83 | // Hàm để thiết lập giá trị của biến môi trường 84 | void setEnv(const std::string &var, const std::string &value) 85 | { 86 | // Kiểm tra xem value có phải là một biến môi trường khác hay không 87 | std::string actualValue = getEnv(value); 88 | if (!actualValue.empty()) 89 | { 90 | _putenv_s(var.c_str(), actualValue.c_str()); 91 | } 92 | else 93 | { 94 | _putenv_s(var.c_str(), value.c_str()); 95 | } 96 | } 97 | 98 | // Hàm để xóa biến môi trường 99 | void unsetEnv(const std::string &var) 100 | { 101 | _putenv_s(var.c_str(), ""); 102 | std::cout << "Unset variable " << var << std::endl; 103 | } 104 | 105 | // Hàm để kiểm tra xem một đường dẫn có trong PATH hay không 106 | bool isInPath(const std::string &path) 107 | { 108 | std::string currentPath = getEnv("PATH"); 109 | return currentPath.find(path) != std::string::npos; 110 | } 111 | 112 | // Hàm để liệt kê tất cả các biến môi trường 113 | void listAllEnv() 114 | { 115 | extern char **environ; 116 | for (char **env = environ; *env; ++env) 117 | { 118 | std::cout << *env << std::endl; 119 | } 120 | } 121 | 122 | // Hàm để lưu biến môi trường vào file 123 | void saveEnvToFile(const std::string &filename) 124 | { 125 | std::ofstream file(filename); 126 | if (!file) 127 | { 128 | std::cerr << "Could not open file for writing: " << filename << std::endl; 129 | return; 130 | } 131 | extern char **environ; 132 | for (char **env = environ; *env; ++env) 133 | { 134 | file << *env << std::endl; 135 | } 136 | file.close(); 137 | std::cout << "Environment variables saved to " << filename << std::endl; 138 | } 139 | 140 | // Hàm để tải biến môi trường từ file 141 | void loadEnvFromFile(const std::string &filename) 142 | { 143 | std::ifstream file(filename); 144 | if (!file) 145 | { 146 | std::cerr << "Could not open file for reading: " << filename << std::endl; 147 | return; 148 | } 149 | std::string line; 150 | while (std::getline(file, line)) 151 | { 152 | size_t pos = line.find('='); 153 | if (pos != std::string::npos) 154 | { 155 | std::string var = line.substr(0, pos); 156 | std::string value = line.substr(pos + 1); 157 | setEnv(var, value); 158 | } 159 | } 160 | file.close(); 161 | std::cout << "Environment variables loaded from " << filename << std::endl; 162 | } 163 | 164 | // Hàm để lấy giá trị của biến môi trường 165 | std::string getEnv(const std::string &var) 166 | { 167 | const char *value = getenv(var.c_str()); 168 | if (value) 169 | { 170 | return std::string(value); 171 | } 172 | return ""; 173 | } 174 | }; 175 | 176 | const std::unordered_set EnvironmentManager::supportedCommands = { 177 | "add_path", 178 | "remove_path", 179 | "print_env", 180 | "set_env", 181 | "unset_env", 182 | "is_in_path", 183 | "list_env", 184 | "save_env", 185 | "load_env"}; 186 | 187 | #endif // ENVIRONMENT_H 188 | -------------------------------------------------------------------------------- /Feature/help.h: -------------------------------------------------------------------------------- 1 | #ifndef HELP_COMMAND_H 2 | #define HELP_COMMAND_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void showHelp(const std::vector &args) 9 | { 10 | if (!args.empty()) 11 | { 12 | std::cerr << "Usage: help" << std::endl; 13 | return; 14 | } 15 | 16 | std::cout << std::left; 17 | std::cout << std::setw(20) << "Command" << ": Description" << std::endl; 18 | std::cout << std::setw(20) << "--------------------" << "--------------------" << std::endl; 19 | std::cout << std::setw(20) << "delete" << ": Delete a directory" << std::endl; 20 | std::cout << std::setw(20) << "move" << ": Move a directory" << std::endl; 21 | std::cout << std::setw(20) << "list_tree" << ": List the directory tree" << std::endl; 22 | std::cout << std::setw(20) << "create" << ": Create a directory" << std::endl; 23 | std::cout << std::setw(20) << "copy" << ": Copy a directory" << std::endl; 24 | std::cout << std::setw(20) << "open" << ": Open a file" << std::endl; 25 | std::cout << std::setw(20) << "rename" << ": Rename a file" << std::endl; 26 | std::cout << std::setw(20) << "--------------------" << "--------------------" << std::endl; 27 | std::cout << std::setw(20) << "start_foreground" << ": Start a process in foreground" << std::endl; 28 | std::cout << std::setw(20) << "start_background" << ": Start a process in background" << std::endl; 29 | std::cout << std::setw(20) << "terminate" << ": Terminate a process" << std::endl; 30 | std::cout << std::setw(20) << "list_processes" << ": List running processes" << std::endl; 31 | std::cout << std::setw(20) << "child" << ": Start a child process" << std::endl; 32 | std::cout << std::setw(20) << "manage_threads" << ": Manage threads" << std::endl; 33 | std::cout << std::setw(20) << "list_children" << ": Print all children processes" << std::endl; 34 | std::cout << std::setw(20) << "suspend" << ": Suspend a process" << std::endl; 35 | std::cout << std::setw(20) << "resume" << ": Resume a process" << std::endl; 36 | std::cout << std::setw(20) << "after" << ": Schedule a command" << std::endl; 37 | std::cout << std::setw(20) << "--------------------" << "--------------------" << std::endl; 38 | std::cout << std::setw(20) << "run" << ": Run a script" << std::endl; 39 | std::cout << std::setw(20) << "calculator" << ": Open the calculator" << std::endl; 40 | std::cout << std::setw(20) << "time" << ": Show system time" << std::endl; 41 | std::cout << std::setw(20) << "date" << ": Show system date" << std::endl; 42 | std::cout << std::setw(20) << "uptime" << ": Show system uptime" << std::endl; 43 | std::cout << std::setw(20) << "cpuinfo" << ": Show CPU information" << std::endl; 44 | std::cout << std::setw(20) << "meminfo" << ": Show memory information" << std::endl; 45 | std::cout << std::setw(20) << "diskinfo" << ": Show disk information" << std::endl; 46 | std::cout << std::setw(20) << "--------------------" << "--------------------" << std::endl; 47 | std::cout << std::setw(20) << "change_color" << ": Change text color" << std::endl; 48 | std::cout << std::setw(20) << "calculate" << ": Calculate expression value" << std::endl; 49 | std::cout << std::setw(20) << "function" << ": Define a function" << std::endl; 50 | std::cout << std::setw(20) << "evaluate" << ": Evaluate a function" << std::endl; 51 | std::cout << std::setw(20) << "if else" << ": Conditional execution" << std::endl; 52 | std::cout << std::setw(20) << "loop" << ": Loop expression" << std::endl; 53 | std::cout << std::setw(20) << "convert" << ": Number base convertion" << std::endl; 54 | std::cout << std::setw(20) << "alias" << ": Create command alias" << std::endl; 55 | std::cout << std::setw(20) << "unalias" << ": Remove command alias" << std::endl; 56 | std::cout << std::setw(20) << "bookmark" << ": Bookmark management" << std::endl; 57 | std::cout << std::setw(20) << "--------------------" << "--------------------" << std::endl; 58 | std::cout << std::setw(20) << "add_path" << ": Add a path to PATH" << std::endl; 59 | std::cout << std::setw(20) << "remove_path" << ": Remove a path from PATH" << std::endl; 60 | std::cout << std::setw(20) << "print_env" << ": Print environment variable" << std::endl; 61 | std::cout << std::setw(20) << "set_env" << ": Set environment variable" << std::endl; 62 | std::cout << std::setw(20) << "unset_env" << ": Unset environment variable" << std::endl; 63 | std::cout << std::setw(20) << "is_in_path" << ": Check if a path is in PATH" << std::endl; 64 | std::cout << std::setw(20) << "list_env" << ": List all environment variables" << std::endl; 65 | std::cout << std::setw(20) << "save_env" << ": Save environment variables to file" << std::endl; 66 | std::cout << std::setw(20) << "load_env" << ": Load environment variables from file" << std::endl; 67 | std::cout << std::setw(20) << "--------------------" << "--------------------" << std::endl; 68 | std::cout << std::setw(20) << "write_file" << ": Write content to file" << std::endl; 69 | std::cout << std::setw(20) << "read_file" << ": Read content from file" << std::endl; 70 | std::cout << std::setw(20) << "file_size" << ": Get file size" << std::endl; 71 | std::cout << std::setw(20) << "--------------------" << "--------------------" << std::endl; 72 | std::cout << std::setw(20) << "dancing" << ": Show dancing faces" << std::endl; 73 | std::cout << std::setw(20) << "tictactoe" << ": Start a Tic-Tac-Toe game" << std::endl; 74 | std::cout << std::setw(20) << "duck" << ": Show a duck" << std::endl; 75 | std::cout << std::setw(20) << "--------------------" << "--------------------" << std::endl; 76 | std::cout << std::setw(20) << "cd" << ": Change directory" << std::endl; 77 | std::cout << std::setw(20) << "dir" << ": List directory contents" << std::endl; 78 | std::cout << std::setw(20) << "pwd" << ": Print working directory" << std::endl; 79 | std::cout << std::setw(20) << "exit" << ": Exit the shell" << std::endl; 80 | std::cout << std::setw(20) << "help" << ": Show this help message" << std::endl; 81 | std::cout << std::setw(20) << "history" << ": Show history" << std::endl; 82 | std::cout << std::setw(20) << "clear" << ": Clear screen" << std::endl; 83 | std::cout << std::setw(20) << "clear_history" << ": Clear history" << std::endl; 84 | } 85 | 86 | #endif // HELP_COMMAND_H 87 | -------------------------------------------------------------------------------- /Feature/function.h: -------------------------------------------------------------------------------- 1 | #ifndef FUNCTION_H 2 | #define FUNCTION_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "variables.h" 11 | 12 | // Khai báo hàm splitInput 13 | std::vector splitInput(const std::string &input); 14 | 15 | struct Function 16 | { 17 | std::string name; 18 | std::vector parameters; 19 | std::vector expressionTokens; 20 | 21 | Function() {} // Constructor mặc định 22 | Function(const std::string &name, const std::vector ¶meters, const std::vector &expressionTokens) 23 | : name(name), parameters(parameters), expressionTokens(expressionTokens) {} 24 | }; 25 | 26 | class FunctionManager 27 | { 28 | public: 29 | void defineFunction(const std::vector &args) 30 | { 31 | if (args.size() < 5) // function name ( param_list ) = expression 32 | { 33 | throw std::runtime_error("Usage: function () = "); 34 | } 35 | 36 | std::string functionName = args[0]; // "f" 37 | std::vector parameters; 38 | std::unordered_set uniqueParams; 39 | 40 | size_t i = 2; // Start after '(' 41 | while (i < args.size() && args[i] != ")") 42 | { 43 | if (args[i] != ",") 44 | { 45 | if (uniqueParams.find(args[i]) != uniqueParams.end()) 46 | { 47 | throw std::runtime_error("Duplicate parameter: " + args[i]); 48 | } 49 | if (isInvalidParameter(args[i])) 50 | { 51 | throw std::runtime_error("Invalid parameter: " + args[i]); 52 | } 53 | uniqueParams.insert(args[i]); 54 | parameters.push_back(args[i]); 55 | } 56 | ++i; 57 | } 58 | 59 | if (i == args.size() || args[i] != ")") 60 | { 61 | throw std::runtime_error("Invalid parameter list."); 62 | } 63 | 64 | ++i; // Move past ')' 65 | if (i == args.size() || args[i] != "=") 66 | { 67 | throw std::runtime_error("Syntax error: Expected '=' after parameter list."); 68 | } 69 | 70 | ++i; // Move past '=' 71 | std::vector expressionTokens(args.begin() + i, args.end()); 72 | 73 | // Định nghĩa hàm 74 | functions[functionName] = Function(functionName, parameters, expressionTokens); 75 | 76 | // Nếu hàm không có tham số, thì thông báo lỗi 77 | if (parameters.empty()) 78 | { 79 | throw std::runtime_error("Function " + functionName + " must have at least one parameter."); 80 | } 81 | 82 | // Hiển thị thông tin chi tiết về hàm đã được định nghĩa 83 | std::cout << "- Function defined!" << std::endl; 84 | std::cout << "- Name: " << functionName << std::endl; 85 | std::cout << "- Parameters (" << parameters.size() << "): "; 86 | for (const auto ¶m : parameters) 87 | { 88 | std::cout << param << " "; 89 | } 90 | std::cout << std::endl; 91 | std::cout << "- Expression: "; 92 | for (const auto &token : expressionTokens) 93 | { 94 | std::cout << token << " "; 95 | } 96 | std::cout << std::endl; 97 | } 98 | 99 | double evaluateFunction(const std::vector &args, VariableManager &variableManager) 100 | { 101 | if (args.size() < 2) 102 | { 103 | throw std::runtime_error("Usage: evaluate "); 104 | } 105 | 106 | std::string functionName = args[0]; 107 | std::vector functionArgs(args.begin() + 1, args.end()); 108 | 109 | if (functions.find(functionName) == functions.end()) 110 | { 111 | throw std::runtime_error("Function " + functionName + " not defined."); 112 | } 113 | 114 | Function function = functions[functionName]; 115 | if (functionArgs.size() != function.parameters.size()) 116 | { 117 | throw std::runtime_error("Incorrect number of arguments for function " + functionName); 118 | } 119 | 120 | // Thay thế tham số bằng giá trị tương ứng trong các token của biểu thức 121 | std::vector evaluatedTokens = function.expressionTokens; 122 | for (size_t i = 0; i < functionArgs.size(); ++i) 123 | { 124 | for (auto &token : evaluatedTokens) 125 | { 126 | if (token == function.parameters[i]) 127 | { 128 | token = functionArgs[i]; 129 | } 130 | } 131 | } 132 | 133 | // Kiểm tra và thay thế các biến không phải là tham số 134 | for (auto &token : evaluatedTokens) 135 | { 136 | if (!isOperator(token) && !isNumber(token) && !isParenthesis(token)) 137 | { 138 | if (std::find(function.parameters.begin(), function.parameters.end(), token) == function.parameters.end()) 139 | { 140 | std::string value = variableManager.envManager.getEnv(token); 141 | if (value.empty()) 142 | { 143 | throw std::runtime_error("Error: Variable " + token + " not set."); 144 | } 145 | token = value; 146 | } 147 | } 148 | } 149 | 150 | // Đánh giá biểu thức 151 | return variableManager.evaluateExpression(evaluatedTokens); 152 | } 153 | 154 | private: 155 | std::unordered_map functions; 156 | 157 | bool isOperator(const std::string &token) 158 | { 159 | return token == "+" || token == "-" || token == "*" || token == "/"; 160 | } 161 | 162 | bool isNumber(const std::string &token) 163 | { 164 | return !token.empty() && std::all_of(token.begin(), token.end(), ::isdigit); 165 | } 166 | 167 | bool isParenthesis(const std::string &token) 168 | { 169 | return token == "(" || token == ")"; 170 | } 171 | 172 | bool isInvalidParameter(const std::string &token) 173 | { 174 | return isNumber(token) || isParenthesis(token) || isOperator(token); 175 | } 176 | }; 177 | 178 | #endif // FUNCTION_H 179 | -------------------------------------------------------------------------------- /bug.txt: -------------------------------------------------------------------------------- 1 | --- [01] Lỗi xử lý tokens: FIXED ⭐ 2 | calculate (x + 1) // Tokens: '(x', '+', '1)' -> Phân tích sai 3 | => Buộc phải viết là calculate ( x + 1 ) -> Bất tiện 4 | => Như vậy các dấu ngoặc và toán tử tách thành token riêng 5 | --> [XỬ LÝ TOKENS KIỂU MỚI] 6 | Token sẽ là dấu phẩy, dấu ngoặc, kí tự liền nhau hoặc là toán tử, hoặc là quote 7 | Ví dụ: function f(x) "x*x" => tokens: ["function", "f", "(", "x", ",", "y", ")", "\"x + y\""] 8 | 9 | >>> (01) Thêm tính năng định nghĩa hàm: UPDATED 📌 10 | Cú pháp: function f(x) "x*x" 11 | Hàm nhiều biến: function f(x, y, z) "x + y + z" 12 | 13 | --- [02] Lỗi hàm có tham số trùng nhau: FIXED ⭐ 14 | function h(x, x) "x" 15 | evaluate h 1 2 // Kết quả in ra: 1 16 | --> [KHÔNG CHO PHÉP ĐỊNH NGHĨA HÀM NHƯ VẬY] 17 | 18 | --- [03] Lỗi không tính được giá trị hàm khi biểu thức có biến toàn cục: FIXED ⭐ 19 | set_env z 2 20 | function h(x) "x + z" 21 | evaluate h 1 // Không tính được 22 | --> [CHO PHÉP LẤY GIÁ TRỊ BIẾN MÔI TRƯỜNG GÁN VÀO] 23 | 24 | --- [04] Lỗi khi truyền giá trị cụ thể: FIXED ⭐ 25 | function f(1) "1 + 1" // Không được định nghĩa như vậy 26 | --> [KHÔNG CHO PHÉP ĐỊNH NGHĨA HÀM NHƯ VẬY] 27 | 28 | --- [05] Lỗi khi truyền toán tử: FIXED ⭐ 29 | function f(x+y,z) 30 | function f(f(x)) 31 | function f(()) 32 | --> [KHÔNG CHO PHÉP ĐỊNH NGHĨA HÀM NHƯ VẬY] 33 | 34 | --- [06] Lỗi không thể dừng tiến trình: SOLVED ✅ 35 | start notepad.exe // notepad lúc này có PID 36 | terminate PID của notepad // -> Không được trên Windows 11 | Được trên Windows 10 37 | --> [SỰ KHÁC BIỆT CỦA WINDOWS 11] 38 | Khi bắt đầu 1 tiến trình, nó tạo ra tiến trình con (hiển thị notepad) rồi lập tức kết thúc 39 | Như vậy muốn dừng tiến trình notepad, phải tìm PID của tiến trình con nó tạo ra và sử dụng PID đó. 40 | 41 | --- [07] Lỗi không hiện tiến trình con trên Task Manager: SOLVED ✅ 42 | start_child // -> Tìm trong Task Manager (Windows 11) không thấy child_process là tiến trình con của main.exe 43 | Hơn nữa, main.exe nằm ở Background Processes thay vì Apps 44 | --> [CÁCH TASK MANAGER LIỆT KÊ TIẾN TRÌNH] 45 | Task Manage liệt kê tiến trình và nhóm tiến trình không đúng. 46 | Để kiểm tra child_process có là tiến trình con của main không thì tìm PID tất cả tiến trình con của main 47 | Và kết quả là child_process có là tiến trình con của main, nhưng không được liệt kê 48 | 49 | --- [08] Lỗi không chạy được foreground: SOLVED ✅ 50 | start_foreground notepad.exe // Không thấy foreground, shell vẫn chuyển đến dòng mới mà không đợi notepad tắt 51 | --> [SỰ KHÁC BIỆT CỦA WINDOWS 11] 52 | Như [06], khi notepad được khởi động, nó là tiến trình cha và tạo 1 tiến trình con rồi lập tức kết thúc 53 | Muốn đợi notepad, ta sẽ đợi mọi tiến trình con của nó tạo ra kết thúc, thay vì chỉ đợi nó 54 | 55 | >>> (02) Xử lý Ctrl + C: UPDATED 📌 56 | 57 | --- [09] Lỗi liên quan đến Ctrl + C: FIXED ⭐ 58 | Khi shell đang bắt đầu dòng 'tiny_shell>' mà ấn Ctrl + C thì bị thoát 59 | Trong shell khởi động foreground chính shell (start_foreground main.exe) và ấn Ctrl + C 60 | -> Bị in ra vài lần từ 'tiny_shell>' trước khi trở về shell cha 61 | --> [CÁCH XỬ LÝ TÍN HIỆU CTRL + C] 62 | Xem chi tiết trong main.cpp hiện tại 63 | 64 | --- [10] Lỗi tô màu cho syntax: UNSOLVED | REMOVED ❌ 65 | Tính năng đọc lệnh realtime và chuyển màu nếu gặp phải từ khóa mà shell hỗ trợ 66 | Ví dụ: function thì gõ đến function sẽ chuyển vàng 67 | -> Làm lỗi nhận tín hiệu Ctrl + C 68 | -> Vẫn không giải quyết được, tính năng đã bị loại bỏ 69 | 70 | --- [11] Lỗi gán biến đã có giá trị cho biến mới: FIXED ⭐ 71 | set_env x 1 72 | set_env y x 73 | print_env y // -> y = x (x là kí tự trong khi x đang có giá trị 1) 74 | --> [KIỂM TRA GIÁ TRỊ GÁN CHO CÓ LÀ BIẾN MÔI TRƯỜNG KHÔNG] 75 | 76 | --- [12] Lỗi định nghĩa hàm không tham số: FIXED ⭐ 77 | function f() "1" 78 | funtion f(,) "1" 79 | evaluate f 80 | --> [KHÔNG CHO PHÉP ĐỊNH NGHĨA HÀM NHƯ VẬY] 81 | 82 | --- [13] Lỗi đọc sai biểu thức điều kiện với dấu so sánh bằng: FIXED ⭐ 83 | if (1 + 1 + 1 = = 3): help else dir // -> Xử lý được 84 | if (1+1+1 = = 3): help else dir // -> Xử lý được 85 | if (1 + 1 + 1 == 3): help else dir // -> Gặp lỗi 86 | --> [CÁCH XỬ LÝ TOÁN TỬ SO SÁNH TRONG LỆNH ĐIỀU KIỆN] 87 | 88 | >>> (03) Chỉnh sửa cú pháp định nghĩa hàm đơn giản hơn: UPDATED 📌 89 | Cũ: function f(x) "x*x" 90 | Mới: function f(x) = x*x 91 | 92 | --- [14] Lỗi khi set biến môi trường: SOLVED ✅ | FIXED: ⭐ 93 | set_env x + // -> Không cho set như này 94 | set_env a 1 95 | set_env b 2 96 | set_env c a + b 97 | print_env c // c = 1 -> Cần ra c = 3 98 | set_env m m // Chạy bình thường -> Cần sửa lại 99 | print_env m // m = m 100 | --> [CHẤP NHẬN TÍNH NĂNG] 101 | Việc xử lý gán biểu thức cho biến tương đối khó và phải can thiệp vào variables.h 102 | Chấp nhận đây là một hạn chế của shell, shell không thể giống như ngôn ngữ lập trình đầy đủ 103 | 104 | >>> (04) Cho phép gán biến môi trường bằng biểu thức: UPDATED 📌 105 | Cũ: 106 | Mới: = hoặc = 107 | 108 | --- [15] Lỗi không tạo được Folder: FIXED ⭐ 109 | create "New Folder" // -> Không hoạt động 110 | delete "New Folder" // -> Không hoạt động 111 | --> [CHỈNH SỬA CÁCH XỬ LÝ TOKEN LÀ QUOTE] 112 | 113 | --- [16] Lỗi không đọc đúng số thập phân: SOLVED ✅ 114 | calculate 11 / 2 - 5.5 // Variable 5.5 not set 115 | --> [CHẤP NHẬN TÍNH NĂNG] 116 | Shell không thể hoàn thiện được như Python 117 | 118 | --- [17] Lỗi Ctrl + C làm dừng tiến trình countdown chạy background: SOLVED: ✅ | FIXED: ⭐ 119 | --> [CHỈNH SỬA CÁCH NHẬN TÍN HIỆU] 120 | Do countdown.exe chia sẻ cùng console với tiến trình cha nên nó cũng chịu ảnh hưởng từ tiến trình cha 121 | Dùng tham số 'CREATE_NEW_PROCESS_GROUP' để tiến trình con tạo ra trong 1 nhóm tiến trình mới 122 | 123 | >>> (05) Cập nhật tính năng mới cho phép định nghĩa từ viết tắt cho lệnh: UPDATED 📌 124 | 125 | >>> (06) Tính năng tính toán nâng cao, đổi hệ cơ số: UPDATED 📌 126 | 127 | >>> (07) Tính năng bookmark lưu danh sách đường dẫn tắt: UPDATED 📌 128 | 129 | >>> (08) Tính năng lập lịch cho câu lệnh chạy sau một thời gian: UPDATED 📌 130 | 131 | ### TEMPLATE BUG RECORD ### 132 | --- [STT] Mô tả lỗi: [ĐÃ FIX HAY CHƯA? UPDATED 📌 | SOLVED: ✅ | FIXED: ⭐ | REMOVED: ❌] 133 | 134 | SOLVED: Đã giải thích được nguyên nhân, đây không phải lỗi 135 | FIXED: Đã công nhận là lỗi và đã sửa, kèm theo cách giải quyết 136 | REMOVED: Không thể tìm được nguyên nhân, không thể giải thích nên đã loại bỏ phần chứa lỗi và các phần liên quan đến lỗi 137 | 138 | [Tab: 4 spaces] Dòng lệnh gây lỗi 139 | --> [CÁCH GIẢI QUYẾT] 140 | -------------------------------------------------------------------------------- /Process/unistd.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | Copyright (c) 2019 win32ports 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | SOFTWARE. 19 | */ 20 | 21 | #pragma once 22 | 23 | #ifndef __UNISTD_H_17CD2BD1_839A_4E25_97C7_DE9544B8B59C__ 24 | #define __UNISTD_H_17CD2BD1_839A_4E25_97C7_DE9544B8B59C__ 25 | 26 | #ifndef _WIN32 27 | 28 | #pragma message("this unistd.h implementation is for Windows only!") 29 | 30 | #else /* _WIN32 */ 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif /* __cplusplus */ 35 | 36 | #ifndef _INC_IO 37 | #include /* _access() */ 38 | #endif /* _INC_IO */ 39 | 40 | #ifndef _INC_DIRECT 41 | #include /* _chdir() */ 42 | #endif /* _INC_DIRECT */ 43 | 44 | #ifndef _INC_PROCESS 45 | #include /* _execl() */ 46 | #endif /* _INC_PROCESS */ 47 | 48 | #include /* */ 49 | 50 | #ifndef access 51 | #define access _access 52 | #endif /* access */ 53 | 54 | #ifndef R_OK 55 | #define R_OK 04 56 | #endif /* R_OK */ 57 | 58 | #ifndef W_OK 59 | #define W_OK 02 60 | #endif /* W_OK */ 61 | 62 | #ifndef X_OK 63 | #define X_OK R_OK 64 | #endif /* X_OK */ 65 | 66 | #ifndef F_OK 67 | #define F_OK 00 68 | #endif /* F_OK */ 69 | 70 | #ifndef chdir 71 | #define chdir _chdir 72 | #endif /* chdir */ 73 | 74 | #ifndef close 75 | #define close _close 76 | #endif /* close */ 77 | 78 | #ifndef STDIN_FILENO 79 | #define STDIN_FILENO 0 80 | #endif /* STDIN_FILENO */ 81 | 82 | #ifndef STDOUT_FILENO 83 | #define STDOUT_FILENO 1 84 | #endif /* STDOUT_FILENO */ 85 | 86 | #ifndef STDERR_FILENO 87 | #define STDERR_FILENO 2 88 | #endif /* STDERR_FILENO */ 89 | 90 | #ifndef dup 91 | #define dup _dup 92 | #endif /* dup */ 93 | 94 | #ifndef dup2 95 | #define dup2 _dup2 96 | #endif /* dup2 */ 97 | 98 | #ifndef execl 99 | #define execl _execl 100 | #endif /* execl */ 101 | 102 | #ifndef execle 103 | #define execle _execle 104 | #endif /* execle */ 105 | 106 | #ifndef execlp 107 | #define execlp _execlp 108 | #endif /* execlp */ 109 | 110 | #ifndef execp 111 | #define execp _execp 112 | #endif /* execp */ 113 | 114 | #ifndef execpe 115 | #define execpe _execpe 116 | #endif /* execpe */ 117 | 118 | #ifndef execpp 119 | #define execpp _execpp 120 | #endif /* execpp */ 121 | 122 | #ifndef rmdir 123 | #define rmdir _rmdir 124 | #endif /* rmdir */ 125 | 126 | #ifndef unlink 127 | #define unlink _unlink 128 | #endif /* unlink */ 129 | 130 | /* permission bits below must be defined in sys/stat.h, but MSVC lacks them */ 131 | 132 | #ifndef S_IRWXU 133 | #define S_IRWXU 0700 134 | #endif /* S_IRWXU */ 135 | 136 | #ifndef S_IRUSR 137 | #define S_IRUSR 0400 138 | #endif /* S_IRUSR */ 139 | 140 | #ifndef S_IWUSR 141 | #define S_IWUSR 0200 142 | #endif /* S_IWUSR */ 143 | 144 | #ifndef S_IXUSR 145 | #define S_IXUSR 0100 146 | #endif /* S_IXUSR */ 147 | 148 | #ifndef S_IRWXG 149 | #define S_IRWXG 070 150 | #endif /* S_IRWXG */ 151 | 152 | #ifndef S_IRGRP 153 | #define S_IRGRP 040 154 | #endif /* S_IRGRP */ 155 | 156 | #ifndef S_IWGRP 157 | #define S_IWGRP 020 158 | #endif /* S_IWGRP */ 159 | 160 | #ifndef S_IXGRP 161 | #define S_IXGRP 010 162 | #endif /* S_IXGRP */ 163 | 164 | #ifndef S_IRWXO 165 | #define S_IRWXO 07 166 | #endif /* S_IRWXO */ 167 | 168 | #ifndef S_IROTH 169 | #define S_IROTH 04 170 | #endif /* S_IROTH */ 171 | 172 | #ifndef S_IWOTH 173 | #define S_IWOTH 02 174 | #endif /* S_IWOTH */ 175 | 176 | #ifndef S_IXOTH 177 | #define S_IXOTH 01 178 | #endif /* S_IXOTH */ 179 | 180 | #ifndef S_ISUID 181 | #define S_ISUID 04000 182 | #endif /* S_ISUID */ 183 | 184 | #ifndef S_ISGID 185 | #define S_ISGID 02000 186 | #endif /* S_ISGID */ 187 | 188 | #ifndef S_ISVTX 189 | #define S_ISVTX 01000 190 | #endif /* S_ISVTX */ 191 | 192 | #ifndef S_IRWXUGO 193 | #define S_IRWXUGO 0777 194 | #endif /* S_IRWXUGO */ 195 | 196 | #ifndef S_IALLUGO 197 | #define S_IALLUGO 0777 198 | #endif /* S_IALLUGO */ 199 | 200 | #ifndef S_IRUGO 201 | #define S_IRUGO 0444 202 | #endif /* S_IRUGO */ 203 | 204 | #ifndef S_IWUGO 205 | #define S_IWUGO 0222 206 | #endif /* S_IWUGO */ 207 | 208 | #ifndef S_IXUGO 209 | #define S_IXUGO 0111 210 | #endif /* S_IXUGO */ 211 | 212 | #ifndef _S_IFMT 213 | #define _S_IFMT 0xF000 214 | #endif /* _S_IFMT */ 215 | 216 | #ifndef _S_IFIFO 217 | #define _S_IFIFO 0x1000 218 | #endif /* _S_IFIFO */ 219 | 220 | #ifndef _S_IFCHR 221 | #define _S_IFCHR 0x2000 222 | #endif /* _S_IFCHR */ 223 | 224 | #ifndef _S_IFDIR 225 | #define _S_IFDIR 0x4000 226 | #endif /* _S_IFDIR */ 227 | 228 | #ifndef _S_IFBLK 229 | #define _S_IFBLK 0x6000 230 | #endif /* _S_IFBLK */ 231 | 232 | #ifndef _S_IFREG 233 | #define _S_IFREG 0x8000 234 | #endif /* _S_IFREG */ 235 | 236 | #ifndef _S_IFLNK 237 | #define _S_IFLNK 0xA000 238 | #endif /* _S_IFLNK */ 239 | 240 | #ifndef _S_IFSOCK 241 | #define _S_IFSOCK 0xC000 242 | #endif /* _S_IFSOCK */ 243 | 244 | #ifndef S_IFMT 245 | #define S_IFMT _S_IFMT 246 | #endif /* S_IFMT */ 247 | 248 | #ifndef S_IFIFO 249 | #define S_IFIFO _S_IFIFO 250 | #endif /* S_IFIFO */ 251 | 252 | #ifndef S_IFCHR 253 | #define S_IFCHR _S_IFCHR 254 | #endif /* S_IFCHR */ 255 | 256 | #ifndef S_IFDIR 257 | #define S_IFDIR _S_IFDIR 258 | #endif /* S_IFDIR */ 259 | 260 | #ifndef S_IFBLK 261 | #define S_IFBLK _S_IFBLK 262 | #endif /* S_IFBLK */ 263 | 264 | #ifndef S_IFREG 265 | #define S_IFREG _S_IFREG 266 | #endif /* S_IFREG */ 267 | 268 | #ifndef S_IFLNK 269 | #define S_IFLNK _S_IFLNK 270 | #endif /* S_IFLNK */ 271 | 272 | #ifndef S_IFSOCK 273 | #define S_IFSOCK _S_IFSOCK 274 | #endif /* S_IFSOCK */ 275 | 276 | #ifndef S_ISTYPE 277 | #define S_ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask)) 278 | #endif /* S_ISTYPE */ 279 | 280 | #ifndef S_ISFIFO 281 | #define S_ISFIFO(mode) S_ISTYPE(mode, S_IFIFO) 282 | #endif /* S_ISFIFO */ 283 | 284 | #ifndef S_ISCHR 285 | #define S_ISCHR(mode) S_ISTYPE(mode, S_IFCHR) 286 | #endif /* S_ISCHR */ 287 | 288 | #ifndef S_ISDIR 289 | #define S_ISDIR(mode) S_ISTYPE(mode, S_IFDIR) 290 | #endif /* S_ISDIR */ 291 | 292 | #ifndef S_ISBLK 293 | #define S_ISBLK(mode) S_ISTYPE(mode, S_IFBLK) 294 | #endif /* S_ISBLK */ 295 | 296 | #ifndef S_ISREG 297 | #define S_ISREG(mode) S_ISTYPE(mode, S_IFREG) 298 | #endif /* S_ISREG */ 299 | 300 | #ifndef S_ISLNK 301 | #define S_ISLNK(mode) S_ISTYPE(mode, S_IFLNK) 302 | #endif /* S_ISLNK */ 303 | 304 | #ifndef S_ISSOCK 305 | #define S_ISSOCK(mode) S_ISTYPE(mode, S_IFSOCK) 306 | #endif /* S_ISSOCK */ 307 | 308 | #ifdef __cplusplus 309 | } 310 | #endif /* __cplusplus */ 311 | 312 | #endif /* _WIN32 */ 313 | 314 | #endif /* __UNISTD_H_17CD2BD1_839A_4E25_97C7_DE9544B8B59C__ */ -------------------------------------------------------------------------------- /Feature/file.h: -------------------------------------------------------------------------------- 1 | #ifndef FILE_H 2 | #define FILE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace fs = std::filesystem; 15 | 16 | class FileManager 17 | { 18 | public: 19 | FileManager() 20 | { 21 | // Đăng ký xử lý tín hiệu SIGINT (Ctrl+C) 22 | signal(SIGINT, signalHandler); 23 | } 24 | 25 | static const std::unordered_set supportedCommands; 26 | 27 | static const std::unordered_set &getSupportedCommands() 28 | { 29 | return supportedCommands; 30 | } 31 | 32 | // Hàm để ghi nội dung vào file 33 | void writeFile(const std::vector &args) 34 | { 35 | if (args.size() < 2) 36 | { 37 | std::cerr << "Usage: write_file [~HEAD | ~FOOT | ~LINE N]" << std::endl; 38 | return; 39 | } 40 | 41 | std::string content = args[0]; 42 | std::string filename = args[1]; 43 | 44 | if (args.size() == 2) 45 | { 46 | // Mặc định ghi vào cuối file 47 | std::ofstream file(filename, std::ios::app); 48 | if (!file) 49 | { 50 | std::cerr << "Failed to open file: " << filename << std::endl; 51 | return; 52 | } 53 | 54 | file << content << std::endl; 55 | file.close(); 56 | } 57 | else if (args.size() == 3 || (args.size() == 4 && args[2] == "~LINE")) 58 | { 59 | std::string position = args[2]; 60 | std::ifstream file_in(filename); 61 | if (!file_in) 62 | { 63 | std::cerr << "Failed to open file: " << filename << std::endl; 64 | return; 65 | } 66 | 67 | std::vector lines; 68 | std::string line; 69 | while (std::getline(file_in, line)) 70 | { 71 | lines.push_back(line); 72 | } 73 | file_in.close(); 74 | 75 | if (position == "~HEAD") 76 | { 77 | lines.insert(lines.begin(), content); 78 | } 79 | else if (position == "~FOOT") 80 | { 81 | lines.push_back(content); 82 | } 83 | else if (position == "~LINE") 84 | { 85 | if (args.size() != 4) 86 | { 87 | std::cerr << "Usage: write_file ~LINE N" << std::endl; 88 | return; 89 | } 90 | size_t line_number = std::stoi(args[3]) - 1; 91 | if (line_number < lines.size()) 92 | { 93 | lines.insert(lines.begin() + line_number, content); 94 | } 95 | else 96 | { 97 | lines.push_back(content); 98 | } 99 | } 100 | 101 | std::ofstream file_out(filename); 102 | if (!file_out) 103 | { 104 | std::cerr << "Failed to open file for writing: " << filename << std::endl; 105 | return; 106 | } 107 | 108 | for (const auto &l : lines) 109 | { 110 | file_out << l << std::endl; 111 | } 112 | file_out.close(); 113 | } 114 | else 115 | { 116 | std::cerr << "Invalid number of arguments." << std::endl; 117 | } 118 | 119 | std::cout << "Successfully wrote to file: " << filename << std::endl; 120 | } 121 | 122 | // Hàm để đọc file 123 | void readFile(const std::vector &args) 124 | { 125 | if (args.size() < 1 || args.size() > 4) 126 | { 127 | std::cerr << "Usage: read_file [~HEAD N | ~FOOT N | ~RANGE M N | ~LINE N]" << std::endl; 128 | return; 129 | } 130 | 131 | std::string filename = args[0]; 132 | std::ifstream file(filename); 133 | if (!file) 134 | { 135 | std::cerr << "Could not open file: " << filename << std::endl; 136 | return; 137 | } 138 | 139 | std::vector lines; 140 | std::string line; 141 | while (std::getline(file, line)) 142 | { 143 | lines.push_back(line); 144 | } 145 | file.close(); 146 | 147 | if (args.size() == 1) 148 | { 149 | // Mặc định đọc toàn bộ file, 5 dòng một lần và hỏi người dùng ấn Enter để tiếp tục hoặc Ctrl+C để thoát 150 | printLinesWithPause(lines, 0, lines.size()); 151 | } 152 | else 153 | { 154 | std::string position = args[1]; 155 | if (position == "~HEAD") 156 | { 157 | if (args.size() != 3) 158 | { 159 | std::cerr << "Usage: read_file ~HEAD N" << std::endl; 160 | return; 161 | } 162 | size_t num_lines = std::stoi(args[2]); 163 | printLines(lines, 0, std::min(num_lines, lines.size())); 164 | } 165 | else if (position == "~FOOT") 166 | { 167 | if (args.size() != 3) 168 | { 169 | std::cerr << "Usage: read_file ~FOOT N" << std::endl; 170 | return; 171 | } 172 | size_t num_lines = std::stoi(args[2]); 173 | printLines(lines, std::max(lines.size() - num_lines, (size_t)0), lines.size()); 174 | } 175 | else if (position == "~RANGE") 176 | { 177 | if (args.size() != 4) 178 | { 179 | std::cerr << "Usage: read_file ~RANGE M N" << std::endl; 180 | return; 181 | } 182 | size_t start_line = std::stoi(args[2]) - 1; 183 | size_t end_line = std::stoi(args[3]) - 1; 184 | if (start_line <= end_line && end_line < lines.size()) 185 | { 186 | printLines(lines, start_line, end_line + 1); 187 | } 188 | else 189 | { 190 | std::cerr << "Invalid line range." << std::endl; 191 | } 192 | } 193 | else if (position == "~LINE") 194 | { 195 | if (args.size() != 3) 196 | { 197 | std::cerr << "Usage: read_file ~LINE N" << std::endl; 198 | return; 199 | } 200 | size_t line_number = std::stoi(args[2]) - 1; 201 | if (line_number < lines.size()) 202 | { 203 | printLines(lines, line_number, line_number + 1); 204 | } 205 | else 206 | { 207 | std::cerr << "Line number out of range." << std::endl; 208 | } 209 | } 210 | else 211 | { 212 | std::cerr << "Invalid position format." << std::endl; 213 | } 214 | } 215 | } 216 | 217 | // Hàm để hiển thị kích thước file và số lượng dòng 218 | void showFileSize(const std::string &fileName) 219 | { 220 | try 221 | { 222 | auto fileSize = fs::file_size(fileName); 223 | std::ifstream file(fileName); 224 | size_t lineCount = 0; 225 | std::string line; 226 | while (std::getline(file, line)) 227 | { 228 | lineCount++; 229 | } 230 | std::cout << "Size of file " << fileName << ": " << fileSize << " bytes" << std::endl; 231 | std::cout << "Number of lines in file " << fileName << ": " << lineCount << std::endl; 232 | } 233 | catch (const fs::filesystem_error &e) 234 | { 235 | std::cerr << "Error: " << e.what() << std::endl; 236 | } 237 | } 238 | 239 | // Hàm để mở file 240 | void openFile(const std::vector &args) 241 | { 242 | if (args.size() != 1) 243 | { 244 | std::cout << "Usage: open " << std::endl; 245 | return; 246 | } 247 | std::string filePath = args[0]; 248 | ShellExecuteA(NULL, "open", filePath.c_str(), NULL, NULL, SW_SHOW); 249 | } 250 | 251 | // Hàm để đổi tên file 252 | void renameFile(const std::vector &args) 253 | { 254 | if (args.size() != 2) 255 | { 256 | std::cout << "Usage: rename " << std::endl; 257 | return; 258 | } 259 | fs::path oldPath = args[0]; 260 | fs::path newPath = args[1]; 261 | if (!fs::exists(oldPath)) 262 | { 263 | std::cout << "File does not exist: " << oldPath << std::endl; 264 | return; 265 | } 266 | fs::rename(oldPath, newPath); 267 | std::cout << "File renamed from " << oldPath << " to " << newPath << std::endl; 268 | } 269 | 270 | // Hàm để tạo một hoặc nhiều file 271 | void createFile(const std::vector &fileNames) 272 | { 273 | for (const auto &fileName : fileNames) 274 | { 275 | std::ofstream file(fileName); 276 | if (file) 277 | { 278 | std::cout << "File created successfully: " << fileName << std::endl; 279 | } 280 | else 281 | { 282 | std::cerr << "Failed to create file: " << fileName << std::endl; 283 | } 284 | } 285 | } 286 | 287 | // Hàm để xóa một hoặc nhiều file 288 | void deleteFile(const std::vector &fileNames) 289 | { 290 | for (const auto &fileName : fileNames) 291 | { 292 | if (fs::remove(fileName)) 293 | { 294 | std::cout << "File deleted successfully: " << fileName << std::endl; 295 | } 296 | else 297 | { 298 | std::cerr << "Failed to delete file: " << fileName << std::endl; 299 | } 300 | } 301 | } 302 | 303 | // Hàm để kiểm tra xem file có tồn tại không 304 | void checkFileExistence(const std::vector &fileNames) 305 | { 306 | for (const auto &fileName : fileNames) 307 | { 308 | if (fs::exists(fileName)) 309 | { 310 | std::cout << "File exists: " << fileName << std::endl; 311 | } 312 | else 313 | { 314 | std::cout << "File does not exist: " << fileName << std::endl; 315 | } 316 | } 317 | } 318 | 319 | // Hàm in ra phần mở rộng của một hay nhiều file 320 | void printFileExtensions(const std::vector &fileNames) 321 | { 322 | for (const auto &fileName : fileNames) 323 | { 324 | std::cout << "Extension of file " << fileName << ": " << fs::path(fileName).extension() << std::endl; 325 | } 326 | } 327 | 328 | // Hàm sao chép file 329 | void copyFile(const std::vector &args) 330 | { 331 | if (args.size() != 2) 332 | { 333 | std::cout << "Usage: copy_file " << std::endl; 334 | return; 335 | } 336 | std::string source = args[0]; 337 | std::string destination = args[1]; 338 | try 339 | { 340 | fs::copy_file(source, destination); 341 | std::cout << "File copied successfully from " << source << " to " << destination << std::endl; 342 | } 343 | catch (const fs::filesystem_error &e) 344 | { 345 | std::cerr << "Error: " << e.what() << std::endl; 346 | } 347 | } 348 | 349 | // Hàm để di chuyển file 350 | void moveFile(const std::vector &args) 351 | { 352 | if (args.size() != 2) 353 | { 354 | std::cout << "Usage: move_file " << std::endl; 355 | return; 356 | } 357 | std::string source = args[0]; 358 | std::string destination = args[1]; 359 | try 360 | { 361 | fs::rename(source, destination); 362 | std::cout << "File moved successfully from " << source << " to " << destination << std::endl; 363 | } 364 | catch (const fs::filesystem_error &e) 365 | { 366 | std::cerr << "Error: " << e.what() << std::endl; 367 | } 368 | } 369 | 370 | // Hàm để liệt kê tất cả file có đuôi xác định trong thư mục 371 | void listFilesWithExtension(const std::vector &args) 372 | { 373 | if (args.size() > 2) 374 | { 375 | std::cout << "Usage: list_file " << std::endl; 376 | return; 377 | } 378 | 379 | // Nếu chỉ có 1 tham số, in ra tất cả file trong thư mục đó 380 | if (args.size() == 1) 381 | { 382 | std::string directory = args[0]; 383 | for (const auto &entry : fs::directory_iterator(directory)) 384 | { 385 | if (entry.is_regular_file()) 386 | { 387 | std::cout << entry.path().filename() << std::endl; 388 | } 389 | } 390 | return; 391 | } 392 | 393 | // Nếu có 2 tham số, in ra tất cả file có đuôi xác định trong thư mục đó 394 | std::string directory = args[0]; 395 | std::string extension = args[1]; 396 | for (const auto &entry : fs::directory_iterator(directory)) 397 | { 398 | if (entry.is_regular_file() && entry.path().extension() == extension) 399 | { 400 | std::cout << entry.path().filename() << std::endl; 401 | } 402 | } 403 | } 404 | 405 | private: 406 | static bool interrupted; 407 | 408 | // Hàm xử lý tín hiệu SIGINT 409 | static void signalHandler(int signum) 410 | { 411 | interrupted = true; 412 | } 413 | 414 | // Hàm để in các dòng từ start đến end-1 415 | void printLines(const std::vector &lines, size_t start, size_t end) 416 | { 417 | for (size_t i = start; i < end; ++i) 418 | { 419 | std::cout << lines[i] << std::endl; 420 | } 421 | std::cout << "End of reading. Returning to shell..." << std::endl; 422 | } 423 | 424 | // Hàm để in các dòng từ start đến end-1 với tạm dừng 425 | void printLinesWithPause(const std::vector &lines, size_t start, size_t end) 426 | { 427 | for (size_t i = start; i < end; ++i) 428 | { 429 | std::cout << lines[i] << std::endl; 430 | if (interrupted) 431 | { 432 | std::cout << "\nReading interrupted. Returning to shell..." << std::endl; 433 | interrupted = false; // Reset flag 434 | return; 435 | } 436 | 437 | if ((i + 1) % 5 == 0 && i + 1 < end) 438 | { 439 | std::cout << "[READ MORE] (Press any key to continue, Ctrl+C to quit)..." << std::endl; 440 | char ch = _getch(); 441 | if (ch == 3) 442 | { // Ctrl+C 443 | std::cout << "\nReading interrupted. Returning to shell..." << std::endl; 444 | return; 445 | } 446 | } 447 | } 448 | std::cout << "End of reading. Returning to shell..." << std::endl; 449 | } 450 | }; 451 | 452 | // Khởi tạo biến tĩnh 453 | bool FileManager::interrupted = false; 454 | 455 | // Khởi tạo danh sách các câu lệnh mà đối tượng này hỗ trợ 456 | const std::unordered_set FileManager::supportedCommands = { 457 | "write_file", 458 | "read_file", 459 | "file_size", 460 | "open", 461 | "rename"}; 462 | 463 | #endif // FILE_H 464 | -------------------------------------------------------------------------------- /Feature/process.h: -------------------------------------------------------------------------------- 1 | #ifndef PROCESS_H 2 | #define PROCESS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | class ProcessManager 18 | { 19 | public: 20 | static const std::unordered_set supportedCommands; 21 | 22 | static const std::unordered_set &getSupportedCommands() 23 | { 24 | return supportedCommands; 25 | } 26 | 27 | DWORD findChildProcess(DWORD parentPID) 28 | { 29 | HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 30 | if (hProcessSnap == INVALID_HANDLE_VALUE) 31 | { 32 | std::cerr << "Failed to create process snapshot: " << GetLastError() << std::endl; 33 | return 0; 34 | } 35 | 36 | PROCESSENTRY32 pe32; 37 | pe32.dwSize = sizeof(PROCESSENTRY32); 38 | 39 | if (!Process32First(hProcessSnap, &pe32)) 40 | { 41 | std::cerr << "Failed to retrieve process information: " << GetLastError() << std::endl; 42 | CloseHandle(hProcessSnap); 43 | return 0; 44 | } 45 | 46 | DWORD childPID = 0; 47 | do 48 | { 49 | if (pe32.th32ParentProcessID == parentPID) 50 | { 51 | childPID = pe32.th32ProcessID; 52 | break; 53 | } 54 | } while (Process32Next(hProcessSnap, &pe32)); 55 | 56 | CloseHandle(hProcessSnap); 57 | return childPID; 58 | } 59 | 60 | // Hàm đợi tất cả tiến trình con của một tiến trình cha kết thúc 61 | void waitForChildProcesses(DWORD parentPID) 62 | { 63 | std::set childPIDs; 64 | HANDLE hProcessSnap; 65 | PROCESSENTRY32 pe32; 66 | 67 | hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 68 | if (hProcessSnap == INVALID_HANDLE_VALUE) 69 | { 70 | std::cerr << "Failed to create process snapshot: " << GetLastError() << std::endl; 71 | return; 72 | } 73 | 74 | pe32.dwSize = sizeof(PROCESSENTRY32); 75 | 76 | if (!Process32First(hProcessSnap, &pe32)) 77 | { 78 | std::cerr << "Failed to retrieve process information: " << GetLastError() << std::endl; 79 | CloseHandle(hProcessSnap); 80 | return; 81 | } 82 | 83 | do 84 | { 85 | if (pe32.th32ParentProcessID == parentPID) 86 | { 87 | childPIDs.insert(pe32.th32ProcessID); 88 | } 89 | } while (Process32Next(hProcessSnap, &pe32)); 90 | 91 | CloseHandle(hProcessSnap); 92 | 93 | for (auto pid : childPIDs) 94 | { 95 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); 96 | if (hProcess) 97 | { 98 | WaitForSingleObject(hProcess, INFINITE); 99 | CloseHandle(hProcess); 100 | waitForChildProcesses(pid); // Đệ quy để đợi các tiến trình con của tiến trình con 101 | } 102 | } 103 | } 104 | 105 | void startProcessForeground(const std::vector &args) 106 | { 107 | if (args.size() < 1) 108 | { 109 | std::cerr << "Usage: start_foreground " << std::endl; 110 | return; 111 | } 112 | 113 | std::string command = args[0]; 114 | for (size_t i = 1; i < args.size(); ++i) 115 | { 116 | command += " " + args[i]; 117 | } 118 | 119 | STARTUPINFOA si = {sizeof(si)}; 120 | PROCESS_INFORMATION pi; 121 | char *cmd = new char[command.length() + 1]; 122 | strcpy(cmd, command.c_str()); 123 | 124 | if (!CreateProcessA(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) 125 | { 126 | std::cerr << "Failed to start process: " << GetLastError() << std::endl; 127 | delete[] cmd; // Giải phóng bộ nhớ 128 | return; 129 | } 130 | 131 | // Đợi tiến trình chính kết thúc 132 | WaitForSingleObject(pi.hProcess, INFINITE); 133 | CloseHandle(pi.hProcess); 134 | CloseHandle(pi.hThread); 135 | 136 | // Đợi cho tất cả các tiến trình con của tiến trình chính kết thúc 137 | waitForChildProcesses(pi.dwProcessId); 138 | 139 | delete[] cmd; // Giải phóng bộ nhớ 140 | } 141 | 142 | void startProcessBackground(const std::vector &args) 143 | { 144 | if (args.size() < 1) 145 | { 146 | std::cout << "Usage: start [arguments...]" << std::endl; 147 | return; 148 | } 149 | 150 | std::string command = args[0]; 151 | for (size_t i = 1; i < args.size(); ++i) 152 | { 153 | command += " " + args[i]; 154 | } 155 | 156 | STARTUPINFOA si = {sizeof(si)}; 157 | PROCESS_INFORMATION pi; 158 | ZeroMemory(&pi, sizeof(pi)); 159 | 160 | char *cmd = new char[command.length() + 1]; 161 | strcpy(cmd, command.c_str()); 162 | 163 | if (!CreateProcessA(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) 164 | { 165 | std::cerr << "Failed to start process: " << GetLastError() << std::endl; 166 | delete[] cmd; // Giải phóng bộ nhớ 167 | return; 168 | } 169 | std::cout << "Started process with PID: " << pi.dwProcessId << std::endl; 170 | 171 | // Wait a bit and check for child processes 172 | Sleep(1000); 173 | DWORD childPID = findChildProcess(pi.dwProcessId); 174 | if (childPID != 0) 175 | { 176 | std::cout << "Detected child process with PID: " << childPID << std::endl; 177 | } 178 | else 179 | { 180 | std::cout << "No child process detected for PID: " << pi.dwProcessId << std::endl; 181 | } 182 | 183 | CloseHandle(pi.hProcess); 184 | CloseHandle(pi.hThread); 185 | delete[] cmd; // Giải phóng bộ nhớ 186 | } 187 | 188 | // Nhóm Forground | Nhóm này không nên chạy Background 189 | void startTicTacToe() 190 | { 191 | std::vector args = {"Process/tictactoe.exe"}; 192 | startProcessForeground(args); 193 | } 194 | 195 | void startDuck() 196 | { 197 | std::vector args = {"Process/duck.exe"}; 198 | startProcessForeground(args); 199 | } 200 | 201 | // Nhóm Background | Nhóm này vẫn có thể chạy Foreground 202 | void startCountdownProcess() 203 | { 204 | std::vector args = {"Process/countdown.exe"}; 205 | startProcessBackground(args); 206 | } 207 | 208 | void startChildProcess() 209 | { 210 | std::vector args = {"Process/child.exe"}; 211 | startProcessBackground(args); 212 | } 213 | 214 | void suspendProc(const vector &args) 215 | { 216 | if (args.size() != 1) 217 | { 218 | cerr << "Usage: suspend \n"; 219 | return; 220 | } 221 | DWORD dwProcessId = stoul(args[0]); 222 | 223 | HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 224 | if (hSnapshot == INVALID_HANDLE_VALUE) 225 | { 226 | cerr << "System error!\n"; 227 | return; 228 | } 229 | 230 | THREADENTRY32 te; 231 | te.dwSize = sizeof(THREADENTRY32); 232 | 233 | if (!Thread32First(hSnapshot, &te)) 234 | { 235 | CloseHandle(hSnapshot); 236 | cerr << "System error!\n"; 237 | return; 238 | } 239 | 240 | do 241 | { 242 | if (te.th32OwnerProcessID == dwProcessId) 243 | { 244 | HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID); 245 | if (hThread != NULL) 246 | { 247 | SuspendThread(hThread); 248 | CloseHandle(hThread); 249 | } 250 | else 251 | { 252 | cerr << "System error!\n"; 253 | return; 254 | } 255 | } 256 | } while (Thread32Next(hSnapshot, &te)); 257 | 258 | CloseHandle(hSnapshot); 259 | } 260 | 261 | void resumeProc(const vector &args) 262 | { 263 | if (args.size() != 1) 264 | { 265 | cerr << "Usage: resume \n"; 266 | return; 267 | } 268 | DWORD dwProcessId = stoul(args[0]); 269 | 270 | HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 271 | if (hSnapshot == INVALID_HANDLE_VALUE) 272 | { 273 | cerr << "System error!\n"; 274 | return; 275 | } 276 | 277 | THREADENTRY32 te; 278 | te.dwSize = sizeof(THREADENTRY32); 279 | 280 | if (!Thread32First(hSnapshot, &te)) 281 | { 282 | CloseHandle(hSnapshot); 283 | cerr << "System error!\n"; 284 | return; 285 | } 286 | 287 | do 288 | { 289 | if (te.th32OwnerProcessID == dwProcessId) 290 | { 291 | HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID); 292 | if (hThread != NULL) 293 | { 294 | ResumeThread(hThread); 295 | CloseHandle(hThread); 296 | } 297 | else 298 | { 299 | cerr << "System error!\n"; 300 | return; 301 | } 302 | } 303 | } while (Thread32Next(hSnapshot, &te)); 304 | 305 | CloseHandle(hSnapshot); 306 | } 307 | 308 | void listProcesses(const std::vector &args) 309 | { 310 | HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 311 | if (hProcessSnap == INVALID_HANDLE_VALUE) 312 | { 313 | std::cerr << "Failed to create process snapshot: " << GetLastError() << std::endl; 314 | return; 315 | } 316 | 317 | PROCESSENTRY32 pe32; 318 | pe32.dwSize = sizeof(PROCESSENTRY32); 319 | 320 | if (!Process32First(hProcessSnap, &pe32)) 321 | { 322 | std::cerr << "Failed to retrieve process information: " << GetLastError() << std::endl; 323 | CloseHandle(hProcessSnap); 324 | return; 325 | } 326 | 327 | std::cout << std::left << std::setw(8) << "PID" << std::setw(50) << "Process Name" << "Status" << std::endl; 328 | std::cout << "---------------------------------------------------" << std::endl; 329 | do 330 | { 331 | #ifdef UNICODE 332 | std::wstring_convert> converter; 333 | std::string processName = converter.to_bytes(pe32.szExeFile); 334 | #else 335 | std::string processName = pe32.szExeFile; 336 | #endif 337 | 338 | HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID); 339 | std::string processStatus = "Unknown"; 340 | if (hProcess) 341 | { 342 | DWORD exitCode; 343 | if (GetExitCodeProcess(hProcess, &exitCode)) 344 | { 345 | if (exitCode == STILL_ACTIVE) 346 | { 347 | processStatus = "Running"; 348 | } 349 | else 350 | { 351 | processStatus = "Terminated"; 352 | } 353 | } 354 | CloseHandle(hProcess); 355 | } 356 | else 357 | { 358 | processStatus = "Access Denied"; 359 | } 360 | 361 | std::cout << std::left << std::setw(8) << pe32.th32ProcessID << std::setw(50) << processName << processStatus << std::endl; 362 | } while (Process32Next(hProcessSnap, &pe32)); 363 | 364 | CloseHandle(hProcessSnap); 365 | } 366 | 367 | void terminateProcess(const std::vector &args) 368 | { 369 | if (args.size() != 1) 370 | { 371 | std::cout << "Usage: terminate " << std::endl; 372 | return; 373 | } 374 | 375 | DWORD pid = std::stoul(args[0]); 376 | 377 | // Thử mở tiến trình với quyền truy cập thông tin và hủy bỏ 378 | HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE, FALSE, pid); 379 | if (!hProcess) 380 | { 381 | DWORD error = GetLastError(); 382 | std::cerr << "Failed to open process for querying and termination: " << error << std::endl; 383 | 384 | if (error == ERROR_ACCESS_DENIED) 385 | { 386 | std::cerr << "Access denied. Please run the shell as administrator." << std::endl; 387 | } 388 | else if (error == ERROR_INVALID_PARAMETER) 389 | { 390 | std::cerr << "Invalid parameter. The process might not exist." << std::endl; 391 | } 392 | 393 | return; 394 | } 395 | 396 | if (!TerminateProcess(hProcess, 0)) 397 | { 398 | DWORD error = GetLastError(); 399 | std::cerr << "Failed to terminate process: " << error << std::endl; 400 | } 401 | else 402 | { 403 | std::cout << "Terminated process with PID: " << pid << std::endl; 404 | } 405 | 406 | CloseHandle(hProcess); 407 | } 408 | 409 | // Hàm để tìm tất cả tiến trình con của một tiến trình cha 410 | std::vector findAllChildProcesses(DWORD parentPID) 411 | { 412 | std::vector childPIDs; 413 | HANDLE hProcessSnap; 414 | PROCESSENTRY32 pe32; 415 | 416 | hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 417 | if (hProcessSnap == INVALID_HANDLE_VALUE) 418 | { 419 | std::cerr << "Failed to create process snapshot: " << GetLastError() << std::endl; 420 | return childPIDs; 421 | } 422 | 423 | pe32.dwSize = sizeof(PROCESSENTRY32); 424 | 425 | if (!Process32First(hProcessSnap, &pe32)) 426 | { 427 | std::cerr << "Failed to retrieve process information: " << GetLastError() << std::endl; 428 | CloseHandle(hProcessSnap); 429 | return childPIDs; 430 | } 431 | 432 | do 433 | { 434 | if (pe32.th32ParentProcessID == parentPID) 435 | { 436 | childPIDs.push_back(pe32.th32ProcessID); 437 | } 438 | } while (Process32Next(hProcessSnap, &pe32)); 439 | 440 | CloseHandle(hProcessSnap); 441 | return childPIDs; 442 | } 443 | 444 | // Hàm để in ra tất cả tiến trình con của một tiến trình cha 445 | void printAllChildProcesses(const std::vector &args) 446 | { 447 | if (args.size() != 1) 448 | { 449 | std::cerr << "Usage: list_children " << std::endl; 450 | return; 451 | } 452 | 453 | DWORD parentPID = std::stoul(args[0]); 454 | std::vector childPIDs = findAllChildProcesses(parentPID); 455 | 456 | if (childPIDs.empty()) 457 | { 458 | std::cout << "No child processes found for PID: " << parentPID << std::endl; 459 | } 460 | else 461 | { 462 | std::cout << "Child processes of PID " << parentPID << ":" << std::endl; 463 | for (DWORD pid : childPIDs) 464 | { 465 | std::cout << " PID: " << pid << std::endl; 466 | } 467 | } 468 | } 469 | }; 470 | 471 | const std::unordered_set ProcessManager::supportedCommands = { 472 | "start_foreground", 473 | "start_background", 474 | "tictactoe", 475 | "duck", 476 | "countdown", 477 | "child", 478 | "suspend", 479 | "resume", 480 | "list_processes", 481 | "terminate", 482 | "list_children"}; 483 | 484 | #endif // PROCESS_H -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "Feature/features.h" 9 | 10 | CommandHistory commandHistory; 11 | FunctionManager functionManager; 12 | EnvironmentManager environmentManager; 13 | VariableManager variableManager(environmentManager); 14 | FileManager fileManager; 15 | ProcessManager processManager; 16 | DirectoryManager directoryManager; 17 | SystemUtils systemUtils; 18 | AliasManager aliasManager; 19 | BookmarkManager bookmarkManager; 20 | ConsoleColor currentColor = ConsoleColor::WHITE; 21 | 22 | // Hàm in ra các thông tin ban đầu khi shell khởi động 23 | void printInitialInfo() 24 | { 25 | // Lấy PID của chính tiến trình hiện tại (main.exe) 26 | DWORD pid = GetCurrentProcessId(); 27 | 28 | // In ra các thông tin ban đầu 29 | std::cout << "========================================" << std::endl; 30 | std::cout << " Tiny Shell " << std::endl; 31 | std::cout << "========================================" << std::endl; 32 | std::cout << "Welcome to Tiny Shell!" << std::endl; 33 | std::cout << "This is a simple shell program to interact with the Windows operating system." << std::endl; 34 | std::cout << "PID of Tiny Shell: " << pid << std::endl; 35 | std::cout << "Type 'help' to see the list of available commands." << std::endl; 36 | std::cout << "========================================" << std::endl; 37 | } 38 | 39 | // Hàm thực thi lệnh -> Có tất cả 58 lệnh 40 | void executeCommand(const std::string &command, const std::vector &args) 41 | { 42 | if (command == "change_color") 43 | { 44 | if (!args.empty()) 45 | { 46 | currentColor = parseColor(args[0]); 47 | setColor(currentColor); 48 | std::cout << "Color changed to " << args[0] << std::endl; 49 | } 50 | else 51 | { 52 | std::cout << "Usage: change_color " << std::endl; 53 | } 54 | return; // Ensure the color change command exits the function 55 | } 56 | if (command == "delete") 57 | { 58 | directoryManager.deleteDirectory(args); 59 | } 60 | else if (command == "move") 61 | { 62 | directoryManager.moveDirectory(args); 63 | } 64 | else if (command == "open") 65 | { 66 | fileManager.openFile(args); 67 | } 68 | else if (command == "create_file") 69 | { 70 | fileManager.createFile(args); 71 | } 72 | else if (command == "delete_file") 73 | { 74 | fileManager.deleteFile(args); 75 | } 76 | else if (command == "move_file") 77 | { 78 | fileManager.moveFile(args); 79 | } 80 | else if (command == "copy_file") 81 | { 82 | fileManager.copyFile(args); 83 | } 84 | else if (command == "check_file") 85 | { 86 | fileManager.checkFileExistence(args); 87 | } 88 | else if (command == "extension_file") 89 | { 90 | fileManager.printFileExtensions(args); 91 | } 92 | else if (command == "list_file") 93 | { 94 | fileManager.listFilesWithExtension(args); 95 | } 96 | else if (command == "exit") 97 | { 98 | exitShell(); 99 | PostQuitMessage(0); // Exit the program 100 | } 101 | else if (command == "list_tree") 102 | { 103 | directoryManager.listDirectoryTree(args); 104 | } 105 | else if (command == "create") 106 | { 107 | directoryManager.createDirectory(args); 108 | } 109 | else if (command == "copy") 110 | { 111 | directoryManager.copyDirectory(args); 112 | } 113 | else if (command == "run") 114 | { 115 | runScript(args); 116 | } 117 | else if (command == "help") 118 | { 119 | showHelp(args); 120 | } 121 | else if (command == "rename") 122 | { 123 | fileManager.renameFile(args); 124 | } 125 | else if (command == "cd") 126 | { 127 | changeDirectory(args); 128 | } 129 | else if (command == "dir") 130 | { 131 | listDirectoryContents(args); 132 | } 133 | else if (command == "pwd") 134 | { 135 | printWorkingDirectory(args); 136 | } 137 | else if (command == "start_foreground") 138 | { 139 | processManager.startProcessForeground(args); 140 | } 141 | else if (command == "start_background") 142 | { 143 | processManager.startProcessBackground(args); 144 | } 145 | else if (command == "terminate") 146 | { 147 | processManager.terminateProcess(args); 148 | } 149 | else if (command == "list_processes") 150 | { 151 | processManager.listProcesses(args); 152 | } 153 | else if (command == "list_children") 154 | { 155 | processManager.printAllChildProcesses(args); 156 | } 157 | else if (command == "child") 158 | { 159 | processManager.startChildProcess(); 160 | } 161 | else if (command == "countdown") 162 | { 163 | processManager.startCountdownProcess(); 164 | } 165 | else if (command == "manage_threads") 166 | { 167 | handleManageThreadsCommand(args); 168 | } 169 | else if (command == "time") 170 | { 171 | systemUtils.showSystemTime(args); 172 | } 173 | else if (command == "date") 174 | { 175 | systemUtils.showSystemDate(args); 176 | } 177 | else if (command == "uptime") 178 | { 179 | systemUtils.showSystemUptime(args); 180 | } 181 | else if (command == "cpuinfo") 182 | { 183 | systemUtils.showCPUInfo(args); 184 | } 185 | else if (command == "meminfo") 186 | { 187 | systemUtils.showMemoryInfo(args); 188 | } 189 | else if (command == "diskinfo") 190 | { 191 | systemUtils.showDiskInfo(args); 192 | } 193 | else if (command == "calculator") 194 | { 195 | systemUtils.showCalculator(args); 196 | } 197 | else if (command == "history") 198 | { 199 | commandHistory.show(); 200 | } 201 | else if (command == "clear_history") 202 | { 203 | commandHistory.clear(); 204 | } 205 | else if (command == "clear") 206 | { 207 | clearScreen(); 208 | } 209 | else if (command == "calculate") 210 | { 211 | // Nếu có tham số truyền vào thì thực hiện tính toán 212 | if (!args.empty()) 213 | { 214 | // Gọi hàm evaluateExpression từ biến variableManager để tính toán biểu thức 215 | try 216 | { 217 | double result = variableManager.evaluateExpression(args); 218 | std::cout << result << std::endl; 219 | } 220 | catch (const std::exception &e) 221 | { 222 | std::cout << "Error: " << e.what() << std::endl; 223 | } 224 | } 225 | else 226 | { 227 | std::cout << "Usage: calculate " << std::endl; 228 | } 229 | } 230 | else if (command == "dancing") 231 | { 232 | dancing(); 233 | } 234 | else if (command == "tictactoe") 235 | { 236 | processManager.startTicTacToe(); 237 | } 238 | else if (command == "duck") 239 | { 240 | processManager.startDuck(); 241 | } 242 | else if (command == "function") 243 | { 244 | try 245 | { 246 | functionManager.defineFunction(args); 247 | } 248 | catch (const std::exception &e) 249 | { 250 | std::cout << "Error: " << e.what() << std::endl; 251 | } 252 | } 253 | else if (command == "evaluate") 254 | { 255 | try 256 | { 257 | double result = functionManager.evaluateFunction(args, variableManager); 258 | std::cout << result << std::endl; 259 | } 260 | catch (const std::exception &e) 261 | { 262 | std::cout << "Error: " << e.what() << std::endl; 263 | } 264 | } 265 | else if (command == "if") 266 | { 267 | if (args.size() < 1) 268 | { 269 | std::cout << "Usage: if (): else " << std::endl; 270 | } 271 | else 272 | { 273 | handleIfElse(args, variableManager); 274 | } 275 | } 276 | else if (command == "loop") 277 | { 278 | if (args.size() < 1) 279 | { 280 | std::cout << "Usage: loop & & ..." << std::endl; 281 | } 282 | else 283 | { 284 | handleLoop(args); 285 | } 286 | } 287 | else if (command == "suspend") 288 | { 289 | processManager.suspendProc(args); 290 | } 291 | else if (command == "resume") 292 | { 293 | processManager.resumeProc(args); 294 | } 295 | else if (command == "add_path") 296 | { 297 | if (!args.empty()) 298 | { 299 | environmentManager.addToPath(args[0]); 300 | } 301 | else 302 | { 303 | std::cout << "Usage: add_path " << std::endl; 304 | } 305 | } 306 | else if (command == "remove_path") 307 | { 308 | if (!args.empty()) 309 | { 310 | environmentManager.removeFromPath(args[0]); 311 | } 312 | else 313 | { 314 | std::cout << "Usage: remove_path " << std::endl; 315 | } 316 | } 317 | else if (command == "print_env") 318 | { 319 | if (!args.empty()) 320 | { 321 | environmentManager.printEnv(args[0]); 322 | } 323 | else 324 | { 325 | std::cout << "Usage: print_env " << std::endl; 326 | } 327 | } 328 | else if (command == "set_env") 329 | { 330 | // // Nếu có đúng 2 tham số thì thiết lập biến môi trường 331 | // if (args.size() == 2) 332 | // { 333 | // environmentManager.setEnv(args[0], args[1]); 334 | // } 335 | // // Nếu có nhiều hơn 2 tham số thì phần tử thứ 2 trở đi sẽ là biểu thức cần tính toán 336 | // else if (args.size() > 2) 337 | // { 338 | // std::vector expression(args.begin() + 1, args.end()); 339 | // try 340 | // { 341 | // int result = variableManager.evaluateExpression(expression); 342 | // environmentManager.setEnv(args[0], std::to_string(result)); 343 | // } 344 | // catch (const std::exception &e) 345 | // { 346 | // std::cout << "Error: " << e.what() << std::endl; 347 | // } 348 | // } // Nếu không có tham số nào thì thông báo lỗi 349 | // else 350 | // { 351 | // std::cout << "Usage: set_env or set_env " << std::endl; 352 | // } 353 | 354 | // Nếu có đúng 3 tham số và tham số thứ 2 là dấu bằng (=) thì thiết lập biến môi trường 355 | if (args.size() == 3 && args[1] == "=") 356 | { 357 | environmentManager.setEnv(args[0], args[2]); 358 | } 359 | // Nếu có nhiều hơn 3 tham số thì phần tử thứ 2 trở đi sẽ là biểu thức cần tính toán 360 | else if (args.size() > 3) 361 | { 362 | std::vector expression(args.begin() + 2, args.end()); 363 | try 364 | { 365 | int result = variableManager.evaluateExpression(expression); 366 | environmentManager.setEnv(args[0], std::to_string(result)); 367 | } 368 | catch (const std::exception &e) 369 | { 370 | std::cout << "Error: " << e.what() << std::endl; 371 | } 372 | } 373 | // Nếu không có tham số nào thì thông báo lỗi 374 | else 375 | { 376 | std::cout << "Usage: set_env = or set_env = " << std::endl; 377 | } 378 | } 379 | else if (command == "unset_env") 380 | { 381 | if (!args.empty()) 382 | { 383 | environmentManager.unsetEnv(args[0]); 384 | } 385 | else 386 | { 387 | std::cout << "Usage: unset_env " << std::endl; 388 | } 389 | } 390 | else if (command == "list_env") 391 | { 392 | environmentManager.listAllEnv(); 393 | } 394 | else if (command == "is_in_path") 395 | { 396 | if (!args.empty()) 397 | { 398 | bool result = environmentManager.isInPath(args[0]); 399 | std::cout << args[0] << (result ? " is" : " is not") << " in PATH." << std::endl; 400 | } 401 | else 402 | { 403 | std::cout << "Usage: is_in_path " << std::endl; 404 | } 405 | } 406 | else if (command == "save_env") 407 | { 408 | if (!args.empty()) 409 | { 410 | environmentManager.saveEnvToFile(args[0]); 411 | } 412 | else 413 | { 414 | std::cout << "Usage: save_env " << std::endl; 415 | } 416 | } 417 | else if (command == "load_env") 418 | { 419 | if (!args.empty()) 420 | { 421 | environmentManager.loadEnvFromFile(args[0]); 422 | } 423 | else 424 | { 425 | std::cout << "Usage: load_env " << std::endl; 426 | } 427 | } 428 | else if (command == "write_file") 429 | { 430 | try 431 | { 432 | fileManager.writeFile(args); 433 | } 434 | catch (const std::exception &e) 435 | { 436 | std::cout << "Error: " << e.what() << std::endl; 437 | } 438 | } 439 | else if (command == "read_file") 440 | { 441 | try 442 | { 443 | fileManager.readFile(args); 444 | } 445 | catch (const std::exception &e) 446 | { 447 | std::cout << "Error: " << e.what() << std::endl; 448 | } 449 | } 450 | else if (command == "file_size") 451 | { 452 | if (!args.empty()) 453 | { 454 | fileManager.showFileSize(args[0]); 455 | } 456 | else 457 | { 458 | std::cout << "Usage: file_size " << std::endl; 459 | } 460 | } 461 | else if (command == "convert") 462 | { 463 | handleBaseConversion(args); 464 | } 465 | else if (command == "bookmark") 466 | { 467 | if (args.size() == 3 && args[0] == "add") 468 | { 469 | bookmarkManager.addBookmark(args[1], args[2]); 470 | } 471 | else if (args.size() == 2 && args[0] == "remove") 472 | { 473 | bookmarkManager.removeBookmark(args[1]); 474 | } 475 | else if (args.size() == 1 && args[0] == "list") 476 | { 477 | bookmarkManager.listBookmarks(); 478 | } 479 | else if (args.size() == 2 && args[0] == "go") 480 | { 481 | bookmarkManager.goBookmark(args[1]); 482 | } 483 | else if (args.size() == 1 && args[0] == "home") 484 | { 485 | bookmarkManager.goHomeDirectory(); 486 | } 487 | else 488 | { 489 | std::cerr << "Usage: bookmark [add | remove | list | go | home]" << std::endl; 490 | } 491 | } 492 | else if (command == "after") 493 | { 494 | scheduleCommand(args); 495 | } 496 | else if (command == "alias") 497 | { 498 | if (args.empty()) 499 | { 500 | aliasManager.listAliases(); 501 | } 502 | else if (args.size() == 3) 503 | { 504 | aliasManager.addAlias(args[0], args[2]); 505 | } 506 | else 507 | { 508 | std::cerr << "Usage: alias = or alias" << std::endl; 509 | } 510 | } 511 | else if (command == "unalias") 512 | { 513 | if (!args.empty()) 514 | { 515 | aliasManager.removeAlias(args[0]); 516 | } 517 | else 518 | { 519 | std::cerr << "Usage: unalias " << std::endl; 520 | } 521 | } 522 | else 523 | { 524 | std::cout << "Unknown command: " << command << std::endl; 525 | } 526 | } 527 | 528 | // Hàm này để tách input thành các tokens, mỗi token là một phần của input 529 | /* Ví dụ: 530 | | Input: calcualte 1 + 2 => tokens: ["calculate", "1", "+", "2"] 531 | | Input write_file "Hello World" "output.txt" => tokens: ["write_file", "Hello World", "output.txt"] 532 | | 533 | | [!] Một số trường hợp khi toán tử (các dấu ngoặc, +, -, *, /) không có khoảng trắng ở giữa, 534 | | cần phải tách ra thành các token riêng biệt. 535 | | Ví dụ: calculate (1+2) => tokens: ["calculate", "(", "1", "+", "2", ")"] 536 | | 537 | | [!] Một số trường hợp khi có dấu ngoặc kép, cần phải giữ nguyên nội dung trong dấu ngoặc. 538 | | Và nếu gặp dấu phẩy (,) thì cũng cần phải tách ra thành token riêng biệt. 539 | | Ví dụ: function f(x, y) "x + y" => tokens: ["function", "f", "(", "x", ",", "y", ")", "\"x + y\""] 540 | */ 541 | std::vector splitInput(const std::string &input) 542 | { 543 | std::vector tokens; 544 | std::string token; 545 | bool inQuotes = false; 546 | 547 | for (char ch : input) 548 | { 549 | if (ch == '\"') 550 | { 551 | inQuotes = !inQuotes; 552 | if (!inQuotes) // End of quoted string 553 | { 554 | tokens.push_back(token); 555 | token.clear(); 556 | } 557 | } 558 | else if (isspace(ch) && !inQuotes) 559 | { 560 | if (!token.empty()) 561 | { 562 | tokens.push_back(token); 563 | token.clear(); 564 | } 565 | } 566 | else if ((ch == '(' || ch == ')' || ch == ',' || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '<' || ch == '>') && !inQuotes) 567 | { 568 | if (!token.empty()) 569 | { 570 | tokens.push_back(token); 571 | token.clear(); 572 | } 573 | tokens.push_back(std::string(1, ch)); 574 | } 575 | else 576 | { 577 | token += ch; 578 | } 579 | } 580 | 581 | if (!token.empty()) 582 | { 583 | tokens.push_back(token); 584 | } 585 | 586 | // Nếu tokens không rỗng thì giải quyết alias 587 | if (!tokens.empty()) 588 | { 589 | tokens[0] = aliasManager.resolveAlias(tokens[0]); 590 | } 591 | 592 | return tokens; 593 | } 594 | 595 | int main() 596 | { 597 | // In ra thông tin ban đầu khi shell khởi động 598 | printInitialInfo(); 599 | 600 | commandHistory.load(); // Tải lịch sử từ file (nếu có) 601 | 602 | std::string input; 603 | 604 | signal(SIGINT, SIG_IGN); 605 | 606 | while (true) 607 | { 608 | setColor(ConsoleColor::YELLOW); 609 | std::cout << "tiny_shell> "; 610 | resetColor(); 611 | 612 | setColor(currentColor); 613 | 614 | std::getline(std::cin, input); 615 | 616 | if (std::cin.fail() || std::cin.eof()) 617 | { 618 | std::cin.clear(); 619 | std::cout << std::endl; 620 | continue; 621 | } 622 | 623 | // Ghi câu lệnh vào lịch sử 624 | commandHistory.add(input); 625 | 626 | // splitInput để tách input thành các tokens 627 | std::vector tokens = splitInput(input); 628 | 629 | if (tokens.empty()) 630 | continue; 631 | 632 | // Lấy lệnh từ tokens, là phần tử đầu tiên 633 | /* Ví dụ: 634 | | Input: calculate 1 + 2 => tokens: ["calculate", "1", "+", "2"] => command: "calculate" 635 | | Input write_file "Hello World" "output.txt" => tokens: ["write_file", "Hello World", "output.txt"] => command: "write_file" 636 | | Thành phần này quyết định hành động tiếp theo sẽ được thực hiện. 637 | */ 638 | std::string command = tokens[0]; 639 | 640 | // Xóa lệnh ra khỏi tokens => tokens chỉ còn các tham số của lệnh 641 | tokens.erase(tokens.begin()); 642 | 643 | // Xử lý các lệnh còn lại 644 | executeCommand(command, tokens); 645 | } 646 | return 0; 647 | } 648 | -------------------------------------------------------------------------------- /Document/Template/main.tex: -------------------------------------------------------------------------------- 1 | \input{setup} 2 | \input{macro} 3 | 4 | % \usepackage{handoutWithNotes} 5 | % \pgfpagesuselayout{1 on 1 with notes}[a4paper,border shrink=5mm] 6 | 7 | \AtBeginSection[]{ 8 | \begin{frame} 9 | \tableofcontents[currentsection] 10 | \end{frame} 11 | } 12 | 13 | \begin{document} 14 | 15 | \begin{frame} 16 | \titlepage 17 | \end{frame} 18 | 19 | \begin{frame}{Mục lục} 20 | \tableofcontents[hideallsubsections] 21 | \end{frame} 22 | 23 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 24 | 25 | \section{Giới thiệu chung} 26 | 27 | \subsection{Khái niệm} 28 | 29 | \begin{frame}{Giao diện dòng lệnh} 30 | \begin{itemize} 31 | \it em \cyan{Giao diện dòng lệnh} (Command Line Interface - CLI) là một phương thức tương tác giữa người dùng và hệ thống máy tính. \\ 32 | $\to$ Người dùng nhập các lệnh dưới \orange{dạng văn bản} và nhận phản hồi dưới dạng văn bản.\\ 33 | $\to$ \underline{Yêu cầu} người dùng có kiến thức về các lệnh và cú pháp. 34 | \item Chương trình xử lý giao diện dòng lệnh được gọi là Trình thông dịch dòng lệnh (command-line interpreter), Trình xử lý dòng lệnh (command-line processor), hay Shell. 35 | \end{itemize} 36 | \end{frame} 37 | 38 | \begin{frame}{Lời gọi hệ thống} 39 | \begin{itemize} 40 | \item \cyan{Lời gọi hệ thống} (system call) là một giao diện mà chương trình ứng dụng (user application) sử dụng để yêu cầu các dịch vụ từ hệ điều hành. 41 | \item Lời gọi hệ thống thường được gọi thông qua các hàm thư viện trong ngôn ngữ lập trình.\\ 42 | \vspace{10 pt} 43 | \orange{Ví dụ:} 44 | \begin{itemize} 45 | \item Trên Unix/Linux: \t{open()}, \t{wait()}, \t{mmap()}, \t{socket()},... 46 | \item Trên Windows: \t{CreateFile()}, \t{WaitForSingleObject()}, \t{VirtualAlloc()},... 47 | \end{itemize} 48 | \item Trên Windows, các lời gọi hệ thống được cung cấp thông qua các API của Windows, chủ yếu từ Windows API (WinAPI). Các lời gọi hệ thống trên Windows thường phức tạp hơn và bao gồm nhiều chức năng bổ sung để tương thích với kiến trúc của Windows. 49 | \end{itemize} 50 | \end{frame} 51 | 52 | \subsection{Windows API} 53 | \begin{frame}{Windows API} 54 | \begin{itemize} 55 | \item \cyan{Windows API} là một tập hợp các giao diện lập trình ứng dụng được Microsoft cung cấp, cho phép các phần mềm tương tác với hệ điều hành Windows. 56 | \item \underline{Chức năng:} WinAPI cung cấp các chức năng cần thiết để quản lý tệp, tiến trình, bộ nhớ, giao tiếp mạng và nhiều hơn nữa. 57 | \end{itemize} 58 | 59 | \end{frame} 60 | 61 | \begin{frame} 62 | \begin{table}[h] 63 | \centering 64 | \begin{tabular}{|>{\raggedright}m{3cm}|>{\raggedright\arraybackslash}m{4.5cm}|>{\raggedright\arraybackslash}m{4.5cm}|} 65 | \hline 66 | \textbf{Tính năng} & \textbf{Windows (WinAPI)} & \textbf{Unix/Linux} \\ \hline 67 | \textbf{Quản lý tệp} & \texttt{CreateFile}, \texttt{ReadFile}, \texttt{WriteFile}, \texttt{CloseHandle} & \texttt{open}, \texttt{read}, \texttt{write}, \texttt{close} \\ \hline 68 | \textbf{Quản lý tiến trình} & \texttt{CreateProcess}, \texttt{WaitForSingleObject}, \texttt{TerminateProcess} & \texttt{fork}, \texttt{exec}, \texttt{wait}, \texttt{kill} \\ \hline 69 | \textbf{Quản lý bộ nhớ} & \texttt{VirtualAlloc}, \texttt{VirtualFree} & \texttt{mmap}, \texttt{munmap}, \texttt{brk} \\ \hline 70 | \textbf{Giao tiếp mạng} & Winsock: \texttt{socket}, \texttt{bind}, \texttt{listen}, \texttt{accept}, \texttt{connect} & BSD Sockets: \texttt{socket}, \texttt{bind}, \texttt{listen}, \texttt{accept}, \texttt{connect} \\ \hline 71 | \textbf{Tính mở rộng} & Nhiều tùy chọn và tham số & Thường đơn giản, ít tùy chọn hơn \\ \hline 72 | \textbf{Tài liệu hỗ trợ} & Phong phú, chi tiết & Tài liệu tốt nhưng không phong phú bằng Windows \\ \hline 73 | \end{tabular} 74 | \caption{So sánh lời gọi hệ thống giữa Windows và Unix/Linux} 75 | \end{table} 76 | \end{frame} 77 | 78 | \begin{frame} 79 | \begin{itemize} 80 | \item Để biên dịch các chương trình sử dụng Windows API, bạn cần đảm bảo rằng trình biên dịch của bạn được cấu hình đúng để liên kết với các thư viện cần thiết. 81 | \item Để sử dụng các hàm Windows API, bạn cần bao gồm tệp tiêu đề \texttt{} trong mã nguồn C++ của bạn. Đây là tệp tiêu đề chính chứa các khai báo cho hầu hết các hàm Windows API. 82 | \end{itemize} 83 | \end{frame} 84 | 85 | \subsection{Shell} 86 | 87 | \begin{frame}{Shell trong Windows} 88 | Shell trong Windows là một giao diện cho phép người dùng tương tác với hệ điều hành và quản lý tài nguyên máy tính. 89 | \vspace{5 pt} 90 | Các loại Shell trong Windows: 91 | \begin{itemize} 92 | \item \cyan{Windows Shell (Graphical Shell):} giao diện đồ họa người dùng (GUI) chính. 93 | \item \orange{Command Prompt (CMD):} giao diện dòng lệnh (CLI) truyền thống. 94 | \item \orange{PowerShell:} công cụ dòng lệnh mạnh mẽ và một ngôn ngữ script được thiết kế cho quản trị hệ thống và tự động hóa trên Windows. 95 | \end{itemize} 96 | \end{frame} 97 | 98 | \begin{frame} 99 | \begin{table}[h] 100 | \centering 101 | \begin{tabular}{|>{\raggedright}m{2cm}|>{\raggedright\arraybackslash}m{3cm}|>{\raggedright\arraybackslash}m{3.5cm}|} 102 | \hline 103 | \textbf{Tính năng} & \textbf{CMD} & \textbf{PowerShell} \\ \hline 104 | \textbf{Ngôn ngữ} & Dòng lệnh cơ bản & Ngôn ngữ script mạnh mẽ dựa trên .NET \\ \hline 105 | \textbf{Cmdlets} & Không có & Hàng ngàn cmdlets mạnh mẽ \\ \hline 106 | \textbf{Pipeline} & Hạn chế & Mạnh mẽ và linh hoạt \\ \hline 107 | \textbf{Scripting} & Hỗ trợ các script \texttt{.bat} đơn giản & Hỗ trợ script mạnh mẽ với \texttt{.ps1} \\ \hline 108 | \textbf{Tích hợp .NET} & Không có & Tích hợp sâu với .NET \\ \hline 109 | \textbf{Khả năng tự động hóa} & Hạn chế & Mạnh mẽ và linh hoạt \\ \hline 110 | \end{tabular} 111 | \caption{So sánh giữa CMD và PowerShell} 112 | \end{table} 113 | \end{frame} 114 | 115 | \section{Tiny Shell} 116 | 117 | \subsection{Cài đặt và triển khai} 118 | \begin{frame}{Môi trường phát triển} 119 | \begin{itemize} 120 | \item \cyan{Ngôn ngữ lập trình:} C++ 17 hoặc lớn hơn 121 | \item \cyan{Trình biên dịch:} g++ (Rev3, Built by MSYS2 project) 13.2.0 122 | \item \cyan{Phần mềm:} IDE Visual Studio Code V1.90.0 hoặc phiên bản mới nhất 123 | \item \cyan{Hệ điều hành:} Windows 10 trở lên, tốt nhất nếu Windows 11 124 | \end{itemize} 125 | \end{frame} 126 | 127 | \begin{frame}{Cấu trúc mã nguồn} 128 | \cyan{Tổ chức mã nguồn}\footnote{\orange{Mã nguồn dự án:} \href{https://github.com/HaiAu2501/Operating-System-Project}{Operating System Project}. \orange{Hướng dẫn sử dụng:} \href{https://github.com/HaiAu2501/Operating-System-Project/blob/main/README.md}{README}}: Dễ đọc, dễ quản lý, dễ sử dụng kèm hướng dẫn chi tiết. 129 | \begin{figure}[h] 130 | \centering 131 | \includegraphics[width=0.65\textwidth]{images/03.png} 132 | \end{figure} 133 | \end{frame} 134 | 135 | \begin{frame} 136 | \begin{enumerate} 137 | \item Sau khi biên dịch tệp \t{main.cpp} và chạy chương trình \t{main.exe} thành công, bạn có thể chính thức sử dụng Tiny Shell. 138 | \end{enumerate} 139 | \begin{figure}[h] 140 | \centering 141 | \includegraphics[width=0.9\textwidth]{images/01.png} 142 | \caption{Màn hình hiện lên sau khi khởi chạy Tiny Shell} 143 | \end{figure} 144 | \end{frame} 145 | 146 | \begin{frame} 147 | \begin{enumerate} 148 | \setcounter{enumi}{1} 149 | \item Hãy bắt đầu với lệnh \t{help} để xem \orange{danh sách các lệnh} mà Tiny Shell hỗ trợ.\\ 150 | $\to$ Nếu không rõ cú pháp lệnh, hay gõ (sai) lệnh và Tiny Shell sẽ thông báo.\\ 151 | \vspace{10 pt} 152 | \orange{Ví dụ:}\\ 153 | \begin{figure} 154 | \centering 155 | \includegraphics{images/04.png} 156 | \caption{Nếu nhập sai cú pháp lệnh, Tiny Shell sẽ nhắc nhở cú pháp đúng} 157 | \end{figure} 158 | \end{enumerate} 159 | \end{frame} 160 | 161 | \begin{frame} 162 | \begin{enumerate} 163 | \setcounter{enumi}{2} 164 | \item Tiny Shell hỗ trợ \cyan{70 lệnh cơ bản} và tổng cộng \cyan{90 cú pháp lệnh}. Trong đó: 165 | \begin{itemize} 166 | \item Quản lý tệp và thư mục: 15 lệnh. 167 | \item Quản lý tiến trình: 11 lệnh. 168 | \item Hệ thống và tiện ích: 17 lệnh. 169 | \item Điều hướng và giao diện: 10 lệnh. 170 | \item Tính toán nâng cao: 18 lệnh. 171 | \end{itemize} 172 | \item Lấy cảm hứng từ CMD và PowerShell của hệ điều hành Windows.\\ 173 | $\to$ Tiny Shell còn có những \orange{tính năng riêng đặc biệt}, cung cấp nhiều tiện ích để người dùng dễ dàng giao tiếp với máy tính. 174 | \end{enumerate} 175 | \end{frame} 176 | 177 | \subsection{Các tính năng cơ bản} 178 | 179 | \begin{frame}{Quản lý tệp} 180 | Tiny Shell có thể thực hiện một số thao tác với tệp: 181 | \begin{table} 182 | \centering 183 | \begin{tabular}{l|l} 184 | \cyan{Tính năng thiết yếu} & \cyan{Tính năng nâng cao} \\ 185 | \hline 186 | \t{open} & \t{check\_file} \\ 187 | \t{move\_file} & \t{file\_size} \\ 188 | \t{rename\_file} & \red{read\_file}: hỗ trợ đọc theo dòng \\ 189 | \t{delete\_file} & \red{write\_file}: hỗ trợ ghi theo dòng \\ 190 | \t{create\_file} & \red{extension\_file}: xem phần mở rộng\\ 191 | \t{copy\_file} & \red{list\_file}: liệt kê file với phần mở rộng \\ 192 | \end{tabular} 193 | \caption{Một số câu lệnh đối với tệp} 194 | \label{tab:my_label} 195 | \end{table} 196 | \end{frame} 197 | 198 | \begin{frame} 199 | \begin{figure} 200 | \centering 201 | \includegraphics[width=0.4\textwidth]{images/05.png} 202 | \caption{Chạy các câu lệnh với kịch bản kiểm thử về file} 203 | \label{fig:enter-label} 204 | \end{figure} 205 | \end{frame} 206 | 207 | \begin{frame}{Quản lý thư mục} 208 | Tiny Shell có thể thực hiện một số thao tác với thư mục: 209 | \begin{itemize} 210 | \item \t{create} 211 | \item \t{open} 212 | \item \t{delete} 213 | \item \t{copy} 214 | \item \t{rename} 215 | \item \t{move} 216 | \item \t{cd} 217 | \item \t{dir} 218 | \item \t{pwd} 219 | \item \t{list\_tree} 220 | \end{itemize} 221 | \end{frame} 222 | 223 | \begin{frame} 224 | \begin{figure} 225 | \centering 226 | \includegraphics[width=0.75\textwidth]{images/07.png} 227 | \caption{Chạy các câu lệnh với kịch bản kiểm thử về thư mục} 228 | \label{fig:enter-label} 229 | \end{figure} 230 | \end{frame} 231 | 232 | \begin{frame}{Quản lý tiến trình} 233 | Tiny Shell chứa các câu lệnh quản lí tiến trình: 234 | \begin{table}[h] 235 | \centering 236 | \begin{tabular}{l|l} 237 | \textbf{Lệnh} & \textbf{Mô tả lệnh} \\ 238 | \hline 239 | \t{list\_processes} & In ra danh sách tiến trình \\ 240 | \red{start\_foreground} & Tạo tiến trình con ở trạng thái foreground \\ 241 | \red{start\_background} & Tạo tiến trình con ở trạng thái background \\ 242 | \red{terminate} & Chấm dứt một tiến trình \\ 243 | \red{suspend} & Tạm dừng một tiến trình \\ 244 | \red{resume} & Tiếp tục một tiến trình \\ 245 | \end{tabular} 246 | \caption{Một số câu lệnh đối với tiến trình} 247 | \label{tab:process_management} 248 | \end{table} 249 | \end{frame} 250 | 251 | \begin{frame} 252 | \begin{figure} 253 | \centering 254 | \includegraphics[width=0.9\textwidth]{images/21.png} 255 | \caption{Câu lệnh liệt kê tiến trình} 256 | \label{fig:enter-label} 257 | \end{figure} 258 | \end{frame} 259 | 260 | \begin{frame} 261 | \begin{table}[h] 262 | \centering 263 | \begin{tabular}{l|l} 264 | \textbf{Lệnh nâng cao} & \textbf{Mô tả lệnh} \\ 265 | \hline 266 | \t{list\_children} & In ra danh sách tiến trình con \\ 267 | \t{manage\_threads} & Quản lý luồng \\ 268 | \t{child} & Tạo một tiến trình con đơn giản (background) \\ 269 | \t{countdown} & Tạo một cửa sổ đếm ngược 10 giây (background) \\ 270 | \t{duck} & Tạo một chú vịt bơi trên màn hình (foreground)\\ 271 | \t{tictactoe} & Khởi động trò chơi Tic-Tac-Toe trên màn hình (foreground) \\ 272 | \t{dancing} & Hiển thị một khuôn mặt nhảy múa trên màn hình (foreground) \\ 273 | \red{after} & Lên lịch chạy câu lệnh sau một khoảng thời gian \\ 274 | \end{tabular} 275 | \caption{Một số câu lệnh nâng cao đối với tiến trình} 276 | \label{tab:process_management} 277 | \end{table} 278 | Trong đó: 279 | \begin{itemize} 280 | \item Nếu đang có tiến trình con chạy foreground và người dùng ấn tổ hợp phím \orange{Ctrl + C} thì tiến trình con sẽ dừng và trở về Shell chính. 281 | \item Nếu Shell đang chạy và người dùng ấn tổ hợp phím \orange{Ctrl + C} thì không khiến Shell dừng, thay vào đó, nó bỏ qua dòng hiện tại tạo ra dòng mới \t{tiny\_shell>}. 282 | \end{itemize} 283 | \end{frame} 284 | 285 | \begin{frame} 286 | \begin{figure} 287 | \centering 288 | \includegraphics[width=0.6\textwidth]{images/22.png} 289 | \caption{Chạy Tic-Tac-Toe (foreground), có thể ấn Ctrl + C để thoát và quay lại Tiny Shell} 290 | \label{fig:enter-label} 291 | \end{figure} 292 | \end{frame} 293 | 294 | \begin{frame}{Quản lý biến môi trường} 295 | Tiny Shell chứa các câu lệnh quản lý đường dẫn và biến môi trường: 296 | \begin{table}[h] 297 | \centering 298 | \begin{tabular}{l|l} 299 | \textbf{Lệnh} & \textbf{Mô tả lệnh} \\ 300 | \hline 301 | \t{add\_path} & Thêm một đường dẫn vào PATH \\ 302 | \t{is\_in\_path} & Kiểm tra xem một đường dẫn có nằm trong PATH hay không \\ 303 | \t{remove\_path} & Xóa một đường dẫn khỏi PATH \\ 304 | \red{set\_env} & Thiết lập một biến môi trường \\ 305 | \red{unset\_env} & Hủy bỏ một biến môi trường \\ 306 | \red{print\_env} & In giá trị của một biến môi trường cụ thể \\ 307 | \t{list\_env} & Liệt kê tất cả các biến môi trường \\ 308 | \t{save\_env} & Lưu các biến môi trường vào một tệp \\ 309 | \t{load\_env} & Tải các biến môi trường từ một tệp \\ 310 | \end{tabular} 311 | \caption{Một số câu lệnh đối với đường dẫn và biến môi trường} 312 | \label{tab:path_env_management} 313 | \end{table} 314 | \end{frame} 315 | 316 | \begin{frame} 317 | \begin{figure} 318 | \centering 319 | \includegraphics[width=0.4\textwidth]{images/09.png} 320 | \caption{Chạy các câu lệnh với kịch bản kiểm thử về đường dẫn và biến môi trường} 321 | \label{fig:enter-label} 322 | \end{figure} 323 | \end{frame} 324 | 325 | \subsection{Các tính năng nâng cao} 326 | 327 | \begin{frame}{Tiện ích hệ thống} 328 | Tiny Shell có thể hiểu một số lệnh về tiện ích hệ thống: 329 | \begin{table}[h] 330 | \centering 331 | \begin{tabular}{l|l} 332 | \textbf{Lệnh thiết yếu} & \textbf{Mô tả lệnh} \\ 333 | \hline 334 | \t{time} & Hiển thị thời gian hiện tại \\ 335 | \t{date} & Hiển thị ngày hiện tại \\ 336 | \t{uptime} & Hiển thị thời gian hệ thống đã hoạt động \\ 337 | \t{cpuinfo} & Hiển thị thông tin về CPU \\ 338 | \t{meminfo} & Hiển thị thông tin về bộ nhớ \\ 339 | \t{diskinfo} & Hiển thị thông tin về đĩa cứng \\ 340 | \t{calculator} & Mở máy tính \\ 341 | \end{tabular} 342 | \caption{Một số câu lệnh đối với tiện ích hệ thống} 343 | \label{tab:system_utilities} 344 | \end{table} 345 | \end{frame} 346 | 347 | \begin{frame} 348 | \begin{figure} 349 | \centering 350 | \includegraphics[width=0.6\textwidth]{images/08.png} 351 | \caption{Chạy các câu lệnh với kịch bản kiểm thử với các tiện ích hệ thống} 352 | \label{fig:enter-label} 353 | \end{figure} 354 | \end{frame} 355 | 356 | \begin{frame} 357 | \begin{table}[h] 358 | \centering 359 | \begin{tabular}{l|l} 360 | \textbf{Lệnh nâng cao} & \textbf{Mô tả lệnh} \\ 361 | \hline 362 | \red{exit} & Thoát khỏi shell \\ 363 | \red{help} & Hiển thị trợ giúp về các lệnh có sẵn \\ 364 | \red{history} & Hiển thị lịch sử các lệnh đã nhập \\ 365 | \red{clear} & Xóa màn hình hiển thị của shell \\ 366 | \red{clear\_history} & Xóa lịch sử các lệnh đã nhập \\ 367 | \red{change\_color} & Đổi màu chữ của shell 368 | \end{tabular} 369 | \caption{Một số câu lệnh nâng cao đối với tiện ích hệ thống} 370 | \label{tab:system_utilities} 371 | \end{table} 372 | \end{frame} 373 | 374 | \begin{frame} 375 | \begin{figure} 376 | \centering 377 | \includegraphics[width=0.6\textwidth]{images/13.png} 378 | \caption{Chạy một số câu lệnh nâng cao kiểm thử các tiện ích hệ thống} 379 | \label{fig:enter-label} 380 | \end{figure} 381 | \end{frame} 382 | 383 | \begin{frame}{Thực thi kịch bản} 384 | \begin{itemize} 385 | \item Thư mục Testcase\footnote{\orange{Mã nguồn dự án:} \href{https://github.com/HaiAu2501/Operating-System-Project/tree/main/Testcase}{Kịch bản kiểm thử}} chứa các kịch bản kiểm thử. Mỗi kịch bản là dãy lệnh của Tiny Shell được lưu thành một file \t{.bat}. 386 | \item Tiny Shell có thể thực hiện các câu lệnh được viết trong file \t{.bat}. 387 | \end{itemize} 388 | \begin{figure} 389 | \centering 390 | \includegraphics[width=\textwidth]{images/06.png} 391 | \caption{Minh họa một kịch bản kiểm tra dãy lệnh với thư mục} 392 | \label{fig:enter-label} 393 | \end{figure} 394 | \end{frame} 395 | 396 | \begin{frame}{Tính toán nâng cao} 397 | Tiny Shell có thể hiểu một số lệnh về tính toán và điều kiện. 398 | \begin{table}[h] 399 | \centering 400 | \begin{tabular}{l|l} 401 | \textbf{Lệnh} & \textbf{Mô tả lệnh} \\ 402 | \hline 403 | \red{calculate} & Tính giá trị một biểu thức \\ 404 | \red{function} & Định nghĩa một hàm \\ 405 | \red{evaluate} & Tính giá trị của một hàm tại giá trị cụ thể \\ 406 | \t{convert} & Chuyển đổi hệ cơ số \\ 407 | \end{tabular} 408 | \caption{Một số lệnh đối với tính toán và điều kiện} 409 | \label{tab:calculation_condition} 410 | \end{table} 411 | \begin{itemize} 412 | \item Biểu thức nhập vào dưới dạng trung tố (infix), sau đó sử dụng \cyan{thuật toán Shunting Yard} chuyển biểu thức trung tố sang biểu thức hậu tố (postfix) để tính toán giá trị. 413 | \item Một số câu lệnh vòng lặp và điều kiện không thể hoàn thiện như ngôn ngữ lập trình. 414 | \end{itemize} 415 | \end{frame} 416 | 417 | \begin{frame} 418 | \begin{figure} 419 | \centering 420 | \includegraphics[width=0.5\textwidth]{images/10.png} 421 | \caption{Chạy các câu lệnh kiểm thử chức năng tính toán} 422 | \label{fig:enter-label} 423 | \end{figure} 424 | \end{frame} 425 | 426 | \subsection{Các tiện ích mở rộng} 427 | 428 | \begin{frame}{Các tiện ích mở rộng} 429 | Shell có thể thực hiện một số tiện ích khác như: 430 | \begin{table}[h] 431 | \centering 432 | \begin{tabular}{l|l} 433 | \textbf{Lệnh} & \textbf{Mô tả lệnh} \\ 434 | \hline 435 | \t{alias} & Định nghĩa viết tắt của câu lệnh \\ 436 | \t{unalias} & Hủy định nghĩa viết tắt của câu lệnh \\ 437 | \t{bookmark} & Định nghĩa tên gọi tắt cho đường dẫn \\ 438 | \red{loop} & Thực hiện một lệnh lặp với số vòng cụ thể \\ 439 | \red{if else} & Thực hiện biểu thức điều kiện \\ 440 | \end{tabular} 441 | \caption{Một số lệnh đối với tiện ích mở rộng} 442 | \label{tab:additional_commands} 443 | \end{table} 444 | \end{frame} 445 | 446 | \begin{frame} 447 | \begin{figure} 448 | \centering 449 | \includegraphics[width=0.55\textwidth]{images/11.png} 450 | \caption{Chạy các câu lệnh kiểm thử các tiện ích mở rộng} 451 | \label{fig:enter-label} 452 | \end{figure} 453 | \end{frame} 454 | 455 | \section{Kết luận \& Thảo luận} 456 | 457 | \subsection{Tính ứng dụng} 458 | 459 | \begin{frame}{Ứng dụng trong học tập} 460 | Sản phẩm \orange{Tiny Shell}, mô phỏng giao diện dòng lệnh shell để người dùng tương tác với hệ điều hành, có nhiều tính ứng dụng quan trọng và giá trị trong học tập: 461 | \vspace{5 pt} 462 | \begin{itemize} 463 | \item Hiểu sâu hơn về cách hệ điều hành quản lý và thực thi các lệnh từ người dùng, cách xử lý các tiến trình và cách giao tiếp với phần cứng. 464 | \item Xây dựng một shell yêu cầu hiểu biết về lập trình hệ thống, bao gồm quản lý bộ nhớ, quản lý tiến trình và xử lý tín hiệu $\to$ \cyan{củng cố kiến thức lập trình C/C++ và hệ điều hành}. 465 | \item Nâng cao \orange{kỹ năng thiết kế phần mềm} và quản lý dự án: xác định yêu cầu, quá trình triển khai và kiểm thử sản phẩm. 466 | \end{itemize} 467 | \end{frame} 468 | 469 | \begin{frame}{Ý nghĩa với cá nhân} 470 | \begin{itemize} 471 | \item Nắm vững \orange{khái niệm cơ bản về hệ điều hành}: tệp, thư mục, tiến trình, chương trình,... 472 | \item Hiểu sâu hơn về Windows API, các thư viện Windows và các lời gọi hệ thống. 473 | \item Học cách \cyan{ghi nhận chi tiết các lỗi} xảy ra trong quá trình phát triển, từ đó phân tích và khắc phục một cách hệ thống.\\ 474 | $\to$ Thông qua việc viết Bug Record (\t{bug.txt}), lên kế hoạch kiểm thử và sửa lỗi.\\ 475 | $\to$ Học cách tổ chức mã nguồn theo thư mục hợp lý, giúp mã nguồn dễ đọc, dễ bảo trì. 476 | \end{itemize} 477 | \end{frame} 478 | 479 | \begin{frame} 480 | \begin{figure} 481 | \centering 482 | \includegraphics[width=0.8\textwidth]{images/12.png} 483 | \caption{Bản ghi lỗi\footnote{\orange{Mã nguồn dự án:} \href{https://github.com/HaiAu2501/Operating-System-Project/blob/main/bug.txt}{Bản ghi lỗi}} và cách khắc phục lỗi} 484 | \label{fig:enter-label} 485 | \end{figure} 486 | \begin{itemize} 487 | \item Áp dụng các nguyên lý \cyan{lập trình hướng đối tượng} trong việc thiết kế và triển khai các tính năng trong Tiny Shell. 488 | \item Làm việc nhóm hiệu quả, chia sẻ kiến thức và phân công công việc một cách hợp lý. 489 | \end{itemize} 490 | \end{frame} 491 | 492 | \subsection{Khó khăn và giải pháp} 493 | \begin{frame}{Khó khăn} 494 | \begin{itemize} 495 | \item Việc xây dựng bộ phân tích cú pháp để hiểu và xử lý đúng các lệnh từ người dùng gặp nhiều thách thức.\\ 496 | $\to$ Đảm bảo rằng các lệnh sai cú pháp được phát hiện và thông báo lỗi một cách rõ ràng cho người dùng.\\ 497 | $\to$ Xử lý các đường dẫn tệp, bao gồm đường dẫn tương đối và tuyệt đối.\\ 498 | $\to$ Quản lý các tín hiệu hệ thống như SIGINT (Ctrl + C). 499 | \item Khó khăn khi xử lý các lệnh có cú pháp phức tạp như lệnh điều kiện, vòng lặp, và các biểu thức toán học. 500 | \item Đối mặt với các lỗi phát sinh, thiếu nhất quán trong tổ chức mã nguồn. 501 | \end{itemize} 502 | \end{frame} 503 | 504 | \begin{frame}{Giải pháp} 505 | \begin{itemize} 506 | \item Thực hiện tối ưu hóa mã nguồn để Tiny Shell hoạt động hiệu quả, không tiêu tốn quá nhiều tài nguyên hệ thống. 507 | \item Liên tục kiểm thử, tối ưu hóa và sửa lỗi, phát triển các kịch bản kiểm thử với độ khó cao. 508 | \item Thử thách trước cú pháp và tính năng phức tạp. 509 | \end{itemize} 510 | \end{frame} 511 | 512 | \begin{frame} 513 | \begin{columns} 514 | \begin{column}{0.45\textwidth} 515 | \centering 516 | \Large \orange{Cảm ơn thầy và các bạn đã lắng nghe!} 517 | \end{column} 518 | \begin{column}{1 pt} 519 | \centering 520 | \textcolor{cyan}{\rule{1pt}{200pt}} 521 | \end{column} 522 | \begin{column}{0.45\textwidth} 523 | \begin{itemize} 524 | \item \cyan{Email:} tuankiet.nv2501@gmail.com 525 | \item \cyan{GitHub:} \href{https://github.com/HaiAu2501}{HaiAu2501} 526 | \item \cyan{Phone:} +84978 621 832 527 | \end{itemize} 528 | \end{column} 529 | \end{columns} 530 | 531 | \end{frame} 532 | 533 | \end{document} 534 | --------------------------------------------------------------------------------