From 354a52e1fdbc8f1e30a761c87eefe9e169d399bf Mon Sep 17 00:00:00 2001 From: Kat Richey Date: Thu, 6 Oct 2022 02:12:56 -0500 Subject: [PATCH] Wow, documentation! --- asa.c | 34 +++++++++++++++++++++++++++------- basename.c | 40 +++++++++++++++++++++++++++++++++++++++- cat.c | 15 +++++++++++++++ cksum.c | 24 ++++++++++++++++++++++-- dirname.c | 9 +++++++++ 5 files changed, 112 insertions(+), 10 deletions(-) diff --git a/asa.c b/asa.c index e8d1505..e7643d0 100755 --- a/asa.c +++ b/asa.c @@ -9,25 +9,42 @@ int main(int argc, char ** argv) { char c, c_temp; for(i = 1; i < argc; i++) { - if(argv[i][0] == '-' && argv[i][1] == '\0') + /* If - is passed as an argument, set the input file to stdin */ + if(argv[i][0] == '-' && argv[i][1] == '\0') { in_file = stdin; + } else { + /* Open the file given */ in_file = fopen(argv[i], "r"); if(in_file == NULL) { + /* If it can't open, set that we encountered an error */ + /* + TODO: this should probably check errno instead of + assuming that we can't find the file + */ fprintf(stderr, "Cannot find file %s\n", argv[i]); error = 1; continue; } } + /* + Loop through the file line by line, applying transformations based on + the first character of the line, as given by the POSIX spec. + */ eof_reached = 0; while(!eof_reached) { c = fgetc(in_file); + /* + Get the first character of the line and print the right thing + */ switch(c) { - case '1': printf("\f"); break; - case '0': printf("\n"); break; - case '+': printf("\r"); break; - case EOF: eof_reached = 1; continue; + case '1': printf("\f"); break; /* Form feed on 1 */ + case '0': printf("\n"); break; /* New line on 0 */ + case '+': printf("\r"); break; /* Carriage return on + */ + case EOF: eof_reached = 1; continue; /* Leave on EOF */ + /* Anything else, don't do anything */ } + /* Print out the rest of the line unless we hit an EOF, where we quit. */ for(c_temp = fgetc(in_file); c_temp != '\n'; c_temp = fgetc(in_file)) { if(c_temp == EOF) { eof_reached = 1; @@ -40,8 +57,11 @@ int main(int argc, char ** argv) { printf("\n"); } - if(error) + /* If we ever hit an error, return 1. */ + if(error) { return 1; - else + } + else { return 0; + } } diff --git a/basename.c b/basename.c index fba1b1f..fe1d4a1 100755 --- a/basename.c +++ b/basename.c @@ -10,6 +10,15 @@ int main(int argc, char ** argv) { int basename_length = 0, last_slash = 0; int suffix_length = 0; + /* + Basename takes two arguments, one for the path itself and an optional + one for a suffix to remove (e.g. ".c" to remove the C file extension). + Here, we check for that second argument to determine if we need to + remove an extension. + + If there aren't multiple arguments, check if a path was even given. If + not, the POSIX spec says to just return a newline. + */ if(argc > 2) { suffix_present = 1; } @@ -18,6 +27,9 @@ int main(int argc, char ** argv) { return 0; } + /* + If the path is just //, the POSIX spec also says to return newline + */ if(strcmp(argv[1], "//") == 0) { printf("\n"); return 0; @@ -25,16 +37,25 @@ int main(int argc, char ** argv) { i = 0; + /* + Find the end of the path (probably could've just used strlen) + */ for(c = argv[1][i]; c != '\0'; c = argv[1][i]) { i++; } + /* + If the last character of the path is /, then remove it + */ if(argv[1][i-1] == '/') { argv[1][i-1] = '\0'; } i = 0; + /* + Find the last slash in the path + */ for(c = argv[1][i]; c != '\0'; c = argv[1][i]) { if(c == '/') { last_slash = i; @@ -44,10 +65,16 @@ int main(int argc, char ** argv) { i = last_slash + 1; + /* + Figure out how long the basename is + */ for(c = argv[1][i]; c != '\0'; c = argv[1][i]) { basename_length++; i++; } + /* + Allocate memory for the basename; fail out if we can't + */ basename = calloc(basename_length + 1, sizeof(*basename)); if(basename == NULL) { fprintf(stderr, "%s: Could not allocate sufficient memory\n", argv[0]); @@ -56,13 +83,21 @@ int main(int argc, char ** argv) { i = last_slash + 1; + /* + Transfer the basename to the array + */ for(c = argv[1][i]; c != '\0'; c = argv[1][i]) { basename[i - (last_slash + 1)] = c; i++; } - basename[basename_length] = '\0'; + basename[basename_length] = '\0'; /* don't forget the null! */ + /* + If we need to remove a suffix, check if the end of the string is + actually equal to the suffix and, if it is, replace the first character + of the suffix with a null character. + */ if(suffix_present && strcmp(basename, argv[2]) != 0) { i = 0; for(c = argv[2][i]; c != '\0'; c = argv[2][i]) { @@ -84,6 +119,9 @@ int main(int argc, char ** argv) { } } + /* + Print the basename, free the memory, and quit! + */ printf("%s\n", basename); free(basename); diff --git a/cat.c b/cat.c index 3ccd213..b9726e1 100755 --- a/cat.c +++ b/cat.c @@ -12,17 +12,28 @@ int main(int argc, char *argv[]) { int error_occurred; + /* + Check for -u and use unbuffered output if present + */ while((c = getopt(argc, argv, "u")) != -1) { if(c == 'u') { using_unbuffered_output = 1; } } + /* + Set unbuffered output. We do this for both stdin and stdout, let setvbuf + allocate the buffer (that we don't need), _IONBF tells it to not buffer, + and we just say 15 character buffer because, well, eh, who cares? + */ if(using_unbuffered_output) { setvbuf(stdin, NULL, _IONBF, 15); setvbuf(stdout, NULL, _IONBF, 15); } + /* + If no input files were given, just open up stdin + */ if(argc == 1 || optind == argc) { cur_in_file = stdin; for(c = fgetc(cur_in_file); c != EOF; c = fgetc(cur_in_file)) { @@ -31,6 +42,10 @@ int main(int argc, char *argv[]) { fclose(cur_in_file); } + /* + Open up each file given (or stdin if - was given), print it to stdout, + then close it and move to the next while there are still files + */ for(i = optind; i < argc; i++) { if(argv[i][0] == '-' && argv[i][1] == '\0') { cur_in_file = stdin; diff --git a/cksum.c b/cksum.c index 72acd4e..eaee526 100755 --- a/cksum.c +++ b/cksum.c @@ -6,6 +6,10 @@ unsigned int crc32(FILE * in_file); int count_octets(FILE * in_file); +/* + I think this can technically be computed (don't quote me on that), but it's + easier and faster to implement it as a lookup table. +*/ unsigned int crc32_table[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, @@ -77,14 +81,20 @@ int main(int argc, char ** argv) { int i, error = 0; FILE *in_file; + /* + Open each file (set that we encountered an error if we couldn't) then + print the CRC32 checksum and number of octets in the file. + */ for(i = 1; i < argc; i++) { in_file = fopen(argv[i], "r"); if(in_file == NULL) { error = 1; fprintf(stderr, "Cannot find file %s\n", argv[i]); } - else + else { printf("%u %d %s\n", crc32(in_file), count_octets(in_file), argv[i]); + fclose(in_file); + } } if(error) @@ -95,27 +105,37 @@ int main(int argc, char ** argv) { /* Based off the CRC-32 psuedocode implementation on the Wikipedia article for CRC */ unsigned int crc32(FILE * in_file) { + /* the CRC starts off as 0xFFFFFFFF */ unsigned int crc = 0xffffffff; int nLookupIndex; char c; + /* Make sure we're at the start of the file */ fseek(in_file, 0, SEEK_SET); + /* + For each character, set nLookupIndex to CRC XOR that character ANDed with + 256, then set the CRC to a new value by right-shifting it 8 and XORing with + the appropriate value from the lookup table + */ for(c = fgetc(in_file); c != EOF; c = fgetc(in_file)) { nLookupIndex = (crc ^ c) & 0xff; crc = (crc >> 8) ^ crc32_table[nLookupIndex]; } + /* When all's said and done, invert all the bits and return. */ crc ^= 0xffffffff; return crc; } int count_octets(FILE * in_file) { int total_octets = 0; - char c; + char c; /* I may be assuming 8-bit character...uh... */ + /* Ensure we're at the start */ fseek(in_file, 0, SEEK_SET); + /* Count the octets, one by one. There may be an easier way, but eh. */ for(c = fgetc(in_file); c != EOF; c = fgetc(in_file)) total_octets++; diff --git a/dirname.c b/dirname.c index d4ca49a..e72965c 100755 --- a/dirname.c +++ b/dirname.c @@ -6,41 +6,50 @@ int main(int argc, char ** argv) { int i, last_slash = -1, length; + /* If no path given, print / per the POSIX spec */ if(argc == 1) { printf("/\n"); return 0; } + /* Same if // is given */ if(strcmp(argv[1], "//") == 0) { printf("/\n"); return 0; } + /* Oh, look, we use strlen here. */ length = strlen(argv[1]); + /* Replace terminal slash (if present) with null */ if(argv[1][length - 1] == '/') { argv[1][length - 1] = '\0'; } + /* Find last slash */ for(i = 0; i < length; i++) { if(argv[1][i] == '/') { last_slash = i; } } + /* If we didn't find a slash, assume PWD per POSIX spec */ if(last_slash == -1) { printf(".\n"); return 0; } + /* Replace last slash with null to truncate basename */ argv[1][last_slash] = '\0'; + /* If the dirname is //, /, or blank, print a single slash. */ if(strcmp(argv[1], "//") == 0 || strcmp(argv[1], "") == 0 || strcmp(argv[1], "/") == 0) { printf("/\n"); return 0; } + /* Remove any trailing slashes from the dirname */ for(i = last_slash - 1; argv[1][i] == '/'; i--) { argv[1][i] = '\0'; }