diff options
author | Peter Wu <lekensteyn@gmail.com> | 2012-11-01 23:24:26 +0100 |
---|---|---|
committer | Peter Wu <lekensteyn@gmail.com> | 2012-11-01 23:24:26 +0100 |
commit | 18d81a4e8c430f47a4d5e59fd8c7c0591e7d894a (patch) | |
tree | 7ea73f8cf7baf4b18a4b6c13eb1fd313a2bc0663 /slice.c | |
parent | 3ea14aaa16290458b0d0d54c3c922096ac58d514 (diff) | |
download | c-files-18d81a4e8c430f47a4d5e59fd8c7c0591e7d894a.tar.gz |
slice: extract a part from a file
Diffstat (limited to 'slice.c')
-rw-r--r-- | slice.c | 74 |
1 files changed, 74 insertions, 0 deletions
@@ -0,0 +1,74 @@ +/* + * Extract a part from a file. + * + * Author: Peter Wu <lekensteyn@gmail.com> + * Date: 2012-11-01 + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> + +int main(int argc, char **argv) { + if (argc < 4) { + fprintf(stderr, "Usage: %s file offset last-byte|+length\n", *argv); + return 1; + } + char *filename = argv[1]; + unsigned long seekpos = strtoul(argv[2], NULL, 0); + unsigned long bytes_end = strtoul(argv[3], NULL, 0); + + if (*argv[3] == '+') { + if (bytes_end + seekpos < bytes_end) { + fprintf(stderr, "Integer overflow on the last byte\n"); + return 1; + } + bytes_end += seekpos; + } + + if (bytes_end <= seekpos) { + fprintf(stderr, "The last byte must be greater than the first byte.\n"); + return 1; + } + + FILE *fp; + if (filename[0] == '-' && filename[1] == 0) + fp = stdin; + else + fp = fopen(filename, "r"); + if (!fp) { + perror(filename); + return 1; + } + + unsigned long read_bytes = 0; + if (!fseek(fp, seekpos, SEEK_SET)) + read_bytes += seekpos; + + do { + char buf[8 * 1024]; + unsigned int read_count = sizeof(buf); + unsigned long skip_bytes = 0; + if (bytes_end - read_bytes < read_count) + read_count = bytes_end - read_bytes; + + if (read_bytes < seekpos) + skip_bytes = seekpos - read_bytes; + + unsigned long n = fread(buf, 1, read_count, fp); + if (!n) + break; /* EOF? */ + if (n > skip_bytes) + write(STDOUT_FILENO, buf + skip_bytes, n); + read_bytes += n; + } while (read_bytes < bytes_end); + + if (read_bytes != bytes_end) + fprintf(stderr, "Output is truncated, missing %lu bytes.\n", + bytes_end - read_bytes); + + fclose(fp); + + return 0; +} |