Skip to content

Commit

Permalink
Made cat faster and slightly bigger
Browse files Browse the repository at this point in the history
  • Loading branch information
mckenney5 committed Jun 2, 2021
1 parent 1cde59c commit 3447ce6
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 19 deletions.
8 changes: 6 additions & 2 deletions slimcat.1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH SLIMCAT "1" "August 2020" "SLIM CAT 1.1.0" "User Commands"
.TH SLIMCAT "1" "August 2020" "SLIM CAT 1.2.0" "User Commands"
.SH NAME
slimcat \- still concatenating files and printing on the standard output, just slimmer.
.SH SYNOPSIS
Expand All @@ -8,7 +8,7 @@ slimcat \- still concatenating files and printing on the standard output, just s
.PP
This is a rewrite of GNU cat where the unused features are removed. The only option is -h for help and -u for unbuffered output.
.PP
We concatenate files(s) to standard output with less than 50 lines of code.
We concatenate files(s) to standard output with less than 60 lines of code.
.PP
With no file, or when file is \-, read standard input.
.SH EXAMPLES
Expand Down Expand Up @@ -37,6 +37,10 @@ Unknown command line argument.
.TP
3
Error while writing.
.TP
4
Error while allocating memory.

.SH AUTHOR
Written by Adam McKenney
.SH "REPORTING BUGS"
Expand Down
44 changes: 27 additions & 17 deletions src/cat.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,46 @@
#include <stdio.h> //fprintf, perror
#include <stdlib.h> //exit
#include <unistd.h> //read, write, close
#include <fcntl.h> //open
#include <sys/types.h> //stat
#include <sys/stat.h> //stat
#include <sys/sendfile.h> //sendfile
#include <fcntl.h> //open, STDIN_FILENO, STDOUT_FILENO

#define NAME "slimcat" //Program name, can be changed so a user can keep their bloated version of cat
#define HELP "Usage: " NAME " [-hu] [file...]\nWe concatenate files(s) to standard output with less than 50 lines of code.\n\nWith no file, or when file is -, read standard input.\nExamples:\n " NAME " -h Displays the help\n " NAME " -u Tells the OS that we dont want a buffer (warning may be a lot slower with a large file).\n " NAME " x - y Output x's contents, then standard input, then y's contents.\n " NAME " Copy standard input to standard output."
#define BUFF_SIZE 10000 //a larger buffer trades memory for speed

void throw_error(char* extra_msg, int exit_code){
void throw_error(const char* extra_msg, const int exit_code){
/* function to writes the program name, optionally extra info, then the error to stderr */
if(extra_msg != NULL) fprintf(stderr, "%s: %s: ", NAME, extra_msg);
else fprintf(stderr, "%s: ", NAME);
perror("");
if(exit_code) exit(exit_code); //allows non-fatal errors to keep going
}
void cat(int fd, char no_buf){
void cat(const int fd, const char no_buf, size_t size){
/* reads from the file descriptor into buf, until zero bytes are read */
char buf[BUFF_SIZE];
size_t r = 0, size = BUFF_SIZE;
if(no_buf) size = sizeof(char);
while((r=read(fd, buf, size)) > 0)
if(write(1, buf, r) != r) throw_error(NULL, 3); //if writing stops for some reason
if(r == -1) throw_error(NULL, 1); //if read(2) throws an error
if(fd == STDIN_FILENO || size > 2147479552 /* max file size for sendfile in Linux */ ){
size_t r = 0;
if(no_buf) size = 1;
void *buf = malloc(size);
if(buf == NULL) throw_error("Buffer Allocation", 4);
while((r=read(fd, buf, size)) > 0)
if(write(STDOUT_FILENO, buf, r) != r) throw_error(NULL, 3); //if writing stops for some reason
if(r == -1) throw_error(NULL, 1); //if read(2) throws an error
free(buf);
} else //if we are given a file, use the sendfile syscall for better speed
if(sendfile(STDOUT_FILENO, fd, 0, size) != size) throw_error("In sendfile", 1);
}
int get_file(char* file_name, char no_buf){
void get_file(const char* file_name, const char no_buf){
/* tries to open the user's file, then calls cat() with its file pointer */
int fd = -1;
if(file_name[0] == '-' && file_name[1] == '\0'){ cat(STDIN_FILENO, no_buf, BUFF_SIZE); return;}
struct stat buffer;
int fd = -1, status = stat(file_name, &buffer);
if(status != 0) throw_error(file_name, 1);
fd = open(file_name, O_RDONLY);
if(fd == -1) throw_error(file_name, 1);
cat(fd, no_buf);
cat(fd, no_buf, buffer.st_size);
close(fd);
return 0;
}
int main(int argc, char *argv[]){
size_t i = 0;
Expand All @@ -42,10 +52,10 @@ int main(int argc, char *argv[]){
if(argv[i][1] == 'h') { puts(HELP); return 0; }
else if(argv[i][1] == 'u') no_buf = 1; //required by POSIX, turns off buffered output
else { fprintf(stderr, "%s: unknown command line arg '%s'\n", NAME, argv[i]); return 2;}
} else break;
} else {
if(argv[i] == NULL || argv[i][0] == '-') cat(STDIN_FILENO, no_buf, BUFF_SIZE); //if no args
else for( ; i < argc; i++) get_file(argv[i], no_buf); //step through each arg as if it's a file
}
}
if(argv[i] == NULL) cat(STDIN_FILENO, no_buf); //if no args
else for( ; i < argc; i++) get_file(argv[i], no_buf); //step through each arg as if it's a file
return 0;
}

0 comments on commit 3447ce6

Please sign in to comment.