From 284e1b7a5c4b1b0b0f38d16ecb1507ea4ac964f4 Mon Sep 17 00:00:00 2001 From: Charles Cabergs Date: Sat, 8 Aug 2020 16:22:55 +0200 Subject: Moved everything in root --- README.md | 10 ++- basename.c | 83 +++++++++++++++++++ basename/basename.c | 83 ------------------- cut.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++ cut/cut.c | 225 ---------------------------------------------------- head.c | 166 ++++++++++++++++++++++++++++++++++++++ head/head.c | 166 -------------------------------------- mkdir.c | 86 ++++++++++++++++++++ mkdir/mkdir.c | 86 -------------------- rm.c | 130 ++++++++++++++++++++++++++++++ rm/rm.c | 130 ------------------------------ seq.c | 126 +++++++++++++++++++++++++++++ seq/seq.c | 126 ----------------------------- 13 files changed, 825 insertions(+), 817 deletions(-) create mode 100644 basename.c delete mode 100644 basename/basename.c create mode 100644 cut.c delete mode 100644 cut/cut.c create mode 100644 head.c delete mode 100644 head/head.c create mode 100644 mkdir.c delete mode 100644 mkdir/mkdir.c create mode 100644 rm.c delete mode 100644 rm/rm.c create mode 100644 seq.c delete mode 100644 seq/seq.c diff --git a/README.md b/README.md index ee1b35b..2d090f0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ # coreutils -Rewrite of some core utilities for educationnal purposes +Rewrite of some core utilities for educational purposes. + +| Name | Description | +|------------|-------------------------------------------| +| `mkdir` | make directories | +| `basename` | strip directory and suffix from filenames | +| `cut` | remove sections from each line of files | +| `rm` | remove files or directories | +| `seq` | print a sequence of numbers | diff --git a/basename.c b/basename.c new file mode 100644 index 0000000..83f3b8f --- /dev/null +++ b/basename.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include + +char *g_name = "basename"; + +void fatal(char *message) +{ + fprintf(stderr, "%s: %s\n", g_name, message); + exit(EXIT_FAILURE); +} + +char *truncate_path(char *s, char *suffix) +{ + if (*s == '\0') + return s; + + size_t last = strlen(s) - 1; + while (s[last] == '/' && last != 0) + { + s[last] = '\0'; + last--; + } + + char *last_slash = strrchr(s, '/'); + if (last_slash != NULL && last_slash != s) + s = last_slash + 1; + + if (suffix != NULL) + { + char *end = s + strlen(s) - strlen(suffix); + if (end > s && strcmp(end, suffix) == 0) + *end = '\0'; + } + return s; +} + +int main(int argc, char **argv) +{ + int option; + char *suffix = NULL; + bool multiple = false; + char line_delim = '\n'; + + g_name = argv[0]; + while ((option = getopt(argc, argv, "as:z")) != -1) + { + switch (option) + { + case 's': + suffix = optarg; + case 'a': + multiple = true; + break; + case 'z': + line_delim = '\0'; + break; + default: + return EXIT_FAILURE; + } + } + + if (optind == argc) + fatal("missing operand"); + + if (!multiple) + { + argv[optind] = truncate_path(argv[optind], argv[optind + 1]); + fputs(argv[optind], stdout); + putchar(line_delim); + return EXIT_SUCCESS; + } + + for (; optind < argc; optind++) + { + argv[optind] = truncate_path(argv[optind], suffix); + fputs(argv[optind], stdout); + putchar(line_delim); + } + return EXIT_SUCCESS; +} diff --git a/basename/basename.c b/basename/basename.c deleted file mode 100644 index 83f3b8f..0000000 --- a/basename/basename.c +++ /dev/null @@ -1,83 +0,0 @@ -#include -#include -#include -#include -#include - -char *g_name = "basename"; - -void fatal(char *message) -{ - fprintf(stderr, "%s: %s\n", g_name, message); - exit(EXIT_FAILURE); -} - -char *truncate_path(char *s, char *suffix) -{ - if (*s == '\0') - return s; - - size_t last = strlen(s) - 1; - while (s[last] == '/' && last != 0) - { - s[last] = '\0'; - last--; - } - - char *last_slash = strrchr(s, '/'); - if (last_slash != NULL && last_slash != s) - s = last_slash + 1; - - if (suffix != NULL) - { - char *end = s + strlen(s) - strlen(suffix); - if (end > s && strcmp(end, suffix) == 0) - *end = '\0'; - } - return s; -} - -int main(int argc, char **argv) -{ - int option; - char *suffix = NULL; - bool multiple = false; - char line_delim = '\n'; - - g_name = argv[0]; - while ((option = getopt(argc, argv, "as:z")) != -1) - { - switch (option) - { - case 's': - suffix = optarg; - case 'a': - multiple = true; - break; - case 'z': - line_delim = '\0'; - break; - default: - return EXIT_FAILURE; - } - } - - if (optind == argc) - fatal("missing operand"); - - if (!multiple) - { - argv[optind] = truncate_path(argv[optind], argv[optind + 1]); - fputs(argv[optind], stdout); - putchar(line_delim); - return EXIT_SUCCESS; - } - - for (; optind < argc; optind++) - { - argv[optind] = truncate_path(argv[optind], suffix); - fputs(argv[optind], stdout); - putchar(line_delim); - } - return EXIT_SUCCESS; -} diff --git a/cut.c b/cut.c new file mode 100644 index 0000000..2a7990d --- /dev/null +++ b/cut.c @@ -0,0 +1,225 @@ +#define _POSIX_C_SOURCE 200809L +#define _DEFAULT_SOURCE 1 + +#include +#include +#include +#include +#include +#include +#include + +#define LIST_VALUE_INFINITY -1 +#define LIST_VALUE_SINGLETON -2 + +#define LINE_BUFFER_SIZE 2024 + +typedef enum +{ + LIST_BYTE, + LIST_CHAR, + LIST_FIELD, + LIST_UNDEFINED, +} t_list_type; + +char *g_name = "cut"; + +void fatal_msg(char *message) +{ + fprintf(stderr, "%s: %s\n", g_name, message); + exit(EXIT_FAILURE); +} + +void fatal_errno(void) +{ + perror(g_name); + exit(EXIT_FAILURE); +} + +int parse_uint(char *s, char **endptr) +{ + if (!isdigit(*s)) + return -1; + unsigned long x = strtoul(s, endptr, 10); + return (int)x; +} + +int main(int argc, char **argv) +{ + int option; + int list_start = LIST_VALUE_INFINITY; + int list_end = LIST_VALUE_INFINITY; + t_list_type list_type = LIST_UNDEFINED; + wchar_t delimiter = '\t'; + bool print_only_delimiter = false; + char line_delimiter = '\n'; + + g_name = argv[0]; + while ((option = getopt(argc, argv, "b:c:d:f:sz")) > 0) + { + + switch (option) + { + case 'b': + case 'c': + case 'f': + if (list_type != LIST_UNDEFINED) + fatal_msg("only one type of list may be specified"); + + switch (option) + { + case 'b': list_type = LIST_BYTE; break; + case 'c': list_type = LIST_CHAR; break; + case 'f': list_type = LIST_FIELD; break; + } + + char *ptr = optarg; + + char *hyphen = strchr(ptr, '-'); + if (hyphen == NULL) // N + { + list_start = parse_uint(ptr, &ptr); + if (*ptr != '\0') + fatal_msg(""); + list_end = LIST_VALUE_SINGLETON; + } + else + { + if (ptr == hyphen) // -M + { + list_end = parse_uint(ptr + 1, &ptr); + printf(">> %d %d |%s|\n", list_start, list_end, ptr); + if (*ptr != '\0') + fatal_msg(""); + } + else + { + list_start = parse_uint(ptr, &ptr); + if (*ptr != '-') + fatal_msg(""); + ptr++; + if (*ptr != '\0') // N-M + { + list_end = parse_uint(ptr, &ptr); + } + if (*ptr != '\0') + fatal_msg(""); + } + } + break; + + case 'd': + delimiter = optarg[0]; + if (delimiter != '\0' && optarg[1] != '\0') + fatal_msg("the delimiter must be a single character"); + break; + + case 's': + print_only_delimiter = true; + break; + case 'z': + line_delimiter = '\0'; + break; + } + } + if (list_type == LIST_UNDEFINED) + fatal_msg("you must specify a list of bytes, characters, or fields"); + if (list_type != LIST_FIELD && delimiter != '\t') + fatal_msg("an input delimiter may be specified only when operating on fields"); + if (list_type != LIST_FIELD && print_only_delimiter) + fatal_msg("suppressing non-delimited lines makes sense only when operating on fields"); + + if (list_start == 0) + fatal_msg("list are numbered from 1"); + if (list_end > 0 && list_start > list_end) + fatal_msg("invalid decreasing range"); + + char *line = NULL; + size_t line_buffer_size = LINE_BUFFER_SIZE; + ssize_t read_size = -1; + + if ((line = malloc(LINE_BUFFER_SIZE)) == NULL) + exit(1); + + char *field; + int counter = 1; + char delimiter_buf[2] = {delimiter, '\0'}; + + if (optarg == NULL) + { + errno = 0; + while ((read_size = getdelim(&line, &line_buffer_size, line_delimiter, stdin)) > 0) + { + switch (list_type) + { + case LIST_BYTE: + case LIST_CHAR: // TODO unicode + if (list_end == LIST_VALUE_SINGLETON) + { + if (read_size - 1 >= list_start) + fputc(line[list_start - 1], stdout); + } + else if (list_start == LIST_VALUE_INFINITY) + { + line[list_end] = '\0'; + fputs(line, stdout); + } + else if (list_end == LIST_VALUE_INFINITY) + { + fputs(&line[list_start - 1], stdout); + } + else + { + line[list_end] = '\0'; + fputs(&line[list_start - 1], stdout); + } + break; + case LIST_FIELD: + while ((field = strsep(&line, delimiter_buf)) != NULL) + { + if (list_end == LIST_VALUE_SINGLETON && counter == list_start) + fputs(field, stdout); + else if (list_start == LIST_VALUE_INFINITY && counter <= list_end) + fputs(field, stdout); + else if (list_end == LIST_VALUE_INFINITY && counter >= list_start) + fputs(field, stdout); + else if (counter >= list_start && counter <= list_end) + fputs(field, stdout); + counter++; + } + break; + } + putchar('\n'); + } + free(line); + if (errno != 0) + fatal_errno(); + return EXIT_SUCCESS; + } + + + /* while (optarg != NULL) */ + /* { */ + /* if (strcmp(optarg, "-") == 0) */ + /* { */ + /* // read stdin */ + /* } */ + /* else */ + /* { */ + /* FILE *file; */ + /* */ + /* if ((file = fopen(optarg, "r")) == NULL) */ + /* fatal_errno(); */ + /* */ + /* while (getdelim(&line, 0, line_delimiter, file)) */ + /* { */ + /* if (field) */ + /* strsep(line, delimiter); */ + /* } */ + /* } */ + /* } */ + + + + return EXIT_SUCCESS; +} diff --git a/cut/cut.c b/cut/cut.c deleted file mode 100644 index 2a7990d..0000000 --- a/cut/cut.c +++ /dev/null @@ -1,225 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#define _DEFAULT_SOURCE 1 - -#include -#include -#include -#include -#include -#include -#include - -#define LIST_VALUE_INFINITY -1 -#define LIST_VALUE_SINGLETON -2 - -#define LINE_BUFFER_SIZE 2024 - -typedef enum -{ - LIST_BYTE, - LIST_CHAR, - LIST_FIELD, - LIST_UNDEFINED, -} t_list_type; - -char *g_name = "cut"; - -void fatal_msg(char *message) -{ - fprintf(stderr, "%s: %s\n", g_name, message); - exit(EXIT_FAILURE); -} - -void fatal_errno(void) -{ - perror(g_name); - exit(EXIT_FAILURE); -} - -int parse_uint(char *s, char **endptr) -{ - if (!isdigit(*s)) - return -1; - unsigned long x = strtoul(s, endptr, 10); - return (int)x; -} - -int main(int argc, char **argv) -{ - int option; - int list_start = LIST_VALUE_INFINITY; - int list_end = LIST_VALUE_INFINITY; - t_list_type list_type = LIST_UNDEFINED; - wchar_t delimiter = '\t'; - bool print_only_delimiter = false; - char line_delimiter = '\n'; - - g_name = argv[0]; - while ((option = getopt(argc, argv, "b:c:d:f:sz")) > 0) - { - - switch (option) - { - case 'b': - case 'c': - case 'f': - if (list_type != LIST_UNDEFINED) - fatal_msg("only one type of list may be specified"); - - switch (option) - { - case 'b': list_type = LIST_BYTE; break; - case 'c': list_type = LIST_CHAR; break; - case 'f': list_type = LIST_FIELD; break; - } - - char *ptr = optarg; - - char *hyphen = strchr(ptr, '-'); - if (hyphen == NULL) // N - { - list_start = parse_uint(ptr, &ptr); - if (*ptr != '\0') - fatal_msg(""); - list_end = LIST_VALUE_SINGLETON; - } - else - { - if (ptr == hyphen) // -M - { - list_end = parse_uint(ptr + 1, &ptr); - printf(">> %d %d |%s|\n", list_start, list_end, ptr); - if (*ptr != '\0') - fatal_msg(""); - } - else - { - list_start = parse_uint(ptr, &ptr); - if (*ptr != '-') - fatal_msg(""); - ptr++; - if (*ptr != '\0') // N-M - { - list_end = parse_uint(ptr, &ptr); - } - if (*ptr != '\0') - fatal_msg(""); - } - } - break; - - case 'd': - delimiter = optarg[0]; - if (delimiter != '\0' && optarg[1] != '\0') - fatal_msg("the delimiter must be a single character"); - break; - - case 's': - print_only_delimiter = true; - break; - case 'z': - line_delimiter = '\0'; - break; - } - } - if (list_type == LIST_UNDEFINED) - fatal_msg("you must specify a list of bytes, characters, or fields"); - if (list_type != LIST_FIELD && delimiter != '\t') - fatal_msg("an input delimiter may be specified only when operating on fields"); - if (list_type != LIST_FIELD && print_only_delimiter) - fatal_msg("suppressing non-delimited lines makes sense only when operating on fields"); - - if (list_start == 0) - fatal_msg("list are numbered from 1"); - if (list_end > 0 && list_start > list_end) - fatal_msg("invalid decreasing range"); - - char *line = NULL; - size_t line_buffer_size = LINE_BUFFER_SIZE; - ssize_t read_size = -1; - - if ((line = malloc(LINE_BUFFER_SIZE)) == NULL) - exit(1); - - char *field; - int counter = 1; - char delimiter_buf[2] = {delimiter, '\0'}; - - if (optarg == NULL) - { - errno = 0; - while ((read_size = getdelim(&line, &line_buffer_size, line_delimiter, stdin)) > 0) - { - switch (list_type) - { - case LIST_BYTE: - case LIST_CHAR: // TODO unicode - if (list_end == LIST_VALUE_SINGLETON) - { - if (read_size - 1 >= list_start) - fputc(line[list_start - 1], stdout); - } - else if (list_start == LIST_VALUE_INFINITY) - { - line[list_end] = '\0'; - fputs(line, stdout); - } - else if (list_end == LIST_VALUE_INFINITY) - { - fputs(&line[list_start - 1], stdout); - } - else - { - line[list_end] = '\0'; - fputs(&line[list_start - 1], stdout); - } - break; - case LIST_FIELD: - while ((field = strsep(&line, delimiter_buf)) != NULL) - { - if (list_end == LIST_VALUE_SINGLETON && counter == list_start) - fputs(field, stdout); - else if (list_start == LIST_VALUE_INFINITY && counter <= list_end) - fputs(field, stdout); - else if (list_end == LIST_VALUE_INFINITY && counter >= list_start) - fputs(field, stdout); - else if (counter >= list_start && counter <= list_end) - fputs(field, stdout); - counter++; - } - break; - } - putchar('\n'); - } - free(line); - if (errno != 0) - fatal_errno(); - return EXIT_SUCCESS; - } - - - /* while (optarg != NULL) */ - /* { */ - /* if (strcmp(optarg, "-") == 0) */ - /* { */ - /* // read stdin */ - /* } */ - /* else */ - /* { */ - /* FILE *file; */ - /* */ - /* if ((file = fopen(optarg, "r")) == NULL) */ - /* fatal_errno(); */ - /* */ - /* while (getdelim(&line, 0, line_delimiter, file)) */ - /* { */ - /* if (field) */ - /* strsep(line, delimiter); */ - /* } */ - /* } */ - /* } */ - - - - return EXIT_SUCCESS; -} diff --git a/head.c b/head.c new file mode 100644 index 0000000..f2201b5 --- /dev/null +++ b/head.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include +#include +#include + +typedef enum +{ + VLEVEL_QUIET, + VLEVEL_NORMAL, + VLEVEL_VERBOSE, +} t_verbose_level; + +typedef enum +{ + UNIT_LINE, + UNIT_BYTE, +} t_unit; + +char *g_name = "head"; + +#define UNIT_BYTE_BUFFER_SIZE 1028 + +void fatal_printf(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + fprintf(stderr, "%s: ", g_name); + vfprintf(stderr, format, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +int file_head(FILE *file, + char *header, t_unit unit, + unsigned long count, char line_delimiter) +{ + char buf[UNIT_BYTE_BUFFER_SIZE] = {'\0'}; + size_t read_size; + size_t write_size; + char *line = NULL; + size_t line_size = 0; + ssize_t ret; + + if (header != NULL) + printf("==> %s <==\n", header); + switch (unit) + { + case UNIT_BYTE: + while (count > 0) + { + read_size = count > UNIT_BYTE_BUFFER_SIZE ? UNIT_BYTE_BUFFER_SIZE : count; + write_size = fread(buf, 1, read_size, file); + fwrite(buf, 1, write_size, stdout); + if (write_size < read_size) + break; + count -= read_size; + } + break; + + case UNIT_LINE: + for (; count > 0 && (ret = getdelim(&line, &line_size, line_delimiter, file)) != -1; count--) + fwrite(line, 1, ret, stdout); + free(line); + break; + } + return 0; +} + +int file_path_head(char *path, + char *header, t_unit unit, + unsigned long count, char line_delimiter) +{ + FILE *file; + + if ((file = fopen(path, "r")) == NULL) + { + fprintf(stderr, "%s: cannot open '%s' for reading: %s\n", g_name, path, strerror(errno)); + return -1; + } + file_head(file, header, unit, count, line_delimiter); + fclose(file); + return 0; +} + +int main(int argc, char **argv) +{ + int option; + t_verbose_level verbose_level = VLEVEL_NORMAL; + t_unit unit = UNIT_LINE; + unsigned long count = 10; + char line_delimiter = '\n'; + + g_name = argv[0]; + + while ((option = getopt(argc, argv, "c:n:qvz")) != -1) + { + switch (option) + { + case 'c': + case 'n': + if (strchr(optarg, '-') != NULL) + fatal_printf("invalid number of bytes: '%s'\n", optarg); + char *endptr; + errno = 0; + // TODO '-' prefix result in tail + // TODO human readable size suffix + count = strtoul(optarg, &endptr, 10); + if (*endptr != '\0') + fatal_printf("invalid number of bytes: '%s'\n", optarg); + if (errno != 0 || *endptr != '\0') + fatal_printf("invalid number of bytes: '%s': %s\n", optarg, strerror(errno)); + switch (option) + { + case 'c': unit = UNIT_BYTE; break; + case 'n': unit = UNIT_LINE; break; + } + break; + + case 'q': verbose_level = VLEVEL_QUIET; break; + case 'v': verbose_level = VLEVEL_VERBOSE; break; + case 'z': line_delimiter = '\0'; break; + } + } + + if (argv[optind] == NULL) + { + file_head( + stdin, verbose_level == VLEVEL_VERBOSE ? "standard input" : NULL, + unit, count, line_delimiter); + return EXIT_SUCCESS; + } + + if (argv[optind + 1] == NULL) + { + if (strcmp(argv[optind], "-") == 0) + file_head( + stdin, verbose_level == VLEVEL_VERBOSE ? "standard input" : NULL, + unit, count, line_delimiter); + else + file_path_head( + argv[optind], verbose_level == VLEVEL_VERBOSE ? argv[optind] : NULL, + unit, count, line_delimiter); + return EXIT_SUCCESS; + } + + for (; optind < argc; optind++) + { + int ret = 0; + + if (strcmp(argv[optind], "-") == 0) + ret = file_head( + stdin, verbose_level != VLEVEL_QUIET ? "standard input" : NULL, + unit, count, line_delimiter); + else + ret = file_path_head( + argv[optind], verbose_level != VLEVEL_QUIET ? argv[optind] : NULL, + unit, count, line_delimiter); + if (argv[optind + 1] != NULL && ret != -1) + putchar('\n'); + } + return EXIT_SUCCESS; +} diff --git a/head/head.c b/head/head.c deleted file mode 100644 index f2201b5..0000000 --- a/head/head.c +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -typedef enum -{ - VLEVEL_QUIET, - VLEVEL_NORMAL, - VLEVEL_VERBOSE, -} t_verbose_level; - -typedef enum -{ - UNIT_LINE, - UNIT_BYTE, -} t_unit; - -char *g_name = "head"; - -#define UNIT_BYTE_BUFFER_SIZE 1028 - -void fatal_printf(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - fprintf(stderr, "%s: ", g_name); - vfprintf(stderr, format, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - -int file_head(FILE *file, - char *header, t_unit unit, - unsigned long count, char line_delimiter) -{ - char buf[UNIT_BYTE_BUFFER_SIZE] = {'\0'}; - size_t read_size; - size_t write_size; - char *line = NULL; - size_t line_size = 0; - ssize_t ret; - - if (header != NULL) - printf("==> %s <==\n", header); - switch (unit) - { - case UNIT_BYTE: - while (count > 0) - { - read_size = count > UNIT_BYTE_BUFFER_SIZE ? UNIT_BYTE_BUFFER_SIZE : count; - write_size = fread(buf, 1, read_size, file); - fwrite(buf, 1, write_size, stdout); - if (write_size < read_size) - break; - count -= read_size; - } - break; - - case UNIT_LINE: - for (; count > 0 && (ret = getdelim(&line, &line_size, line_delimiter, file)) != -1; count--) - fwrite(line, 1, ret, stdout); - free(line); - break; - } - return 0; -} - -int file_path_head(char *path, - char *header, t_unit unit, - unsigned long count, char line_delimiter) -{ - FILE *file; - - if ((file = fopen(path, "r")) == NULL) - { - fprintf(stderr, "%s: cannot open '%s' for reading: %s\n", g_name, path, strerror(errno)); - return -1; - } - file_head(file, header, unit, count, line_delimiter); - fclose(file); - return 0; -} - -int main(int argc, char **argv) -{ - int option; - t_verbose_level verbose_level = VLEVEL_NORMAL; - t_unit unit = UNIT_LINE; - unsigned long count = 10; - char line_delimiter = '\n'; - - g_name = argv[0]; - - while ((option = getopt(argc, argv, "c:n:qvz")) != -1) - { - switch (option) - { - case 'c': - case 'n': - if (strchr(optarg, '-') != NULL) - fatal_printf("invalid number of bytes: '%s'\n", optarg); - char *endptr; - errno = 0; - // TODO '-' prefix result in tail - // TODO human readable size suffix - count = strtoul(optarg, &endptr, 10); - if (*endptr != '\0') - fatal_printf("invalid number of bytes: '%s'\n", optarg); - if (errno != 0 || *endptr != '\0') - fatal_printf("invalid number of bytes: '%s': %s\n", optarg, strerror(errno)); - switch (option) - { - case 'c': unit = UNIT_BYTE; break; - case 'n': unit = UNIT_LINE; break; - } - break; - - case 'q': verbose_level = VLEVEL_QUIET; break; - case 'v': verbose_level = VLEVEL_VERBOSE; break; - case 'z': line_delimiter = '\0'; break; - } - } - - if (argv[optind] == NULL) - { - file_head( - stdin, verbose_level == VLEVEL_VERBOSE ? "standard input" : NULL, - unit, count, line_delimiter); - return EXIT_SUCCESS; - } - - if (argv[optind + 1] == NULL) - { - if (strcmp(argv[optind], "-") == 0) - file_head( - stdin, verbose_level == VLEVEL_VERBOSE ? "standard input" : NULL, - unit, count, line_delimiter); - else - file_path_head( - argv[optind], verbose_level == VLEVEL_VERBOSE ? argv[optind] : NULL, - unit, count, line_delimiter); - return EXIT_SUCCESS; - } - - for (; optind < argc; optind++) - { - int ret = 0; - - if (strcmp(argv[optind], "-") == 0) - ret = file_head( - stdin, verbose_level != VLEVEL_QUIET ? "standard input" : NULL, - unit, count, line_delimiter); - else - ret = file_path_head( - argv[optind], verbose_level != VLEVEL_QUIET ? argv[optind] : NULL, - unit, count, line_delimiter); - if (argv[optind + 1] != NULL && ret != -1) - putchar('\n'); - } - return EXIT_SUCCESS; -} diff --git a/mkdir.c b/mkdir.c new file mode 100644 index 0000000..3ab73d1 --- /dev/null +++ b/mkdir.c @@ -0,0 +1,86 @@ +#define _POSIX_C_SOURCE 2 + +#include +#include +#include +#include +#include +#include +#include +#include + +char *g_name = "mkdir"; + +int mkdir_wrapper(const char *path, mode_t mode, bool verbose) +{ + int ret; + + if ((ret = mkdir(path, mode)) == -1 && (verbose || errno != EEXIST)) + fprintf(stderr, "%s: cannot create directory '%s': %s\n", g_name, path, strerror(errno)); + else if (verbose) + printf("%s: created directory '%s'\n", g_name, path); + return ret; +} + +int main(int argc, char **argv) +{ + int option; + mode_t mode = 0755; + bool parent = false; + bool verbose = false; + + g_name = argv[0]; + if (argc == 1) + { + fprintf(stderr, "%s: missing operand\n", g_name); + return EXIT_FAILURE; + } + while ((option = getopt(argc, argv, "m:pv")) != -1) + { + switch (option) + { + case 'm': + sscanf(optarg, "%o", &mode); // TODO mode not working + break; + case 'p': + parent = true; + break; + case 'v': + verbose = true; + break; + } + } + for (; optind < argc; optind++) + { + // remove duplicate slash + for (size_t i = 0; argv[optind][i] != '\0'; i++) + { + if (argv[optind][i] == '/' && argv[optind][i + 1] == '/') + { + memmove(&argv[optind][i], &argv[optind][i + 1], strlen(&argv[optind][i + 1]) + 1); + i--; + } + } + + if (parent) + { + char *tmp; + char *searched = argv[optind]; + + if (*searched == '/') + searched++; + for (; (tmp = strchr(searched, '/')) != NULL; searched = tmp + 1) + { + if (tmp[1] == '\0') + continue; + *tmp = '\0'; + mkdir_wrapper(argv[optind], mode, verbose); + *tmp = '/'; + } + mkdir_wrapper(argv[optind], mode, verbose); + } + else + mkdir_wrapper(argv[optind], mode, verbose); + } + return EXIT_SUCCESS; +} diff --git a/mkdir/mkdir.c b/mkdir/mkdir.c deleted file mode 100644 index 3ab73d1..0000000 --- a/mkdir/mkdir.c +++ /dev/null @@ -1,86 +0,0 @@ -#define _POSIX_C_SOURCE 2 - -#include -#include -#include -#include -#include -#include -#include -#include - -char *g_name = "mkdir"; - -int mkdir_wrapper(const char *path, mode_t mode, bool verbose) -{ - int ret; - - if ((ret = mkdir(path, mode)) == -1 && (verbose || errno != EEXIST)) - fprintf(stderr, "%s: cannot create directory '%s': %s\n", g_name, path, strerror(errno)); - else if (verbose) - printf("%s: created directory '%s'\n", g_name, path); - return ret; -} - -int main(int argc, char **argv) -{ - int option; - mode_t mode = 0755; - bool parent = false; - bool verbose = false; - - g_name = argv[0]; - if (argc == 1) - { - fprintf(stderr, "%s: missing operand\n", g_name); - return EXIT_FAILURE; - } - while ((option = getopt(argc, argv, "m:pv")) != -1) - { - switch (option) - { - case 'm': - sscanf(optarg, "%o", &mode); // TODO mode not working - break; - case 'p': - parent = true; - break; - case 'v': - verbose = true; - break; - } - } - for (; optind < argc; optind++) - { - // remove duplicate slash - for (size_t i = 0; argv[optind][i] != '\0'; i++) - { - if (argv[optind][i] == '/' && argv[optind][i + 1] == '/') - { - memmove(&argv[optind][i], &argv[optind][i + 1], strlen(&argv[optind][i + 1]) + 1); - i--; - } - } - - if (parent) - { - char *tmp; - char *searched = argv[optind]; - - if (*searched == '/') - searched++; - for (; (tmp = strchr(searched, '/')) != NULL; searched = tmp + 1) - { - if (tmp[1] == '\0') - continue; - *tmp = '\0'; - mkdir_wrapper(argv[optind], mode, verbose); - *tmp = '/'; - } - mkdir_wrapper(argv[optind], mode, verbose); - } - else - mkdir_wrapper(argv[optind], mode, verbose); - } - return EXIT_SUCCESS; -} diff --git a/rm.c b/rm.c new file mode 100644 index 0000000..2bcf68f --- /dev/null +++ b/rm.c @@ -0,0 +1,130 @@ +#define _POSIX_C_SOURCE 200112L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum +{ + FLAG_FORCE = 1 << 0, + FLAG_INTERACTIVE = 1 << 1, + /* FLAG_INTERACTIVE_ONCE = 1 << 2, */ // TODO + FLAG_RECURSIVE = 1 << 3, + FLAG_DIRECTORY = 1 << 4, + FLAG_VERBOSE = 1 << 5, +} t_flags; + +char *g_name = "rm"; + +void log_errno(char *path) +{ + fprintf(stderr, "%s: cannot remove '%s': %s\n", g_name, path, strerror(errno)); +} + +void fatal_errno(char *path) +{ + log_errno(path); + exit(EXIT_FAILURE); +} + +int rm_file(char *path, t_flags flags) +{ + struct stat statbuf; + char recursive_path[PATH_MAX + 1] = {'\0'}; + + if (lstat(path, &statbuf) == -1) + fatal_errno(path); + if (flags & FLAG_INTERACTIVE + || (!(flags & FLAG_FORCE) + && !((statbuf.st_mode & S_IWUSR && statbuf.st_uid == getuid()) || + (statbuf.st_mode & S_IWGRP && statbuf.st_gid == getgid()) || + statbuf.st_mode & S_IWOTH))) + { + printf("%s: remove regular file '%s'? ", g_name, path); + if (tolower(getchar()) != 'y') + return 0; + } + + if (S_ISDIR(statbuf.st_mode) && flags & FLAG_RECURSIVE) + { + DIR *directory; + struct dirent *entry; + + if ((directory = opendir(path)) == NULL) + { + log_errno(path); + return 0; + } + strcpy(recursive_path, path); + if (path[strlen(path) - 1] != '/') + strcat(recursive_path, "/"); + while ((entry = readdir(directory)) != NULL) + { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + strcat(recursive_path, entry->d_name); + rm_file(recursive_path, flags); + strrchr(recursive_path, '/')[1] = '\0'; + } + closedir(directory); + if (rmdir(path) == -1) + log_errno(path); + else if (flags & FLAG_VERBOSE) + printf("removed directory '%s'\n", path); + } + else if (S_ISDIR(statbuf.st_mode) && flags & FLAG_DIRECTORY) + { + if (rmdir(path) == -1) + log_errno(path); + else if (flags & FLAG_VERBOSE) + printf("removed directory '%s'\n", path); + } + else + { + if (unlink(path) == -1) + log_errno(path); + else if (flags & FLAG_VERBOSE) + printf("removed '%s'\n", path); + } + return 0; +} + +int main(int argc, char **argv) +{ + if (argc == 1) + { + fprintf(stderr, "%s: missing operand\n", argv[0]); + return EXIT_FAILURE; + } + g_name = argv[0]; + + int option; + t_flags flags = 0; + + while ((option = getopt(argc, argv, "firRdv")) != -1) + { + switch (option) + { + case 'f': flags |= FLAG_FORCE; break; + case 'i': flags |= FLAG_INTERACTIVE; break; + /* case 'I': flags |= FLAG_INTERACTIVE_ONCE; break; */ + case 'd': flags |= FLAG_DIRECTORY; break; + case 'v': flags |= FLAG_VERBOSE; break; + + case 'r': + case 'R': + flags |= FLAG_RECURSIVE; break; + break; + } + } + + for (; optind < argc; optind++) + rm_file(argv[optind], flags); + return EXIT_SUCCESS; +} diff --git a/rm/rm.c b/rm/rm.c deleted file mode 100644 index 2bcf68f..0000000 --- a/rm/rm.c +++ /dev/null @@ -1,130 +0,0 @@ -#define _POSIX_C_SOURCE 200112L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef enum -{ - FLAG_FORCE = 1 << 0, - FLAG_INTERACTIVE = 1 << 1, - /* FLAG_INTERACTIVE_ONCE = 1 << 2, */ // TODO - FLAG_RECURSIVE = 1 << 3, - FLAG_DIRECTORY = 1 << 4, - FLAG_VERBOSE = 1 << 5, -} t_flags; - -char *g_name = "rm"; - -void log_errno(char *path) -{ - fprintf(stderr, "%s: cannot remove '%s': %s\n", g_name, path, strerror(errno)); -} - -void fatal_errno(char *path) -{ - log_errno(path); - exit(EXIT_FAILURE); -} - -int rm_file(char *path, t_flags flags) -{ - struct stat statbuf; - char recursive_path[PATH_MAX + 1] = {'\0'}; - - if (lstat(path, &statbuf) == -1) - fatal_errno(path); - if (flags & FLAG_INTERACTIVE - || (!(flags & FLAG_FORCE) - && !((statbuf.st_mode & S_IWUSR && statbuf.st_uid == getuid()) || - (statbuf.st_mode & S_IWGRP && statbuf.st_gid == getgid()) || - statbuf.st_mode & S_IWOTH))) - { - printf("%s: remove regular file '%s'? ", g_name, path); - if (tolower(getchar()) != 'y') - return 0; - } - - if (S_ISDIR(statbuf.st_mode) && flags & FLAG_RECURSIVE) - { - DIR *directory; - struct dirent *entry; - - if ((directory = opendir(path)) == NULL) - { - log_errno(path); - return 0; - } - strcpy(recursive_path, path); - if (path[strlen(path) - 1] != '/') - strcat(recursive_path, "/"); - while ((entry = readdir(directory)) != NULL) - { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) - continue; - strcat(recursive_path, entry->d_name); - rm_file(recursive_path, flags); - strrchr(recursive_path, '/')[1] = '\0'; - } - closedir(directory); - if (rmdir(path) == -1) - log_errno(path); - else if (flags & FLAG_VERBOSE) - printf("removed directory '%s'\n", path); - } - else if (S_ISDIR(statbuf.st_mode) && flags & FLAG_DIRECTORY) - { - if (rmdir(path) == -1) - log_errno(path); - else if (flags & FLAG_VERBOSE) - printf("removed directory '%s'\n", path); - } - else - { - if (unlink(path) == -1) - log_errno(path); - else if (flags & FLAG_VERBOSE) - printf("removed '%s'\n", path); - } - return 0; -} - -int main(int argc, char **argv) -{ - if (argc == 1) - { - fprintf(stderr, "%s: missing operand\n", argv[0]); - return EXIT_FAILURE; - } - g_name = argv[0]; - - int option; - t_flags flags = 0; - - while ((option = getopt(argc, argv, "firRdv")) != -1) - { - switch (option) - { - case 'f': flags |= FLAG_FORCE; break; - case 'i': flags |= FLAG_INTERACTIVE; break; - /* case 'I': flags |= FLAG_INTERACTIVE_ONCE; break; */ - case 'd': flags |= FLAG_DIRECTORY; break; - case 'v': flags |= FLAG_VERBOSE; break; - - case 'r': - case 'R': - flags |= FLAG_RECURSIVE; break; - break; - } - } - - for (; optind < argc; optind++) - rm_file(argv[optind], flags); - return EXIT_SUCCESS; -} diff --git a/seq.c b/seq.c new file mode 100644 index 0000000..8307fc4 --- /dev/null +++ b/seq.c @@ -0,0 +1,126 @@ +#define _POSIX_C_SOURCE 2 +#include +#include +#include +#include +#include +#include +#include + +#define MAX(x, y) ((x) > (y) ? (x) : (y)) + +typedef struct +{ + long double value; + int precision; + int integer_len; +} t_num; + +char *g_name = "seq"; + +int parse_num(char *s, t_num *num) +{ + char *tmp; + + errno = 0; + num->value = strtold(s, &tmp); + if (errno != 0 || *tmp != '\0') + { + fprintf(stderr, "%s: invalid floating point argument: '%s'\n", g_name, s); + exit(EXIT_FAILURE); + } + num->precision = 0; + num->integer_len = strlen(s); + if ((tmp = strchr(s, '.')) != NULL) + { + num->precision = strlen(tmp + 1); + num->integer_len = tmp - s; + } + return 0; +} + +int main(int argc, char **argv) +{ + if (argc == 1) + { + fprintf(stderr, "%s: missing operand\n", argv[0]); + return EXIT_FAILURE; + } + + int option; + char *separator = "\n"; + bool padding = false; + + g_name = argv[0]; + + while ((option = getopt(argc, argv, "f:s:w0123456789")) != -1) + { + if (isdigit(option)) + break; + switch (option) + { + case 'f': + exit(EXIT_FAILURE); // TODO + break; + case 's': + separator = optarg; + break; + case 'w': + padding = true; + break; + } + } + + t_num first; + t_num increment; + t_num last; + + first.value = 1.0; + first.precision = 0; + increment.value = 1.0; + increment.precision = 0; + + switch (argc - optind) + { + case 1: + parse_num(argv[optind], &last); + break; + case 2: + parse_num(argv[optind], &first); + parse_num(argv[optind + 1], &last); + break; + case 3: + parse_num(argv[optind], &first); + parse_num(argv[optind + 1], &increment); + if (increment.value == 0) + { + fprintf(stderr, "%s: invalid Zero increment value '%s'\n", argv[0], argv[optind + 3]); + exit(EXIT_FAILURE); + } + parse_num(argv[optind + 2], &last); + break; + default: + fprintf(stderr, "%s: extra operand '%s'\n", argv[0], argv[optind + 3]); + exit(EXIT_FAILURE); + break; + } + + while (increment.value > 0 ? (first.value <= last.value) : (first.value >= last.value)) + { + int precision = MAX(first.precision, increment.precision); + if (!padding) + printf("%.*llf", precision, first.value); + else + { + int width = MAX(last.integer_len, first.integer_len); + if (precision != 0) + width += precision + 1; + printf("%0*.*llf", width, precision, first.value); + } + first.value += increment.value; + if (increment.value > 0 ? (first.value <= last.value) : (first.value >= last.value)) + fputs(separator, stdout); + } + putchar('\n'); + return EXIT_SUCCESS; +} diff --git a/seq/seq.c b/seq/seq.c deleted file mode 100644 index 8307fc4..0000000 --- a/seq/seq.c +++ /dev/null @@ -1,126 +0,0 @@ -#define _POSIX_C_SOURCE 2 -#include -#include -#include -#include -#include -#include -#include - -#define MAX(x, y) ((x) > (y) ? (x) : (y)) - -typedef struct -{ - long double value; - int precision; - int integer_len; -} t_num; - -char *g_name = "seq"; - -int parse_num(char *s, t_num *num) -{ - char *tmp; - - errno = 0; - num->value = strtold(s, &tmp); - if (errno != 0 || *tmp != '\0') - { - fprintf(stderr, "%s: invalid floating point argument: '%s'\n", g_name, s); - exit(EXIT_FAILURE); - } - num->precision = 0; - num->integer_len = strlen(s); - if ((tmp = strchr(s, '.')) != NULL) - { - num->precision = strlen(tmp + 1); - num->integer_len = tmp - s; - } - return 0; -} - -int main(int argc, char **argv) -{ - if (argc == 1) - { - fprintf(stderr, "%s: missing operand\n", argv[0]); - return EXIT_FAILURE; - } - - int option; - char *separator = "\n"; - bool padding = false; - - g_name = argv[0]; - - while ((option = getopt(argc, argv, "f:s:w0123456789")) != -1) - { - if (isdigit(option)) - break; - switch (option) - { - case 'f': - exit(EXIT_FAILURE); // TODO - break; - case 's': - separator = optarg; - break; - case 'w': - padding = true; - break; - } - } - - t_num first; - t_num increment; - t_num last; - - first.value = 1.0; - first.precision = 0; - increment.value = 1.0; - increment.precision = 0; - - switch (argc - optind) - { - case 1: - parse_num(argv[optind], &last); - break; - case 2: - parse_num(argv[optind], &first); - parse_num(argv[optind + 1], &last); - break; - case 3: - parse_num(argv[optind], &first); - parse_num(argv[optind + 1], &increment); - if (increment.value == 0) - { - fprintf(stderr, "%s: invalid Zero increment value '%s'\n", argv[0], argv[optind + 3]); - exit(EXIT_FAILURE); - } - parse_num(argv[optind + 2], &last); - break; - default: - fprintf(stderr, "%s: extra operand '%s'\n", argv[0], argv[optind + 3]); - exit(EXIT_FAILURE); - break; - } - - while (increment.value > 0 ? (first.value <= last.value) : (first.value >= last.value)) - { - int precision = MAX(first.precision, increment.precision); - if (!padding) - printf("%.*llf", precision, first.value); - else - { - int width = MAX(last.integer_len, first.integer_len); - if (precision != 0) - width += precision + 1; - printf("%0*.*llf", width, precision, first.value); - } - first.value += increment.value; - if (increment.value > 0 ? (first.value <= last.value) : (first.value >= last.value)) - fputs(separator, stdout); - } - putchar('\n'); - return EXIT_SUCCESS; -} -- cgit