Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <string.h>
- #include <errno.h>
- #include <limits.h>
- #include <stdbool.h>
- #define BLOCKSIZE 1048576
- void seekt(FILE *input, int lines);
- void unseekt(FILE *input, int lines);
- void btail(FILE *input, long bytes);
- void readprint(FILE *input);
- long validate_input(const char *arg);
- int main(int argc, char **argv){
- FILE *input = stdin;
- int lines = 10;
- long bytes = 0;
- bool verbose = false;
- while ((argc > 1) && (argv[1][0] == '-')){
- switch(argv[1][1]){
- case 'n':
- if(!argv[1][2]){
- if(!argv[2]){
- fprintf(stderr, "Option 'n' requires an argument\n");
- exit(EXIT_FAILURE);
- } else {
- lines = validate_input(argv[2]);
- argc--;
- argv++;
- }
- }
- else
- lines = validate_input(argv[1]+2);
- break;
- case 'h':
- fprintf(stdout, "A helpful text\n");
- return 0;
- case 'v':
- verbose = true;
- break;
- case 'c':
- if(!argv[1][2]){
- if(!argv[2]){
- fprintf(stderr, "Option 'c' requires an argument\n");
- exit(EXIT_FAILURE);
- } else {
- bytes = validate_input(argv[2]);
- argc--;
- argv++;
- }
- }
- else
- bytes = validate_input(argv[1]+2);
- break;
- default:
- fprintf(stderr,"Invalid option\n");
- exit(EXIT_FAILURE);
- }
- argc--;
- argv++;
- }
- if(!argv[1]){
- if(fseek(stdin, 0L, SEEK_SET) == 0){
- // stdin, seekable
- seekt(input, lines);
- }
- else{
- // stdin, unseekable
- unseekt(input, lines);
- }
- } else {
- for(int i = 1; i < argc; i++){
- input = fopen(argv[i], "rb");
- if (input == NULL){
- fprintf(stderr,"Could not open file \"%s\" for reading.\n", argv[i]);
- exit(EXIT_FAILURE);
- }
- if(verbose)
- printf("==> %s <==\n", argv[i]);
- if(bytes > 0)
- btail(input, bytes);
- else{
- size_t ret = 0;
- if((ret = fseek(input, 0L, SEEK_SET)) == 0){
- // file, seekable
- seekt(input, lines);
- }
- else{
- // file, unseekable
- unseekt(input, lines);
- }
- }
- }
- }
- return 0;
- }
- void unseekt(FILE *input, int lines){
- char buffer[BLOCKSIZE];
- size_t read, wrote, range;
- long target = 0;
- int lcount = 0;
- read = fread(buffer, sizeof(char), BLOCKSIZE, input);
- if(fread(buffer, 1, 1, input) != 0){
- fprintf(stderr, "Read error\n");
- exit(EXIT_FAILURE);
- }
- if(*(buffer+read-1) == '\n')
- lcount--;
- for(target = read; target > 0; target--){
- if(buffer[target] == '\n')
- lcount++;
- if(lcount == lines){
- target++;
- break;
- }
- }
- range = read-target;
- wrote = fwrite(buffer+target, sizeof(char), range, stdout);
- if(fflush(stdout) != 0 || wrote < range){
- fprintf(stderr, "Write error\n");
- exit(EXIT_FAILURE);
- }
- }
- void seekt(FILE *input, int lines){
- char c;
- int linenum = 0;
- long bytecount = 0;
- long fsize = 0;
- fseek(input, 0L, SEEK_END);
- fsize = ftell(input);
- fseek(input, -1L, SEEK_END);
- if((c = fgetc(input)) == '\n'){
- linenum--;
- } else ungetc(c, input);
- while(-bytecount < fsize){
- fseek(input, --bytecount, SEEK_END);
- c = fgetc(input);
- if (c == '\n')
- linenum++;
- else
- ungetc(c, input);
- if(linenum == lines)
- break;
- }
- readprint(input);
- fclose(input);
- }
- void btail(FILE *input, long bytes){
- long fsize;
- fseek(input, 0L, SEEK_END);
- fsize = ftell(input);
- if(bytes > fsize)
- bytes = fsize;
- fseek(input, -bytes, SEEK_END);
- readprint(input);
- fclose(input);
- }
- void readprint(FILE *input){
- char buffer[BLOCKSIZE];
- size_t read, wrote;
- read = fread(buffer, sizeof(char), BLOCKSIZE, input);
- if(fread(buffer, 1, 1, input) != 0){
- fprintf(stderr, "Read error\n");
- exit(EXIT_FAILURE);
- }
- wrote = fwrite(buffer, sizeof(char), read, stdout);
- if(fflush(stdout) != 0 || wrote < read){
- fprintf(stderr, "Write error\n");
- exit(EXIT_FAILURE);
- }
- }
- long validate_input(const char *arg){
- char *endptr = NULL;
- long num = 0;
- errno = 0;
- num = strtol(arg, &endptr, 10);
- if (arg == endptr){ // input is not a number
- fprintf(stderr, "Invalid number of lines or bytes: \'%s\'\n", arg);
- exit(1);
- }
- else if(errno == ERANGE && num == LONG_MAX){
- fprintf(stderr, "Number of lines or bytes \'%s\' is too large\n", arg);
- exit(1);
- }
- else if (errno == 0 && arg && *endptr != 0){ // more chars remain after num
- fprintf(stderr, "Invalid number of lines or bytes: \'%s\'\n", arg);
- exit(1);
- }
- else if (errno != 0 && num == 0){
- fprintf(stderr, "Unknown error\n");
- exit(1);
- }
- else if (num < 0)
- return -num;
- return num;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement