/* * Extract a part from a file. * * Author: Peter Wu * Date: 2012-11-01 */ #include #include #include #include int main(int argc, char **argv) { char *filename; unsigned long seekpos, bytes_end; if (argc < 3) { fprintf(stderr, "Usage: %s file offset [last-exclusive-byte|+length]\n", *argv); return 1; } filename = argv[1]; seekpos = strtoul(argv[2], NULL, 0); if (argc >= 4) { bytes_end = strtoul(argv[3], NULL, 0); } else { bytes_end = -1; } if (argc >= 4 && *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 fseek failed, discard some 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 (bytes_end != -1UL && read_bytes != bytes_end) fprintf(stderr, "Output is truncated, missing %lu bytes.\n", bytes_end - read_bytes); fclose(fp); return 0; }