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:
M | cmd/split.c | 136 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------- |
M | test-cmd/split.sh | 40 | +++++++++++++++++++++++++++++++++------- |
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