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 --- head.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 head.c (limited to 'head.c') 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; +} -- cgit