logo

utils-std

Collection of commonly available Unix tools
commit: 47958f771c2aaa197b8d49ccb1f6aad2300328db
parent 8b940079a62153e56f0b935cd3d1facb81cb6bc4
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Fri, 16 Aug 2024 02:29:01 +0200

cmd/split: split_lines function

Diffstat:

Mcmd/split.c136++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Mtest-cmd/split.sh40+++++++++++++++++++++++++++++++++-------
2 files changed, 148 insertions(+), 28 deletions(-)

diff --git a/cmd/split.c b/cmd/split.c @@ -25,6 +25,28 @@ size_t suffix_len = 3, bytes = 0, lines = 0; char *name_in = NULL; static int +base26(int id, char *str) +{ + memcpy(str, name, name_len); + memset(str + name_len, 'a', suffix_len); + + size_t id_p = name_len + suffix_len; + do + { + str[id_p--] = 'a' + (id % 26); + id /= 26; + } while(id > 0 && id_p > name_len); + + if(id_p <= name_len) + { + fprintf(stderr, "split: Failed representing %d into suffix of length %zu\n", id, suffix_len); + return -1; + } + + return 0; +} + +static int split_bytes() { int fd_in = STDIN_FILENO; @@ -52,31 +74,14 @@ split_bytes() while(wrote < fd_in_stat.st_size) { char name_out[NAME_MAX] = ""; - memcpy(name_out, name, name_len); - memset(name_out + name_len, 'a', suffix_len); - - int id_n = split_id++; - size_t id_p = name_len + suffix_len; - do - { - name_out[id_p--] = 'a' + (id_n % 26); - id_n /= 26; - } while(id_n > 0 && id_p > name_len); - - if(id_p <= name_len) - { - fprintf(stderr, - "split: Failed representing %d into suffix of length %zu\n", - split_id, - suffix_len); - return 1; - } + if(base26(split_id++, name_out) < 0) return 1; int fd_out = open(name_out, O_WRONLY | O_NOCTTY | O_CREAT, 0644); if(fd_out < 0) { fprintf(stderr, "split: Failed opening '%s' file: %s\n", name_out, strerror(errno)); - return 1; + err = 1; + break; } int ret = auto_file_copy(fd_in, fd_out, bytes, 0); @@ -107,6 +112,95 @@ split_bytes() return err; } +static int +split_lines() +{ + FILE *in = stdin; + if(name_in != NULL) + { + in = fopen(name_in, "r"); + if(in == NULL) + { + fprintf(stderr, "split: Failed opening '%s' file: %s\n", name_in, strerror(errno)); + return 1; + } + } + + int err = 0; + char *line = NULL; + size_t line_len = 0; + int split_id = 0; + while(true) + { + if(feof(in)) break; + if(ferror(in)) + { + fprintf(stderr, "split: Failed reading line from file '%s': %s\n", name_in, strerror(errno)); + err = 1; + break; + } + + char name_out[NAME_MAX] = ""; + if(base26(split_id++, name_out) < 0) + { + err = 1; + break; + } + + FILE *out = NULL; + for(int i = 0; i < lines; i++) + { + ssize_t nread = getline(&line, &line_len, in); + if(nread < 0) + { + if(errno != 0) + { + fprintf( + stderr, "split: Failed reading line from file '%s': %s\n", name_in, strerror(errno)); + err = 1; + } + break; + } + + if(out == NULL) + { + out = fopen(name_out, "w"); + if(out == NULL) + { + fprintf(stderr, "split: Failed opening '%s' file: %s\n", name_out, strerror(errno)); + err = 1; + break; + } + } + + if(fwrite(line, nread, 1, out) < 0) + { + fprintf(stderr, "split: Failed writing line to file '%s': %s\n", name_out, strerror(errno)); + err = 1; + break; + } + } + + if(out != NULL) + { + if(fclose(out) < 0) + { + fprintf(stderr, "split: Failing closing file '%s': %s\n", name_out, strerror(errno)); + err = 1; + break; + } + } + + if(err != 0) break; + } + + if(line_len > 0) free(line); + + if(name_in != NULL) fclose(in); + + return err; +} + static char *error_opt_b_l = "split: Options -b and -l are mutually exclusive\n"; int @@ -212,5 +306,5 @@ main(int argc, char *argv[]) if(bytes != 0) return split_bytes(); - return 0; + return split_lines(); } diff --git a/test-cmd/split.sh b/test-cmd/split.sh @@ -38,9 +38,9 @@ t_end() exit $err } -check_splits() +check_splits_b32() { - for i in split_test_* + for i in split_test_b32_* do size="$(wc -c $i | cut -d' ' -f1)" if [ "$size" != "32" ] @@ -51,8 +51,21 @@ check_splits() done } +check_splits_l10() +{ + for i in split_test_l10_* + do + size="$(wc -l $i | cut -d' ' -f1)" + if [ "$size" != "10" ] + then + printf "# Expected 10 lines but '%s' has %d lines\n" "$i" "$size" + return 1 + fi + done +} + err=0 -plans=3 +plans=6 count=0 printf '1..%d\n' "$plans" @@ -63,9 +76,22 @@ cd "$tempdir" || exit 1 trap t_end EXIT -t split "$target" -b 32 "$WD/test-cmd/inputs/all_bytes" split_test_ +### + +t split_b32 "$target" -b 32 "$WD/test-cmd/inputs/all_bytes" split_test_b32_ + +t check_splits check_splits_b32 + +cat split_test_b32_* > split_test_b32 +t compare cmp split_test_b32 "$WD/test-cmd/inputs/all_bytes" + +### + +seq 1 100 > test_100 + +t split_l10 "$target" -l 10 test_100 split_test_l10_ -t check_splits check_splits +t check_splits check_splits_l10 -cat split_test_* > split_test -t compare cmp split_test "$WD/test-cmd/inputs/all_bytes" +cat split_test_l10_* > split_test_l10 +t compare cmp split_test_l10 test_100