Advertisement
Guest User

xtail

a guest
Apr 1st, 2021
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.79 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <ctype.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. #include <limits.h>
  7. #include <stdbool.h>
  8.  
  9. #define BLOCKSIZE 1048576
  10.  
  11. void seekt(FILE *input, int lines);
  12. void unseekt(FILE *input, int lines);
  13. void btail(FILE *input, long bytes);
  14. void readprint(FILE *input);
  15. long validate_input(const char *arg);
  16.  
  17. int main(int argc, char **argv){
  18.     FILE *input = stdin;
  19.     int lines = 10;
  20.     long bytes = 0;
  21.     bool verbose = false;
  22.  
  23.     while ((argc > 1) && (argv[1][0] == '-')){
  24.         switch(argv[1][1]){
  25.             case 'n':
  26.                 if(!argv[1][2]){
  27.                     if(!argv[2]){
  28.                         fprintf(stderr, "Option 'n' requires an argument\n");
  29.                         exit(EXIT_FAILURE);
  30.                     } else {
  31.                         lines = validate_input(argv[2]);
  32.                         argc--;
  33.                         argv++;
  34.                     }
  35.                 }
  36.                 else
  37.                     lines = validate_input(argv[1]+2);
  38.                 break;
  39.             case 'h':
  40.                 fprintf(stdout, "A helpful text\n");
  41.                 return 0;
  42.             case 'v':
  43.                 verbose = true;
  44.                 break;
  45.             case 'c':
  46.                 if(!argv[1][2]){
  47.                     if(!argv[2]){
  48.                         fprintf(stderr, "Option 'c' requires an argument\n");
  49.                         exit(EXIT_FAILURE);
  50.                     } else {
  51.                         bytes = validate_input(argv[2]);
  52.                         argc--;
  53.                         argv++;
  54.                     }
  55.                 }
  56.                 else
  57.                     bytes = validate_input(argv[1]+2);
  58.                 break;
  59.             default:
  60.                 fprintf(stderr,"Invalid option\n");
  61.                 exit(EXIT_FAILURE);
  62.         }
  63.         argc--;
  64.         argv++;
  65.     }
  66.  
  67.     if(!argv[1]){
  68.         if(fseek(stdin, 0L, SEEK_SET) == 0){
  69.             // stdin, seekable
  70.             seekt(input, lines);
  71.         }
  72.         else{
  73.             // stdin, unseekable
  74.             unseekt(input, lines);
  75.         }
  76.     } else {
  77.         for(int i = 1; i < argc; i++){
  78.             input = fopen(argv[i], "rb");
  79.             if (input == NULL){
  80.                 fprintf(stderr,"Could not open file \"%s\" for reading.\n", argv[i]);
  81.                 exit(EXIT_FAILURE);
  82.             }
  83.             if(verbose)
  84.                 printf("==> %s <==\n", argv[i]);
  85.             if(bytes > 0)
  86.                 btail(input, bytes);
  87.             else{
  88.                 size_t ret = 0;
  89.                 if((ret = fseek(input, 0L, SEEK_SET)) == 0){
  90.                     // file, seekable
  91.                     seekt(input, lines);
  92.                 }
  93.                 else{
  94.                     // file, unseekable
  95.                     unseekt(input, lines);
  96.                 }
  97.             }
  98.         }
  99.     }
  100.     return 0;
  101. }
  102.  
  103. void unseekt(FILE *input, int lines){
  104.     char buffer[BLOCKSIZE];
  105.     size_t read, wrote, range;
  106.     long target = 0;
  107.     int lcount = 0;
  108.  
  109.     read = fread(buffer, sizeof(char), BLOCKSIZE, input);
  110.     if(fread(buffer, 1, 1, input) != 0){
  111.         fprintf(stderr, "Read error\n");
  112.         exit(EXIT_FAILURE);
  113.     }
  114.  
  115.     if(*(buffer+read-1) == '\n')
  116.         lcount--;
  117.  
  118.     for(target = read; target > 0; target--){
  119.         if(buffer[target] == '\n')
  120.             lcount++;
  121.         if(lcount == lines){
  122.             target++;
  123.             break;
  124.         }
  125.     }
  126.  
  127.     range = read-target;
  128.     wrote = fwrite(buffer+target, sizeof(char), range, stdout);
  129.  
  130.     if(fflush(stdout) != 0 || wrote < range){
  131.         fprintf(stderr, "Write error\n");
  132.         exit(EXIT_FAILURE);
  133.     }
  134. }
  135.  
  136. void seekt(FILE *input, int lines){  
  137.     char c;
  138.     int linenum = 0;
  139.     long bytecount = 0;
  140.     long fsize = 0;
  141.  
  142.     fseek(input, 0L, SEEK_END);
  143.     fsize = ftell(input);
  144.     fseek(input, -1L, SEEK_END);
  145.     if((c = fgetc(input)) == '\n'){
  146.         linenum--;
  147.     } else ungetc(c, input);
  148.  
  149.     while(-bytecount < fsize){
  150.         fseek(input, --bytecount, SEEK_END);
  151.         c = fgetc(input);
  152.         if (c == '\n')
  153.             linenum++;
  154.         else
  155.             ungetc(c, input);
  156.         if(linenum == lines)
  157.             break;
  158.     }
  159.  
  160.     readprint(input);
  161.     fclose(input);
  162. }
  163.  
  164. void btail(FILE *input, long bytes){
  165.     long fsize;
  166.  
  167.     fseek(input, 0L, SEEK_END);
  168.     fsize = ftell(input);
  169.  
  170.     if(bytes > fsize)
  171.         bytes = fsize;
  172.  
  173.     fseek(input, -bytes, SEEK_END);
  174.     readprint(input);
  175.     fclose(input);    
  176. }
  177.  
  178. void readprint(FILE *input){
  179.     char buffer[BLOCKSIZE];
  180.     size_t read, wrote;
  181.  
  182.     read = fread(buffer, sizeof(char), BLOCKSIZE, input);
  183.     if(fread(buffer, 1, 1, input) != 0){
  184.         fprintf(stderr, "Read error\n");
  185.         exit(EXIT_FAILURE);
  186.     }
  187.  
  188.     wrote = fwrite(buffer, sizeof(char), read, stdout);
  189.     if(fflush(stdout) != 0 || wrote < read){
  190.         fprintf(stderr, "Write error\n");
  191.         exit(EXIT_FAILURE);
  192.     }
  193. }
  194.  
  195. long validate_input(const char *arg){
  196.     char *endptr = NULL;
  197.     long num = 0;
  198.     errno = 0;
  199.  
  200.     num = strtol(arg, &endptr, 10);
  201.     if (arg == endptr){ // input is not a number
  202.         fprintf(stderr, "Invalid number of lines or bytes: \'%s\'\n", arg);
  203.         exit(1);
  204.     }
  205.     else if(errno == ERANGE && num == LONG_MAX){
  206.         fprintf(stderr, "Number of lines or bytes \'%s\' is too large\n", arg);
  207.         exit(1);
  208.     }
  209.     else if (errno == 0 && arg && *endptr != 0){ // more chars remain after num
  210.         fprintf(stderr, "Invalid number of lines or bytes: \'%s\'\n", arg);
  211.         exit(1);
  212.     }
  213.     else if (errno != 0 && num == 0){
  214.         fprintf(stderr, "Unknown error\n");
  215.         exit(1);
  216.     }
  217.     else if (num < 0)
  218.         return -num;
  219.        
  220.     return num;
  221. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement