From 47e9c333620a0ca186efc00d2495b44fc887882f Mon Sep 17 00:00:00 2001 From: Tyler Murphy Date: Wed, 7 Jun 2023 21:33:44 -0400 Subject: [PATCH] more documentation --- command/cat.c | 1 + command/chmod.c | 1 + command/chown.c | 1 + command/cp.c | 151 +++++++++++++++++++++++++++++++++++------------- command/dd.c | 51 ++++++++++------ command/echo.c | 46 ++++++++++++--- command/ed.c | 62 ++++++++++---------- 7 files changed, 217 insertions(+), 96 deletions(-) diff --git a/command/cat.c b/command/cat.c index 8a87369..2995f45 100644 --- a/command/cat.c +++ b/command/cat.c @@ -1,5 +1,6 @@ /** * file: cat.c + * command: cat * author: Tyler Murphy */ diff --git a/command/chmod.c b/command/chmod.c index 8bf6aab..6d1003b 100644 --- a/command/chmod.c +++ b/command/chmod.c @@ -1,5 +1,6 @@ /** * file: chmod.c + * command: chmod * author: Tyler Murphy */ diff --git a/command/chown.c b/command/chown.c index 7f9cb0f..59613c5 100644 --- a/command/chown.c +++ b/command/chown.c @@ -1,5 +1,6 @@ /** * file: chown.c + * command: chown * author: Tyler Murphy */ diff --git a/command/cp.c b/command/cp.c index 4c65a51..576a99b 100644 --- a/command/cp.c +++ b/command/cp.c @@ -1,3 +1,9 @@ +/** + * file: cp.c + * command: cp + * author: Tyler Murphy + */ + #include "command.h" #include "lslib.h" @@ -10,14 +16,20 @@ #include #include +/** + * Command flags to be used with cp + */ static struct { - bool recurse; - bool preserve; - bool sym_link; - bool hard_link; - bool verbose; + bool recurse; /* Recurse copy directorys */ + bool preserve; /* Preserve file attributes */ + bool sym_link; /* Symlink files instead of copy */ + bool hard_link; /* Hardlink files instead of copy */ + bool verbose; /* Verbose the output */ } flags; +/** + * Help function for cp + */ static void help(void) { printf("Usage: cp [-rplsv] SOURCE... DEST\n\n"); printf("Copy SOURCEs to DEST\n\n"); @@ -27,6 +39,12 @@ static void help(void) { printf("\t-v\tVerbose\n"); } +/** + * Takes in each argument that has a single - and parses it + * @param c the character after the - + * @param next the next argument in argv that hasnt been parsed + * @reutrn if the next arg was used or if the arg was invalid + */ static int short_arg(char c, char* next) { UNUSED(next); switch (c) { @@ -54,24 +72,33 @@ static int short_arg(char c, char* next) { return ARG_UNUSED; } +/** + * Takes in two files paths and copies the data from one path to another + * @param from the file to copy from + * @param to the file to copy to + * @returns if the file successfully coppied + */ static bool copy_file(char* from, char* to) { - #define BS 1024 + #define BS 1024 /* The block size of copy with */ - FILE *from_f, *to_f; - char buf[BS]; - int read; + FILE *from_f, *to_f; /* file pointers to cope data from and to */ + char buf[BS]; /* te file copy buffer */ + int read; /* the amount of bytes read */ + /* attempt to get a read stream from the src file */ from_f = get_file_s(from, "r"); if (from_f == NULL) { return false; } + /* attempt to get a write streams from the dest file */ to_f = get_file_s(to, "w"); if (to_f == NULL) { fclose(from_f); return false; } - + /* while data is read copy the data to the dest */ while ((read = fread(buf, 1, BS, from_f)) > 0) { fwrite(buf, 1, read, to_f); } + /* output if verbose */ if (flags.verbose) { output("copied '%s'", from); } @@ -79,164 +106,206 @@ static bool copy_file(char* from, char* to) { return true; } +/** + * Takes in two file paths and symlinks from one to the other path + * @param from the file to symlink + * @param to the path to put the symlink + * @returns if the file successfully symlinked + */ static bool symlink_file(char* from, char* to) { + /* symlink the file and error if failed */ if (symlink(from, to) < 0) { error_s("failed to symlink '%s'", from); return false; } else if (flags.verbose) { - output("symlinked '%s'", from); + output("symlinked '%s'", from); /* output if verbose */ } return true; } +/** + * Takes in two file paths and hardlinks from one to the other path + * @param from the file to hardlink + * @param the path to put the hardlink + * @returns fi the fule successfully hardlinked + */ static bool hardlink_file(char* from, char* to) { + /* hard link the file and error if failed */ if (link(from, to) < 0) { error_s("failed to hardlink '%s'", from); return false; } else if (flags.verbose) { - output("hardlinked '%s'", from); + output("hardlinked '%s'", from); /* output if verbose */ } return true; } +/** + * Copies data from one path to another using the set path buffers and + * flags. Make sure to set these before running this function. + * @param s the stat of the file being coppied + */ static void run_copy(struct stat* s) { + /* read file paths from the path buffers */ char* from = get_path_buffer(); char* to = get_path_buffer_2(); + /* choose copy method based on given flags */ bool result; - if (flags.sym_link) { - result = symlink_file(from, to); + if (flags.sym_link) { + result = symlink_file(from, to); /* symlink */ } else if (flags.hard_link) { - result = hardlink_file(from, to); + result = hardlink_file(from, to); /* hardlink */ } else { - result = copy_file(from, to); + result = copy_file(from, to); /* copy */ } + /* if failed return */ if (!result) return; if (!flags.preserve) return; + /* if set to preserve file attribs, copy over ownership and permissions */ if (chmod(to, s->st_mode) < 0) { - error_s("cannot chmod '%s'", to); + error_s("cannot chmod '%s'", to); /* error if failed */ return; } if (chown(to, s->st_uid, s->st_gid) < 0) { - error_s("cannot chown '%s'", to); + error_s("cannot chown '%s'", to); /* error if failed */ return; } } +/* predefine function definition */ static void cp_file(char* path); +/** + * Copies all files in a diretory specified in the path buffer, to the dest. + * Make sure both the src and dest path buffers are set before calling. + * @param s the stat of the directory + */ static void cp_directory(struct stat* s) { DIR* d; struct dirent* file; + /* if were not recursing ignore directory and error */ if (!flags.recurse) { error_s("-r not specified; omitting directory '%s'", get_path_buffer()); return; } + /* if we failed to make the directory to copy data into error and return */ if (mkdir(get_path_buffer_2(), s->st_mode) < 0 && errno != EEXIST) { error_s("cannot create directory '%s'", get_path_buffer_2()); return; } + /* open directory, if failed error and return */ d = opendir(get_path_buffer()); - if (d == NULL) { error_s("cannot open directory '%s'", get_path_buffer()); return; } + /* copy each file in the directory */ while ((file = readdir(d)) != NULL) { if (is_dot_dir(file->d_name)) continue; cp_file(file->d_name); } } -static char* get_file_name(char* path) { - int last = 0; - int i = 0; - - if (path[0] == '\0') return path; - - while (true) { - if (path[i+1] == '\0') break; - if (path[i] == '/') { - last = i; - } - i++; - } - - if (last == 0) return path; - else return path + last + 1; -} - +/** + * Copies a given file path to the destination given in the 2nd path buffer + * Make sure path buffer 2 is set before running this function + * @param path the file to copy + */ static void cp_file(char* path) { + /* load src and dest into path buffers */ int save = push_path_buffer(path); - int save2 = push_path_buffer_2(get_file_name(path)); - + int save2 = push_path_buffer_2(get_last_component(path)); + + /* if we cannot get file info error and return */ struct stat s; if (lstat(get_path_buffer(), &s) < 0) { pop_path_buffer(save); error_s("cannot stat '%s'", get_path_buffer()); return; } - + + /* if the file is a directory copy it as a directory, else copy it as a file */ if (S_ISDIR(s.st_mode)) { cp_directory(&s); } else { run_copy(&s); } + /* cleanup */ pop_path_buffer(save); pop_path_buffer_2(save2); } +/** + * Copes file from a src path to a dest path + */ COMMAND(cp_main) { int start, i; struct stat s; + /* define default flags */ flags.hard_link = false; flags.sym_link = false; flags.preserve = false; flags.recurse = false; flags.verbose = false; + /* parse arguments */ start = parse_args(argc, argv, help, short_arg, NULL); + /* if not enough arguments passed show help message and quit */ if (argc - start < 2) { global_help(help); } /* only when 2 args and first is a file, the 2nd will be a file */ if (argc - start == 2) { + + /* if cannot read file info error and exit */ struct stat s; if (lstat(argv[start], &s) < 0) { error("cannot stat '%s'", argv[start]); } + + /* load src and dest into path buffers */ push_path_buffer(argv[argc-2]); push_path_buffer_2(argv[argc-1]); + + /* if the file is a directory copy it as a directory, else copy it as a file */ if (!S_ISDIR(s.st_mode)) { run_copy(&s); } else { cp_directory(&s); } + + /* no need to cleanup path buffers since command is done */ + return EXIT_SUCCESS; } + + /* otherwise treat the dest argument as a directory */ - /* push directory */ + /* push dest directory */ push_path_buffer_2(argv[argc-1]); + /* if we cannot read dest info error and return */ if (lstat(get_path_buffer_2(), &s) < 0) { error("target: '%s'", get_path_buffer_2()); } + /* copy each file into dest directory */ for (i = start; i < argc - 1; i++) { cp_file(argv[i]); } diff --git a/command/dd.c b/command/dd.c index e298c69..d628f9f 100644 --- a/command/dd.c +++ b/command/dd.c @@ -1,8 +1,17 @@ +/** + * file: dd.c + * command: dd + * author: Tyler Murphy + */ + #include "command.h" #include "lslib.h" #include +/** + * Help function for dd + */ static void help(void) { printf("Usage: dd [if=FILE] [of=FILE] [bs=N] [count=N]\n\n"); printf("Copy a file with converting and formatting\n\n"); @@ -12,49 +21,57 @@ static void help(void) { printf("\tcount=N\t\tCopy only N input blocks\n"); } +/** +* Copys a file with converting and formatting +*/ COMMAND(dd_main) { - FILE* in_file = stdin; - FILE* out_file = stdout; - int bs = 1024; - int count = -1; + FILE* in_file = stdin; /* the file to copy from */ + FILE* out_file = stdout; /* the file to copy to */ + int bs = 1024; /* the default bs */ + int count = -1; /* amount of bs's to copy, if negative go until EOF */ int i; - char* buffer; + char* buffer; /* buffer to hold copy data */ size_t read; + /* parse arguments and only check for --help */ parse_help(argc, argv, help); + /* dd doesnt use standard arguments, parse though each argument and match each arg */ for (i = 0; i < argc; i++) { - if (prefix("if=", argv[i])) { - char* path = argv[i] + 3; + if (prefix("if=", argv[i])) { /* sets the input file */ + char* path = argv[i] + 3; /* get data after = */ in_file = get_file(path, "rb"); - } else if (prefix("of=", argv[i])) { - char* path = argv[i] + 3; + } else if (prefix("of=", argv[i])) { /* sets the output file */ + char* path = argv[i] + 3; /* get data after = */ out_file = get_file(path, "wb"); - } else if (prefix("bs=", argv[i])) { - char* str = argv[i] + 3; - bs = get_number(str); - if (bs < 1) { + } else if (prefix("bs=", argv[i])) { /* sets the blocksize */ + char* str = argv[i] + 3; /* get data after = */ + bs = get_blkm(str); + if (bs < 1) { /* cannot have a negative bs */ error("block size must be greater than 0"); } - } else if (prefix("count=", argv[i])) { - char* str = argv[i] + 6; + } else if (prefix("count=", argv[i])) { /* sets the count of bs to do */ + char* str = argv[i] + 6; /* get data after = */ count = get_number(str); if (count < 1) { error("count must be greather than 0"); } - } else { + } else { /* error and exit since arg is invalid */ error("unkown option %s", argv[i]); } } - + + /* allocate buffer of set bs */ buffer = xalloc(bs); + /* read data until EOF from and to buf */ while ((read = fread(buffer, 1, bs, in_file)) != 0) { fwrite(buffer, 1, read, out_file); if (--count, count == 0) break; } + /* cleanup */ free(buffer); fclose(in_file); fclose(out_file); diff --git a/command/echo.c b/command/echo.c index 49008da..396a0f4 100644 --- a/command/echo.c +++ b/command/echo.c @@ -1,31 +1,47 @@ +/** + * file: echo.c + * command: echo + * author: Tyler Murphy + */ + #include "command.h" #include "lslib.h" #include +/** + * Flags that are to be used with echo + */ static struct { bool escape_codes; bool newline; } flags; +/** + * Prints a null terminated string to standard out and changes each char based on input flags + * @param str the string to print + */ static void print_with_escape_codes(const char* str) { - size_t index = 0; - char n; + size_t index = 0; /* current index in the string */ + char c; /* current char being read */ + char n; /* next char being read */ while (true) { - char c = str[index]; + c = str[index]; /* read current char */ index++; - if (c == '\0') break; - if (c != '\\') { + if (c == '\0') break; /* if we hit the NUL, break */ + if (c != '\\') { /* if its not a escaped code, print and continue */ putchar(c); continue; } + /* read next character */ n = str[index]; index++; + /* check each char against the valid escape codes */ switch (n) { case '\\': putchar('\\'); @@ -47,13 +63,19 @@ static void print_with_escape_codes(const char* str) { case 'v': putchar('\v'); break; - default: + default: /* if none found print both chars as is */ putchar(c); putchar(n); } } } +/** + * Takes in each argument that has a single - and parses it + * @param c the character after the - + * @param next the next argument in argv that hasnt been parsed + * @reutrn if the next arg was used or if the arg was invalid + */ static int short_arg(char c, char* next) { UNUSED(next); switch (c) { @@ -74,19 +96,26 @@ static int short_arg(char c, char* next) { return ARG_UNUSED; } +/** + * Prints data in each argument to stdout + */ COMMAND(echo_main) { int start, i; + /* if no arguments supplied exit */ if (argc < 1) { - return EXIT_SUCCESS; + return EXIT_FAILURE; } + /* set default flags */ flags.escape_codes = false; flags.newline = true; + /* parse arguments, no help message */ start = parse_args(argc, argv, NULL, short_arg, NULL); + /* for each argument either print as is or parse each character for escape codes */ for (i = start; i < argc; i++) { if (flags.escape_codes) { print_with_escape_codes(argv[i]); @@ -94,14 +123,17 @@ COMMAND(echo_main) { printf("%s", argv[i]); } + /* put a space seperator between arguments */ if (i + 1 != argc) { putchar(' '); } } + /* if set to put a new line at the end (default), do so */ if (flags.newline) { putchar('\n'); } + /* done */ return EXIT_SUCCESS; } diff --git a/command/ed.c b/command/ed.c index f839258..bdd69ab 100644 --- a/command/ed.c +++ b/command/ed.c @@ -53,7 +53,7 @@ static bool read_regex(char** end, re_t* regex, enum RegexDirection dir) { while(true) { c = *(index++); if (c == '\0') { - error_s("missing regex after %c\n", dir == BEFORE ? '?' : '/'); + error_s("missing regex after %c", dir == BEFORE ? '?' : '/'); return false; } if (c == (dir == BEFORE ? '?' : '/')) { @@ -186,7 +186,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a) n_pre = -1; } else { if (n_pre < 0) { - error_s("input cannot be negative\n"); + error_s("input cannot be negative"); return false; } index = end_pre; @@ -222,7 +222,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a) } if (address.data.index.i < 0) { - error_s("line number %ld does not exist\n", address.data.index.i + 1); + error_s("line number %ld does not exist", address.data.index.i + 1); return false; } @@ -236,7 +236,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a) n = strtol(index, &end, 10) - 1; if (n < 0) { - error_s("input cannot be negative\n"); + error_s("input cannot be negative"); return false; } if (index == end) { @@ -245,7 +245,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a) address.data.index.i = line_current + n; } if (address.data.index.i >= (long int) line_count) { - error_s("line number %ld does not exist\n", address.data.index.i + 1); + error_s("line number %ld does not exist", address.data.index.i + 1); return false; } break; @@ -281,7 +281,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a) address.data.index.i = n_pre; } if (address.data.index.i < 0 || address.data.index.i >= (long int) line_count) { - error_s("line number %ld does not exist\n", address.data.index.i + 1); + error_s("line number %ld does not exist", address.data.index.i + 1); return false; } } @@ -437,7 +437,7 @@ static bool handle_append(struct LineAddress* address) { unsigned long cap, size; if (address->type != INDEX) { - error_s("append command requires index addressing\n"); + error_s("append command requires index addressing"); return false; } @@ -449,7 +449,7 @@ static bool handle_append(struct LineAddress* address) { if (size > 0) { append_lines(address->data.index.i + 1, buf, size); - printf("ed: appened %lu lines\n", size); + output("appened %lu lines", size); } line_current += size; @@ -459,22 +459,22 @@ static bool handle_append(struct LineAddress* address) { static bool handle_delete(struct LineAddress* address) { if (address->empty && address->data.index.i >= (long int) line_count) { - error_s("line number %ld does not exist\n", address->data.index.i + 1); + error_s("line number %ld does not exist", address->data.index.i + 1); return false; } if (address->type == INDEX) { delete_lines(address->data.index.i, address->data.index.i); - output("deleted line %ld\n", address->data.index.i+1); + output("deleted line %ld", address->data.index.i+1); } else if (address->type == RANGE) { delete_lines(address->data.range.a, address->data.range.b); - output("deleted lines %ld-%ld\n", address->data.range.a+1, address->data.range.b+1); + output("deleted lines %ld-%ld", address->data.range.a+1, address->data.range.b+1); } else if (address->type == SET) { unsigned long i; for (i = 0; i < address->data.set.s; i++) { delete_lines(address->data.set.b[i], address->data.set.b[i]); } - output("deleted %lu lines\n", address->data.set.s); + output("deleted %lu lines", address->data.set.s); } return true; @@ -485,7 +485,7 @@ static bool get_file_name(char** filename) { if (len < 1 || (len == 1 && **filename == '\n')) { if (default_filename == NULL) { - error_s("no default filename specified\n"); + error_s("no default filename specified"); return false; } *filename = default_filename; @@ -510,7 +510,7 @@ static void write_file(char* filename, struct LineAddress* address, char* type) int wrote; if (line_count < 1) { - error_s("cannot write empty file\n"); + error_s("cannot write empty file"); return; } @@ -546,7 +546,7 @@ static void write_file(char* filename, struct LineAddress* address, char* type) pending_writes = false; fclose(file); - output("wrote %d lines from %s\n", wrote, filename); + output("wrote %d lines from %s", wrote, filename); } static void read_file(char* filename) { @@ -566,7 +566,7 @@ static void read_file(char* filename) { if (size < 1) { free(buf); - error_s("attempted to read a empty file\n"); + error_s("attempted to read a empty file"); return; } @@ -577,7 +577,7 @@ static void read_file(char* filename) { append_lines(line, buf, size); free(buf); - output("read and appended %lu lines from %s\n", size, filename); + output("read and appended %lu lines from %s", size, filename); } static void expand_string(char** buf, int* capacity, int* size, char* text, int len) { @@ -650,7 +650,7 @@ static void prompt(void) { struct LineAddress address2; if (address.type != INDEX) { - error_s("comma range addressing requires two index addresses\n"); + error_s("comma range addressing requires two index addresses"); free_address(address); return; } @@ -663,7 +663,7 @@ static void prompt(void) { } if (address2.type != INDEX) { - error_s("comma range addressing requires two index addresses\n"); + error_s("comma range addressing requires two index addresses"); free_address(address); free_address(address2); return; @@ -677,7 +677,7 @@ static void prompt(void) { } if (address.type == RANGE && address.data.range.a > address.data.range.b) { - error_s("range addressing must be in ascending order\n"); + error_s("range addressing must be in ascending order"); free_address(address); return; } @@ -690,10 +690,10 @@ test: case '\n': if (address.empty) { if (line_current == line_count) { - error_s("line number %ld does not exist\n", line_current + 1); + error_s("line number %ld does not exist", line_current + 1); break; } else if (line_current + 1 == line_count) { - error_s("line number %ld does not exist\n", line_current + 2); + error_s("line number %ld does not exist", line_current + 2); break; } else { line_current++; @@ -706,7 +706,7 @@ test: } else if (address.type == RANGE) { line_current = address.data.range.b; } else if (address.type == SET) { - error_s("unexpected range addressing\n"); + error_s("unexpected range addressing"); break; } printf("%s", lines[line_current]); @@ -728,7 +728,7 @@ test: __attribute__((fallthrough)); case 'p': if (address.empty && address.data.index.i >= (long int) line_count) { - error_s("line number %ld does not exist\n", address.data.index.i + 1); + error_s("line number %ld does not exist", address.data.index.i + 1); break; } if (address.type == INDEX) { @@ -779,17 +779,17 @@ test: skip_whitespace(&index); if (*(index++) != '/') { - error_s("unexpected character at start of regex\n"); + error_s("unexpected character at start of regex"); break; } if (!parse_regex_lines(&index, &address)) { return; } while(*index != '\0' && *index != '/') index++; if (*index != '/') { - error_s("/ missing after %c\n", *index); + error_s("/ missing after %c", *index); break; } if (address.data.set.s < 1) { - error_s("no matches found\n"); + error_s("no matches found"); break; } *(index++) = '\0'; @@ -801,11 +801,11 @@ test: char* end; matches = strtol(index, &end, 10); if (end == index) { - error_s("invalid number: %s\n", index); + error_s("invalid number: %s", index); break; } if (matches < 1) { - error_s("matches cannot be less than 1\n"); + error_s("matches cannot be less than 1"); break; } } @@ -815,7 +815,7 @@ test: for (i = 0; i < address.data.set.s; i++) { matches_found += substute_string(address.data.set.b[i], matches, last_regex, replace, sub_len); } - output("replaced %ld matches over %ld lines\n", matches_found, address.data.set.s); + output("replaced %ld matches over %ld lines", matches_found, address.data.set.s); pending_writes = true; break; } @@ -865,7 +865,7 @@ test: printf("%ld\n", line_current + 1); break; default: - error_s("unimplemented command\n"); + error_s("unimplemented command"); break; }