├── LICENSE ├── README.md ├── bin ├── cat ├── cd ├── echo ├── false ├── head ├── nproc ├── printenv ├── pwd ├── sleep ├── tac ├── tail ├── time ├── touch ├── true ├── wc └── yes ├── compile └── src ├── cat.c ├── cd.c ├── echo.c ├── false.c ├── head.c ├── nproc.c ├── printenv.c ├── pwd.c ├── sleep.c ├── tac.c ├── tail.c ├── time.c ├── touch.c ├── true.c ├── wc.c └── yes.c /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 X3ric 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ### **CoreUtils** 4 | 5 | This repository contains basic utility programs implemented in C, inspired by GNU coreutils. 6 | 7 | #### Repository Overview 8 | 9 | **src**: Contains the source code files for utility programs. 10 | 11 | **compile**: Compilation script. 12 | 13 | #### Usage 14 | 15 | **Clone the Repository:** 16 |
17 | git clone https://github.com/x3ric/coreutils
18 | 
19 | 20 | **Compile the Utilities:** 21 | Use the provided `compile` script to compile the utilities. 22 |
23 | ./compile
24 | 
25 | 26 | **Run the Utilities:** 27 | 28 | After compilation, execute the desired utility in the created folder `./bin/`. 29 | 30 |
31 | cat
32 | tac
33 | head
34 | tail
35 | cd
36 | echo
37 | touch
38 | false
39 | pwd
40 | sleep
41 | true
42 | nproc
43 | time
44 | wc
45 | yes
46 | 
47 | 48 | **Compile and Run Shortcut:** 49 | 50 | Execute the following command in the root of the repository to compile and run a utility. 51 | 52 |
53 | ./compile <utility>
54 | 
55 | 56 |
57 |

Arch Linux
58 | -------------------------------------------------------------------------------- /bin/cat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/cat -------------------------------------------------------------------------------- /bin/cd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/cd -------------------------------------------------------------------------------- /bin/echo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/echo -------------------------------------------------------------------------------- /bin/false: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/false -------------------------------------------------------------------------------- /bin/head: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/head -------------------------------------------------------------------------------- /bin/nproc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/nproc -------------------------------------------------------------------------------- /bin/printenv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/printenv -------------------------------------------------------------------------------- /bin/pwd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/pwd -------------------------------------------------------------------------------- /bin/sleep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/sleep -------------------------------------------------------------------------------- /bin/tac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/tac -------------------------------------------------------------------------------- /bin/tail: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/tail -------------------------------------------------------------------------------- /bin/time: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/time -------------------------------------------------------------------------------- /bin/touch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/touch -------------------------------------------------------------------------------- /bin/true: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/true -------------------------------------------------------------------------------- /bin/wc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/wc -------------------------------------------------------------------------------- /bin/yes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x3ric/coreutils/82660d8189a7cb1de6e5ae48f2e653217306ccbe/bin/yes -------------------------------------------------------------------------------- /compile: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [[ ! -d ./bin ]]; then mkdir ./bin; fi 3 | for file in ./src/*.c; do 4 | filename=$(basename -- "$file") 5 | filename_no_ext="./bin/${filename%.*}" 6 | gcc "$file" -o "$filename_no_ext" 7 | chmod +x "$filename_no_ext" 8 | done 9 | if [[ ! -z $1 ]]; then 10 | ./bin/"$1" "${@:2}" 11 | fi 12 | -------------------------------------------------------------------------------- /src/cat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | if (argc == 1) { 7 | return 0; 8 | } 9 | if (argc > 1 && (strcmp(argv[1], "--help") == 0)) { 10 | printf("Concatenate Files\nUsage: cat [FILE]...\n"); 11 | return 0; 12 | } else { 13 | for (int i = 1; i < argc; i++) { 14 | FILE *file = fopen(argv[i], "r"); 15 | if (file == NULL) { 16 | perror(argv[i]); 17 | continue; 18 | } 19 | int c; 20 | while ((c = fgetc(file)) != EOF) { 21 | putchar(c); 22 | } 23 | putchar('\n'); 24 | fclose(file); 25 | } 26 | } 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /src/cd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | if (argc == 1) { 8 | chdir(getenv("HOME")); 9 | } else { 10 | chdir(argv[2]); 11 | } 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /src/echo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void escape(char *str); 6 | 7 | int main(int argc, char *argv[]) { 8 | if (argc > 1 && (strcmp(argv[1], "--help") == 0)) { 9 | printf("Echo\nUsage: echo [ARG] [TEXT]\n" 10 | "args:\n" 11 | " -e enable interpretation of backslash escapes\n" 12 | " '\\a' alert (bell)\n" 13 | " '\\b' backspace\n" 14 | " '\\c' produce no further output\n" 15 | " '\\e' escape\n" 16 | " '\\f' form feed\n" 17 | " '\\n' newline\n" 18 | " '\\r' carriage return\n" 19 | " '\\t' horizontal tab\n" 20 | " '\\v' vertical tab\n" 21 | " '\\\\' backslash\n" 22 | " '\\0NNN' octal number NNN (zero to three digits), ninth bit ignored\n" 23 | " '\\NNN' octal number NNN (one to three digits), ninth bit ignored\n" 24 | " '\\xHH' hexadecimal number HH (one or two digits)\n"); 25 | return 0; 26 | } else { 27 | int shift = 0; 28 | if (argc > 1 && strcmp(argv[1], "-e") == 0) { 29 | shift++; 30 | } 31 | for (int i = shift + 1; i < argc; i++) { 32 | if(shift == 0) { 33 | if (i == argc - 1) { 34 | printf("%s\n", argv[i]); 35 | } else { 36 | printf("%s ", argv[i]); 37 | } 38 | } else { 39 | if (i == argc - 1) { 40 | escape(argv[i]); 41 | putchar('\n'); 42 | } else { 43 | escape(argv[i]); 44 | putchar(' '); 45 | } 46 | } 47 | } 48 | } 49 | return 0; 50 | } 51 | 52 | void escape(char *str) { 53 | char *p = str; 54 | while (*p != '\0') { 55 | if (*p == '\\') { 56 | switch (*(++p)) { 57 | case 'a': 58 | putchar('\a'); 59 | break; 60 | case 'b': 61 | putchar('\b'); 62 | break; 63 | case 'c': 64 | return; 65 | case 'e': 66 | putchar('\x1B'); 67 | break; 68 | case 'f': 69 | putchar('\f'); 70 | break; 71 | case 'n': 72 | putchar('\n'); 73 | break; 74 | case 'r': 75 | putchar('\r'); 76 | break; 77 | case 't': 78 | putchar('\t'); 79 | break; 80 | case 'v': 81 | putchar('\v'); 82 | break; 83 | case '\\': 84 | putchar('\\'); 85 | break; 86 | case '0': 87 | case '1': 88 | case '2': 89 | case '3': 90 | case '4': 91 | case '5': 92 | case '6': 93 | case '7': { 94 | char *endptr; 95 | int value = strtol(p, &endptr, 8); 96 | putchar(value); 97 | p = endptr - 1; 98 | break; 99 | } 100 | case 'x': { 101 | char *endptr; 102 | int value = strtol(++p, &endptr, 16); 103 | putchar(value); 104 | p = endptr - 1; 105 | break; 106 | } 107 | default: 108 | putchar(*p); 109 | } 110 | } else { 111 | putchar(*p); 112 | } 113 | p++; 114 | } 115 | } -------------------------------------------------------------------------------- /src/false.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 1; 3 | } 4 | -------------------------------------------------------------------------------- /src/head.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | if (argc > 1 && (strcmp(argv[1], "--help") == 0)) { 8 | printf("Output First Part Of Files\nUsage: head [OPTIONS] [FILE]...\n" 9 | "Options:\n" 10 | " -h, --help Display this help and exit\n" 11 | " -n, --lines NUM Output the first NUM lines\n" 12 | " -c, --bytes NUM Output the first NUM bytes\n" 13 | " -q, --quiet, --silent Never print headers giving file names\n" 14 | " -v, --verbose Always print headers giving file names\n" 15 | " -z, --zero-terminated Line delimiter is NUL, not newline\n"); 16 | return 0; 17 | } else { 18 | FILE *file; 19 | 20 | int nfiles = argc; 21 | int nbytes = 0; 22 | int mlines = 10; 23 | int mbytes = 0; 24 | bool skip = false; 25 | bool bytes = false; 26 | bool quiet = false; 27 | bool verbose = false; 28 | bool zterminated = false; 29 | 30 | for (int i = 1; i < argc; i++) { 31 | if (i == 1) { 32 | nbytes = 0; 33 | } 34 | 35 | if (skip) { 36 | nfiles--; 37 | skip = false; 38 | if (bytes) { 39 | mbytes = atoi(argv[i]); 40 | } else { 41 | mlines = atoi(argv[i]); 42 | } 43 | continue; 44 | } 45 | 46 | if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--lines") == 0) { 47 | nfiles--; 48 | skip = true; 49 | bytes = false; 50 | continue; 51 | } 52 | 53 | if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--bytes") == 0) { 54 | nfiles--; 55 | skip = true; 56 | bytes = true; 57 | continue; 58 | } 59 | 60 | if (strcmp(argv[i], "-z") == 0 || strcmp(argv[i], "--zero-terminated") == 0) { 61 | zterminated = true; 62 | continue; 63 | } 64 | 65 | if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0 || strcmp(argv[i], "--silent") == 0) { 66 | quiet = true; 67 | continue; 68 | } 69 | 70 | if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) { 71 | verbose = true; 72 | continue; 73 | } 74 | 75 | file = fopen(argv[i], "r"); 76 | if (file == NULL) { 77 | perror(argv[i]); 78 | continue; 79 | } 80 | 81 | if ( ((!quiet || verbose) && (nfiles > 2)) ) { 82 | if ( zterminated ) { 83 | printf("==> %s <==\0", argv[i]); 84 | } else { 85 | printf("==> %s <==\n", argv[i]); 86 | } 87 | } 88 | 89 | int c; 90 | int cline = 0; 91 | while (cline < mlines && (c = fgetc(file)) != EOF) { 92 | if (nbytes == mbytes && mbytes != 0) { 93 | if ( zterminated ) { 94 | putchar('\0'); 95 | } else { 96 | putchar('\n'); 97 | } 98 | break; 99 | } 100 | nbytes++; 101 | if (c == '\n' || c == '\r' || (zterminated && c == '\0')) cline++; 102 | putchar(c); 103 | } 104 | 105 | fclose(file); 106 | } 107 | } 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /src/nproc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | int opt; 8 | int ignore = 0; 9 | int nproc = 0; 10 | 11 | struct option long_options[] = { 12 | {"all", no_argument, NULL, 'a'}, 13 | {"ignore", required_argument, NULL, 'i'}, 14 | {"help", no_argument, NULL, 'h'}, 15 | {NULL, 0, NULL, 0} 16 | }; 17 | 18 | while ((opt = getopt_long(argc, argv, "", long_options, NULL)) != -1) { 19 | switch (opt) { 20 | case 'a': 21 | goto exitnproc; 22 | break; 23 | case 'i': 24 | ignore = atoi(optarg); 25 | break; 26 | case 'h': 27 | printf("Usage: nproc [OPTION]...\n" 28 | "Print the number of processing units available to the current process,\n" 29 | "which may be less than the number of online processors\n\n" 30 | " --all print the number of installed processors\n" 31 | " --ignore=N if possible, exclude N processing units\n" 32 | " --help display this help and exit\n"); 33 | exit(EXIT_SUCCESS); 34 | default: 35 | fprintf(stderr, "Usage: %s [--all] [--ignore=N] [--help]\n", argv[0]); 36 | exit(EXIT_FAILURE); 37 | } 38 | } 39 | 40 | if (ignore > 0) { 41 | nproc = sysconf(_SC_NPROCESSORS_CONF) - ignore; 42 | if(nproc<=0){nproc=1;} 43 | printf("%ld\n", nproc); 44 | } else { 45 | exitnproc: 46 | nproc = sysconf(_SC_NPROCESSORS_ONLN); 47 | printf("%ld\n", nproc); 48 | } 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /src/printenv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | extern char **environ; 6 | 7 | void print_help(char *program_name) { 8 | printf("Usage: %s [-0 | --null] [VARIABLE]\n", program_name); 9 | printf("Print the values of specified environment variable or all environment variables.\n\n"); 10 | printf("Options:\n"); 11 | printf(" -0, --null End each output line with NUL, not newline.\n"); 12 | } 13 | 14 | int main(int argc, char *argv[]) { 15 | int use_null_terminator = 0; 16 | if (argc > 1 && (strcmp(argv[1], "-0") == 0 || strcmp(argv[1], "--null") == 0)) { 17 | use_null_terminator = 1; 18 | argc--; 19 | argv++; 20 | } 21 | if (argc > 2 || (argc == 2 && (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0))) { 22 | print_help(argv[0]); 23 | return 0; 24 | } 25 | if (argc == 2) { 26 | char *value = getenv(argv[1]); 27 | if (value == NULL) { 28 | fprintf(stderr, "%s: %s: No such environment variable\n", argv[0], argv[1]); 29 | return 1; 30 | } 31 | printf("%s", value); 32 | if (use_null_terminator) { 33 | putchar('\0'); 34 | } else { 35 | putchar('\n'); 36 | } 37 | } else { 38 | char **env = environ; 39 | while (*env != NULL) { 40 | printf("%s", *env); 41 | if (use_null_terminator) { 42 | putchar('\0'); 43 | } else { 44 | putchar('\n'); 45 | } 46 | env++; 47 | } 48 | } 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /src/pwd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | printf("%s\n", getenv("PWD")); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /src/sleep.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | if (argc > 1 && (strcmp(argv[1], "--help") == 0)) { 8 | printf("Sleep\nUsage: sleep [TIME]\ntime in seconds or milliseconds. \"int or float\"\n"); 9 | return 0; 10 | } else { 11 | if (argc <= 1) { 12 | return 1; 13 | } 14 | if (strchr(argv[1], '.') != NULL) { 15 | float time = atof(argv[1]); 16 | usleep(time * 1000000); 17 | } else { 18 | int time = atoi(argv[1]); 19 | sleep(time); 20 | } 21 | } 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /src/tac.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | if (argc == 1) { 7 | return 0; 8 | } 9 | if (argc > 1 && (strcmp(argv[1], "--help") == 0)) { 10 | printf("Concatenate Files In Reverse\nUsage: tac [FILE]...\n"); 11 | return 0; 12 | } else { 13 | FILE *file; 14 | for (int i = 1; i < argc; i++) { 15 | file = fopen(argv[i], "r"); 16 | if (file == NULL) { 17 | perror(argv[i]); 18 | continue; 19 | } 20 | int c, linec = 0; 21 | while ((c = fgetc(file)) != EOF) if (c == '\n') linec++; 22 | fseek(file, 0, SEEK_SET); 23 | char **lines = malloc(linec * sizeof(char *)); 24 | for (int i = 0; i < linec; i++) { 25 | char *line = NULL; 26 | size_t len = 0; 27 | getline(&line, &len, file); 28 | lines[i] = line; 29 | } 30 | for (int i = linec - 1; i >= 0; i--) { 31 | printf("%s", lines[i]); 32 | free(lines[i]); 33 | } 34 | free(lines); 35 | putchar('\n'); 36 | fclose(file); 37 | } 38 | } 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /src/tail.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | if (argc > 1 && (strcmp(argv[1], "--help") == 0)) { 8 | printf("Output Last Part Of Files\nUsage: tail [OPTIONS] [FILE]...\n" 9 | "Options:\n" 10 | " -h, --help Display this help and exit\n" 11 | " -n, --lines NUM Output the last NUM lines\n" 12 | " -c, --bytes NUM Output the last NUM bytes\n" 13 | " -q, --quiet, --silent Never print headers giving file names\n" 14 | " -v, --verbose Always print headers giving file names\n" 15 | " -z, --zero-terminated Line delimiter is NUL, not newline\n"); 16 | return 0; 17 | } else { 18 | FILE *file; 19 | 20 | int nfiles = argc; 21 | int nbytes = 0; 22 | int mlines = 10; 23 | int mbytes = 0; 24 | bool skip = false; 25 | bool bytes = false; 26 | bool quiet = false; 27 | bool verbose = false; 28 | bool zterminated = false; 29 | 30 | for (int i = 1; i < argc; i++) { 31 | if (i == 1) { 32 | nbytes = 0; 33 | } 34 | 35 | if (skip) { 36 | nfiles--; 37 | skip = false; 38 | if (bytes) { 39 | mbytes = atoi(argv[i]); 40 | } else { 41 | mlines = atoi(argv[i]); 42 | } 43 | continue; 44 | } 45 | 46 | if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--lines") == 0) { 47 | nfiles--; 48 | skip = true; 49 | bytes = false; 50 | continue; 51 | } 52 | 53 | if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--bytes") == 0) { 54 | nfiles--; 55 | skip = true; 56 | bytes = true; 57 | continue; 58 | } 59 | 60 | if (strcmp(argv[i], "-z") == 0 || strcmp(argv[i], "--zero-terminated") == 0) { 61 | zterminated = true; 62 | continue; 63 | } 64 | 65 | if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0 || strcmp(argv[i], "--silent") == 0) { 66 | quiet = true; 67 | continue; 68 | } 69 | 70 | if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) { 71 | verbose = true; 72 | continue; 73 | } 74 | 75 | file = fopen(argv[i], "r"); 76 | if (file == NULL) { 77 | perror(argv[i]); 78 | continue; 79 | } 80 | 81 | if ((!quiet || verbose) && (nfiles > 2)) { 82 | if (zterminated) { 83 | printf("==> %s <==\0", argv[i]); 84 | } else { 85 | printf("==> %s <==\n", argv[i]); 86 | } 87 | } 88 | 89 | int c, linec = 0; 90 | while ((c = fgetc(file)) != EOF) { 91 | if (nbytes == mbytes && mbytes != 0) { 92 | if ( zterminated ) { 93 | putchar('\0'); 94 | } else { 95 | putchar('\n'); 96 | } 97 | break; 98 | } 99 | nbytes++; 100 | if (c == '\n' || c == '\r' || (zterminated && c == '\0')) linec++; 101 | } 102 | fseek(file, 0, SEEK_SET); 103 | char **lines = malloc(linec * sizeof(char *)); 104 | for (int i = 0; i < linec; i++) { 105 | char *line = NULL; 106 | size_t len = 0; 107 | getline(&line, &len, file); 108 | lines[i] = line; 109 | } 110 | for (int i = linec - 1; i == (linec - mlines); i--) { 111 | printf("%s", lines[i]); 112 | free(lines[i]); 113 | } 114 | free(lines); 115 | fclose(file); 116 | } 117 | } 118 | return 0; 119 | } 120 | -------------------------------------------------------------------------------- /src/time.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void print_usage(double user_time, double sys_time, double cpu_percentage, double elapsed_time) { 8 | printf("shell %.2fs user %.2fs system %.0f%% cpu %.3f total\n", user_time, sys_time, cpu_percentage, elapsed_time); 9 | printf("children %.2fs user %.2fs system %.0f%% cpu %.3f total\n", user_time * 1.5, sys_time * 1.5, cpu_percentage, elapsed_time); 10 | } 11 | 12 | int main(int argc, char *argv[]) { 13 | struct timeval start_time, end_time; 14 | struct rusage start_usage, end_usage; 15 | getrusage(RUSAGE_SELF, &start_usage); 16 | gettimeofday(&start_time, NULL); 17 | if (argc < 2) { 18 | int sum = 0; 19 | for (int i = 0; i < 1000000000; ++i) { 20 | sum += i; 21 | } 22 | gettimeofday(&end_time, NULL); 23 | getrusage(RUSAGE_SELF, &end_usage); 24 | double elapsed_time = (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_usec - start_time.tv_usec) / 1000000.0; 25 | double user_time = (end_usage.ru_utime.tv_sec - start_usage.ru_utime.tv_sec) + (end_usage.ru_utime.tv_usec - start_usage.ru_utime.tv_usec) / 1000000.0; 26 | double sys_time = (end_usage.ru_stime.tv_sec - start_usage.ru_stime.tv_sec) + (end_usage.ru_stime.tv_usec - start_usage.ru_stime.tv_usec) / 1000000.0; 27 | double cpu_percentage = ((user_time + sys_time) / elapsed_time) * 100.0; 28 | print_usage(user_time, sys_time, cpu_percentage, elapsed_time); 29 | } else { 30 | if (system(argv[1]) == -1) { 31 | perror("Failed to execute command"); 32 | return 1; 33 | } 34 | gettimeofday(&end_time, NULL); 35 | getrusage(RUSAGE_SELF, &end_usage); 36 | double elapsed_time = (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_usec - start_time.tv_usec) / 1000000.0; 37 | double user_time = (end_usage.ru_utime.tv_sec - start_usage.ru_utime.tv_sec) + (end_usage.ru_utime.tv_usec - start_usage.ru_utime.tv_usec) / 1000000.0; 38 | double sys_time = (end_usage.ru_stime.tv_sec - start_usage.ru_stime.tv_sec) + (end_usage.ru_stime.tv_usec - start_usage.ru_stime.tv_usec) / 1000000.0; 39 | double cpu_percentage = ((user_time + sys_time) / elapsed_time) * 100.0; 40 | printf("%s %.2fs user %.2fs system %.0f%% cpu %.3f total\n", argv[1], user_time, sys_time, cpu_percentage, elapsed_time); 41 | } 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /src/touch.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | time_t parse_time(const char *time_str) { 11 | struct tm time_info = {0}; 12 | sscanf(time_str, "%4d%2d%2d%2d%2d%2d", 13 | &time_info.tm_year, &time_info.tm_mon, &time_info.tm_mday, 14 | &time_info.tm_hour, &time_info.tm_min, &time_info.tm_sec); 15 | time_info.tm_year -= 1900; 16 | time_info.tm_mon -= 1; 17 | return mktime(&time_info); 18 | } 19 | 20 | int main(int argc, char *argv[]) { 21 | if (argc > 1 && (strcmp(argv[1], "--help") == 0)) { 22 | printf("Set Timestamp\nUsage: touch [OPTION]... FILE...\n" 23 | "Options:\n" 24 | " -a change only the access time\n" 25 | " -c, --no-create do not create any files\n" 26 | " -h, --no-dereference affect each symbolic link instead of any referenced\n" 27 | " file (useful only on systems that can change the\n" 28 | " timestamps of a symlink)\n" 29 | " -m change only the modification time\n" 30 | " -r, --reference=FILE use this file's times instead of current time\n" 31 | " -t [[CC]YY]MMDDhhmm[.ss] use specified time instead of current time,\n" 32 | " with a date-time format that differs from -d's\n" 33 | " --time=WORD specify which time to change:\n" 34 | " access time (-a): 'access', 'atime', 'use';\n" 35 | " modification time (-m): 'modify', 'mtime'\n" 36 | " --help display this help and exit\n"); 37 | return 0; 38 | } 39 | 40 | bool update_access = false, update_modification = false, create_files = true, no_dereference = false; 41 | time_t custom_time = 0; 42 | const char *reference_file = NULL; 43 | 44 | for (int i = 1; i < argc; i++) { 45 | if (argv[i][0] == '-') { 46 | if (strcmp(argv[i], "-a") == 0) { 47 | update_access = true; 48 | } else if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--no-create") == 0) { 49 | create_files = false; 50 | } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--no-dereference") == 0) { 51 | no_dereference = true; 52 | } else if (strcmp(argv[i], "-m") == 0) { 53 | update_modification = true; 54 | } else if (strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "--reference") == 0) { 55 | if (i + 1 < argc) { 56 | reference_file = argv[++i]; 57 | } else { 58 | printf("Option '%s' requires an argument.\n", argv[i]); 59 | return 1; 60 | } 61 | } else if (strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--time") == 0) { 62 | if (i + 1 < argc) { 63 | i++; 64 | custom_time = parse_time(argv[i]); 65 | } else { 66 | printf("Option '%s' requires an argument.\n", argv[i]); 67 | return 1; 68 | } 69 | } else { 70 | printf("Unknown option '%s'.\n", argv[i]); 71 | return 1; 72 | } 73 | } 74 | } 75 | 76 | struct stat st; 77 | for (int i = 1; i < argc; i++) { 78 | if (argv[i][0] != '-') { 79 | if (strcmp(argv[i], "-") == 0) { 80 | printf("Not implemented: update timestamps of standard output.\n"); 81 | } else { 82 | if (no_dereference) { 83 | if (lstat(argv[i], &st) != 0) { 84 | perror("Error getting symbolic link information"); 85 | return 1; 86 | } 87 | } else { 88 | if (stat(argv[i], &st) != 0) { 89 | perror("Error getting file information"); 90 | return 1; 91 | } 92 | } 93 | struct utimbuf new_times; 94 | if (reference_file != NULL) { 95 | if (stat(reference_file, &st) == 0) { 96 | new_times.actime = st.st_atime; 97 | new_times.modtime = st.st_mtime; 98 | } else { 99 | perror("Error getting reference file information"); 100 | return 1; 101 | } 102 | } else if (custom_time != 0) { 103 | new_times.actime = update_access ? custom_time : st.st_atime; 104 | new_times.modtime = update_modification ? custom_time : st.st_mtime; 105 | } else { 106 | new_times.actime = update_access ? time(NULL) : st.st_atime; 107 | new_times.modtime = update_modification ? time(NULL) : st.st_mtime; 108 | } 109 | if (utime(argv[i], &new_times) != 0) { 110 | perror("Error updating timestamp"); 111 | return 1; 112 | } 113 | } 114 | } 115 | } 116 | return 0; 117 | } 118 | -------------------------------------------------------------------------------- /src/true.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 0; 3 | } 4 | -------------------------------------------------------------------------------- /src/wc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define MAX_LINE_LENGTH 1024 7 | 8 | int main(int argc, char *argv[]) { 9 | if (argc > 1 && (strcmp(argv[1], "--help") == 0)) { 10 | printf("Usage: wc [OPTION]... [FILE]...\n" 11 | " or: w [OPTION]... --files0-from=F\n" 12 | "Print newline, word, and byte counts for each FILE, and a total line if\n" 13 | "more than one FILE is specified. A word is a nonempty sequence of non white\n" 14 | "space delimited by white space characters or by start or end of input.\n\n" 15 | "With no FILE, or when FILE is -, read standard input.\n\n" 16 | "Options:\n" 17 | " -c, --bytes print the byte counts\n" 18 | " -m, --chars print the character counts\n" 19 | " -l, --lines print the newline counts\n" 20 | " --files0-from=F read input from the files specified by\n" 21 | " NUL-terminated names in file F;\n" 22 | " If F is - then read names from standard input\n" 23 | " -L, --max-line-length print the maximum display width\n" 24 | " -w, --words print the word counts\n" 25 | " --total=WHEN when to print a line with total counts;\n" 26 | " WHEN can be: auto, always, only, never\n"); 27 | return 0; 28 | } else { 29 | int print_lines = 0, print_words = 0, print_chars = 0, print_bytes = 0, print_max_line_length = 0; 30 | int print_total = 0; 31 | char *file_name = NULL; 32 | int opt; 33 | while ((opt = getopt(argc, argv, "clmLw")) != -1) { 34 | switch (opt) { 35 | case 'c': print_bytes = 1; break; 36 | case 'm': print_chars = 1; break; 37 | case 'l': print_lines = 1; break; 38 | case 'w': print_words = 1; break; 39 | case 'L': print_max_line_length = 1; break; 40 | default: 41 | fprintf(stderr, "Usage: %s [OPTION]... [FILE]...\n", argv[0]); 42 | fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); 43 | return 1; 44 | } 45 | } 46 | if (optind < argc) { 47 | file_name = argv[optind]; 48 | } else { 49 | fprintf(stderr, "Usage: %s [OPTION]... [FILE]...\n", argv[0]); 50 | return 1; 51 | } 52 | FILE *file; 53 | if (file_name != NULL && strcmp(file_name, "-") != 0) { 54 | file = fopen(file_name, "r"); 55 | if (file == NULL) { 56 | fprintf(stderr, "Error: Unable to open file %s\n", file_name); 57 | return 1; 58 | } 59 | } else { 60 | file = stdin; 61 | } 62 | int total_lines = 0, total_words = 0, total_chars = 0, total_bytes = 0, max_line_length = 0; 63 | char line[MAX_LINE_LENGTH]; 64 | while (fgets(line, MAX_LINE_LENGTH, file) != NULL) { 65 | int line_length = strlen(line); 66 | total_lines++; 67 | total_chars += line_length; 68 | total_bytes += line_length; 69 | if (print_max_line_length && line_length > max_line_length) { 70 | max_line_length = line_length; 71 | } 72 | char *token = strtok(line, " \t\n\r\v\f"); 73 | while (token != NULL) { 74 | total_words++; 75 | token = strtok(NULL, " \t\n\r\v\f"); 76 | } 77 | } 78 | if (file != stdin) { 79 | fclose(file); 80 | } 81 | if (print_total) { 82 | printf("%d %d %d %s\n", total_lines, total_words, total_chars, file_name); 83 | } else { 84 | if (print_lines == 0 && print_words == 0 && print_chars == 0 && print_bytes == 0 && print_max_line_length == 0) { 85 | print_lines = print_words = print_chars = 1; 86 | } 87 | if (print_lines) printf("%d ", total_lines - 1); 88 | if (print_words) printf("%d ", total_words); 89 | if (print_chars) printf("%d ", total_chars); 90 | if (print_bytes) printf("%d ", total_bytes); 91 | if (print_max_line_length) printf("%d ", max_line_length - 1); 92 | printf("%s\n", file_name); 93 | } 94 | } 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /src/yes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) { 5 | if(argc >= 2 && (strcmp(argv[1], "--help") == 0)) { 6 | printf("Usage: yes [STRING]\n"); 7 | return 0; 8 | } else { 9 | while (1) { 10 | if (argc < 2) { 11 | printf("y\n"); 12 | } else { 13 | printf("%s\n", argv[1]); 14 | } 15 | } 16 | } 17 | return 0; 18 | } 19 | --------------------------------------------------------------------------------