From 67173fb97117a41cebb82a1364ae686a9574927b Mon Sep 17 00:00:00 2001 From: Tyler Murphy Date: Tue, 16 May 2023 19:15:01 -0400 Subject: [PATCH] slight refactor and start documenting --- command/cat.c | 89 +++++++----- command/chmod.c | 122 +++++++++++----- command/chown.c | 123 +++++++++++----- command/ls.c | 17 ++- lib/convert.c | 63 -------- lib/lslib.h | 376 +++++++++++++++++++++++++++++++++++++++++++----- lib/string.c | 79 ++++++++++ 7 files changed, 655 insertions(+), 214 deletions(-) create mode 100644 lib/string.c diff --git a/command/cat.c b/command/cat.c index f88ca28..8a87369 100644 --- a/command/cat.c +++ b/command/cat.c @@ -1,27 +1,28 @@ +/** + * file: cat.c + * author: Tyler Murphy + */ + #include "command.h" #include "lslib.h" #include #include +/** + * Flags that are to be used with cat + */ static struct { - bool number_lines; - bool number_non_empty; - bool change_non_print; - bool change_tabs; - bool end_lines_dollar; + bool number_lines; /* if to number the lines */ + bool number_non_empty; /* if to number empty lines */ + bool change_non_print; /* if to change non printable characters to be printable */ + bool change_tabs; /* if to change tabs to ^I */ + bool end_lines_dollar; /* if to print a $ at the end of lines */ } flags; -static bool printable(char c) { - switch (c) { - case '\n': return true; - case '\r': return true; - case '\b': return true; - case '\t': return true; - default: return isprint(c) == 0; - } -} - +/** + * Help function for cat + */ static void help(void) { printf("Usage: cat [-nbvteA] [FILE]...\n\n"); printf("Print FILEs to stdout\n\n"); @@ -33,52 +34,68 @@ static void help(void) { printf("\t-A Same as -vte\n"); } +/** + * Give a file pointer, cat all its contents + * @param file the file to cat + */ static void cat_file(FILE* file) { - char c; - size_t read; + char c; /* current character read */ + size_t read; /* amount read */ - size_t line = 1; - bool empty = true; - bool newline = true; + /* default arguments */ + size_t line = 1; /* what line we are on, 1 indexed */ + bool empty = true; /* if the current line is empty (nothing printed) */ + bool newline = true; /* if we are on a new line */ + /* read file a character at a time */ while ((read = fread(&c, 1, 1, file)) != 0) { + /* if its a new line, update the new line pointer */ if (c == '\n') { - if (empty && flags.number_lines) { + if (empty && flags.number_lines) { /* print line number if set to */ printf("\t%ld ", line); } - if (flags.end_lines_dollar) { + if (flags.end_lines_dollar) { /* pint $ if set to */ printf("$"); } line++; - newline = true; - empty = true; + newline = true; /* tell that the new line number is set to be printed */ + empty = true; /* set line to empty */ goto print; } else { empty = false; } - + + /* skip next check if not newline */ if (!newline) { goto print; } + /* if on a new line and is a valid char, print line number */ if (!empty && (flags.number_non_empty || flags.number_lines)) { printf("\t%ld ", line); newline = false; } print: - if (!flags.change_non_print || printable(c)) { + /* print character */ + if (!flags.change_non_print || printable_char(c)) { if (flags.change_tabs && c == '\t') { - fwrite("^I", 1, 2, stdout); + fwrite("^I", 1, 2, stdout); /* print ^I instead of tab */ } else { - fwrite(&c, 1, 1, stdout); + fwrite(&c, 1, 1, stdout); /* print character to stdout */ } - } else { + } else { /* if set to change non print, fix char code */ c |= '@'; fwrite(&c, 1, 1, stdout); } } } +/** + * 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) { @@ -110,33 +127,41 @@ static int short_arg(char c, char* next) { return ARG_UNUSED; } +/** + * Output a files contents + */ COMMAND(cat_main) { int start; int arg_len; int i; + /* set flag defaults */ flags.number_lines = false; flags.number_non_empty = false; flags.change_non_print = false; flags.change_tabs = false; flags.end_lines_dollar = false; + /* parse user arguments */ start = parse_args(argc, argv, help, short_arg, NULL); + /* get the number of arguments to cat */ arg_len = argc - start; + /* if not read from stdin */ if (arg_len < 1) { cat_file(stdin); return EXIT_SUCCESS; } + /* foreach file, try to open it, and then cat it */ for (i = start; i < argc; i++) { - FILE* in = get_file(argv[i], "r"); - cat_file(in); + FILE* in = get_file(argv[i], "r"); /* open file as read */ + cat_file(in); /* print it out */ if (in != stdin) fclose(in); } - return EXIT_SUCCESS; + return EXIT_SUCCESS; /* success */ } diff --git a/command/chmod.c b/command/chmod.c index eabb91c..8bf6aab 100644 --- a/command/chmod.c +++ b/command/chmod.c @@ -1,3 +1,8 @@ +/** + * file: chmod.c + * author: Tyler Murphy + */ + #include "command.h" #include "lslib.h" @@ -8,21 +13,30 @@ #include #include +/** + * If to add remove or directly set bits to a file + */ enum method { ADD, SUB, SET }; +/** + * Flags to set in chmod + */ static struct { - bool recurse; - bool list_changed; - bool verbose; - bool quiet; - enum method method; - mode_t mode; + bool recurse; /* if to recurse directorys */ + bool list_changed; /* if to list what was updated */ + bool verbose; /* if to list all output */ + bool quiet; /* if to silence errors */ + enum method method; /* the method to apply to the mode */ + mode_t mode; /* the mode to apply with the method */ } flags; +/** + * Help function for chmod + */ static void help (void) { printf("Usage: chmod [-Rcvf] MODE[,MODE]... FILE...\n\n"); printf("MODE is octal number (bit pattern sstrwxrwxrwx) or {+|-|=}[rwxXst]\n\n"); @@ -32,6 +46,12 @@ static void help (void) { printf("\t-f\tHide errors\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) { @@ -60,23 +80,31 @@ static int short_arg(char c, char* next) { return ARG_UNUSED; } +/** + * Given a file path, modify its mode, and recurse if set to + * @param path the file path to modify + */ static void chmod_file(char* path) { - int save; - struct stat s; - DIR* d; - struct dirent* file; - mode_t mode = 0; + /* allocate arguments on stack */ + int save; /* path buffer save */ + struct stat s; /* file info */ + DIR* d; /* if recursing, open dir */ + struct dirent* file; /* if recursing, file being read */ + mode_t mode = 0; /* silence the uninitalized var error */ + /* add path to path buffer */ save = push_path_buffer(path); + /* get file statics, if failed return */ if (lstat(get_path_buffer(), &s) < 0) { if (!flags.quiet) { - error_s("cannot stat '%s'", get_path_buffer()); + error_s("cannot stat '%s'", get_path_buffer()); /* error if failed */ } pop_path_buffer(save); return; } + /* get the new mode given the method and proved mode */ if (flags.method == SET) { mode = flags.mode;; } else if (flags.method == ADD) { @@ -85,48 +113,60 @@ static void chmod_file(char* path) { mode = s.st_mode & ~flags.mode; } + /* attempt to modify the file mode, error and return if failed */ if (chmod(get_path_buffer(), mode) < 0) { if (!flags.quiet) { - error_s("cannot chmod '%s'", get_path_buffer()); + error_s("cannot chmod '%s'", get_path_buffer()); /* error if failed */ } - pop_path_buffer(save); + pop_path_buffer(save); /* clean up */ return; } else if (flags.list_changed) { - printf("chmod: changed '%s' to %o\n", get_path_buffer(), mode); + output("changed '%s' to %o", get_path_buffer(), mode); /* print if set to be verbose */ } + /* if not set to recurse, dont bother to do future checks */ if (!flags.recurse) { pop_path_buffer(save); return; } + /* if not a dir, cant recurse and then return */ if (!S_ISDIR(s.st_mode)) { pop_path_buffer(save); return; } + /* get the directory, if failed, error and return */ d = opendir(get_path_buffer()); if (d == NULL) { if (!flags.quiet) { - error_s("cannot open dir '%s'", get_path_buffer()); + error_s("cannot open dir '%s'", get_path_buffer()); /* error if failed */ } - pop_path_buffer(save); + pop_path_buffer(save); /* clean up */ return; } + /* chmod each file read */ while ((file = readdir(d)) != NULL) { - if (is_dot_dir(file->d_name)) continue; + if (is_dot_dir(file->d_name)) continue; /* ignore dot dirs */ chmod_file(file->d_name); } + /* clean up */ closedir(d); pop_path_buffer(save); } +/** + * Parse a given mode and its method + * @param input a pointer to the string to check + * @return the mode parsed, mode parsing could not be done if reached , if so call again + */ static mode_t parse_mode(char** input) { - mode_t mode = 00000; - char* str = *input; + mode_t mode = 00000; /* default mode */ + char* str = *input; /* get the input string */ + /* check method for mode */ switch (*str) { case '=': flags.method = SET; @@ -139,69 +179,76 @@ static mode_t parse_mode(char** input) { break; default: flags.method = SET; - mode = get_mode(str); + mode = get_mode(str); /* get mode and skip next checks */ goto end; } -next: +next: /* check what bits to update */ str++; switch (*str) { - case 'r': + case 'r': /* read */ mode |= 00444; goto next; - case 'w': + case 'w': /* read */ mode |= 00200; goto next; - case 'x': + case 'x': /* execute */ mode |= 00111; goto next; - case 'X': + case 'X': /* empty */ mode |= 00000; goto next; - case 's': + case 's': /* setuid and setgid */ mode |= 06000; goto next; - case 't': + case 't': /* sticky */ mode |= 01000; goto next; case '\0': - case ',': + case ',': /* stop reading args */ goto end; default: - error("invalid option: %c", *str); + error("invalid option: %c", *str); /* error when invalid */ } -end: +end: /* read till next argument and update input string pointer */ + while (true) { if (*str == '\0') { - *input = NULL; + *input = NULL; /* no mroe args */ break; } if (*str == ',') { - *input = ++str; + *input = ++str; /* another argument found */ break; } str++; } - return mode; + return mode; /* return mode */ } +/** + * Modify a files permission mode + */ COMMAND(chmod_main) { - int start, i; + int start, i; + /* get default flags */ flags.recurse = false; flags.list_changed = false; flags.verbose = false; flags.quiet = false; flags.mode = 0; + /* parse arguments */ start = parse_args(argc, argv, help, short_arg, NULL); + /* if not arguments error and return */ if (argc - start < 1) { if (!flags.quiet) { error("no mode provided"); @@ -210,10 +257,12 @@ COMMAND(chmod_main) { } } + /* parse mode continusally until no more mode arguments found */ do { flags.mode |= parse_mode(&argv[start]); } while (argv[start] != NULL); + /* if no files found error and return */ if (argc - start < 2) { if (!flags.quiet) { error("no files passed"); @@ -222,9 +271,10 @@ COMMAND(chmod_main) { } } + /* for each file passed, chmod */ for (i = start + 1; i < argc; i++) { chmod_file(argv[i]); } - return EXIT_SUCCESS; + return EXIT_SUCCESS; /* return */ } diff --git a/command/chown.c b/command/chown.c index e78c1d2..7f9cb0f 100644 --- a/command/chown.c +++ b/command/chown.c @@ -1,3 +1,8 @@ +/** + * file: chown.c + * author: Tyler Murphy + */ + #include "command.h" #include "lslib.h" @@ -10,15 +15,21 @@ #include #include +/** + * File flags to be used with chown + */ static struct { - bool recurse; - bool list_changed; - bool verbose; - bool quiet; - uid_t uid; - gid_t gid; + bool recurse; /* -R if to recurse directorys */ + bool list_changed; /* -c if to list what was changed */ + bool verbose; /* -v if to list all output */ + bool quiet; /* -f if to silence errors */ + uid_t uid; /* the uid to set the file to */ + gid_t gid; /* the gid to set the file to */ } flags; +/** + * Help function for chown + */ static void help (void) { printf("Usage: chown [-Rcvf]... USER[:[GRP]] FILE...\n\n"); printf("Change the owner and/or group of FILEs to USER and/or GRP\n\n"); @@ -28,6 +39,12 @@ static void help (void) { printf("\t-f\tHide errors\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) { @@ -49,68 +66,86 @@ static int short_arg(char c, char* next) { return ARG_UNUSED; } +/** + * Given a file path change the filw ownership with the given flags + * @param path the file to change the ownership + */ static void chown_file(char* path) { - int save; - struct stat s; - DIR* d; - struct dirent* file; + + /* allocate arguments on the stack */ + int save; /* path buffer save */ + struct stat s; /* file stats */ + DIR* d; /* recursing dir if recursing */ + struct dirent* file; /*if recursing current file being read */ save = push_path_buffer(path); + /* attempt to change file ownership, if failed error and return */ if (chown(get_path_buffer(), flags.uid, flags.gid) < 0) { if (!flags.quiet) { - error_s("cannot chown '%s'", get_path_buffer()); + error_s("cannot chown '%s'", get_path_buffer()); /* error if failed */ } - pop_path_buffer(save); + pop_path_buffer(save); /* cleanup */ return; - } else if (flags.list_changed) { - printf("chown: changed '%s' to %u:%u\n", get_path_buffer(), flags.uid, flags.gid); + } else if (flags.list_changed) { /* list changed if verbose */ + output("changed '%s' to %u:%u", get_path_buffer(), flags.uid, flags.gid); } + /* if not recurse dont do future checks and return */ if (!flags.recurse) { pop_path_buffer(save); return; } + /* stat file info and return if failed */ if (lstat(get_path_buffer(), &s) < 0) { if (!flags.quiet) { - error_s("cannot stat '%s'", get_path_buffer()); + error_s("cannot stat '%s'", get_path_buffer()); /* error if failed */ } - pop_path_buffer(save); + pop_path_buffer(save); /* clean up */ return; } + /* if not dir, cannot recurse so return */ if (!S_ISDIR(s.st_mode)) { - pop_path_buffer(save); + pop_path_buffer(save); /* clean up */ return; } + /* open dir, if failed return and error */ d = opendir(get_path_buffer()); if (d == NULL) { if (!flags.quiet) { - error_s("cannot open dir '%s'", get_path_buffer()); + error_s("cannot open dir '%s'", get_path_buffer()); /* error if failed */ } - pop_path_buffer(save); + pop_path_buffer(save); /* clean up */ return; } + /* read each file in directory, and modify its ownership recursivly */ while ((file = readdir(d)) != NULL) { - if (is_dot_dir(file->d_name)) continue; + if (is_dot_dir(file->d_name)) continue; /* if dot dir skip */ chown_file(file->d_name); } + /* clean up */ closedir(d); pop_path_buffer(save); } +/** + * Parse a given user and group from a string + * @param str the stirng to parse + */ static void parse_ownership(char* str) { - char* user = str; - char* group = NULL; - char* end = NULL; - unsigned long i; - struct passwd* p = NULL; - struct group* g = NULL; - + char* user = str; /* a copy of the input string */ + char* group = NULL; /* the group name found in str */ + char* end = NULL; /* the end of a string to parse a number if passed */ + unsigned long i; /* a number i */ + struct passwd* p = NULL; /* a user if found */ + struct group* g = NULL; /* a group if found */ + + /* attempy to find a colon seperating the user and group in the string, if not parse it as a user only */ for (i = 0; i < strlen(str); i++) { if (str[i] == ':') { str[i] = '\0'; @@ -119,33 +154,38 @@ static void parse_ownership(char* str) { } } + /* attempt to parse input as a number */ flags.uid = strtol(user, &end, 10); - if (end != user) goto group; + if (end != user) goto group; /* if successfull they ave a direct uid */ + /* if not try to get the user by the string */ if ((p = getpwnam(user)) == NULL) { - error("invalid user '%s'", user); + error("invalid user '%s'", user); /* error and abort if failed */ } else { - flags.uid = p->pw_uid; + flags.uid = p->pw_uid; /* update flags */ } group: + /* if the group string was not found set the gorup to the user */ if (group == NULL) { if (p == NULL) { - flags.gid = flags.uid; + flags.gid = flags.uid; /* if a int was passed set that int to the group as well */ } else { - flags.gid = p->pw_gid; + flags.gid = p->pw_gid; /* if a user was passed set the group to the users gid */ } return; } + /* if a group was passed, attempt to parse it as a gid first */ flags.gid = strtol(group, &end, 10); - if (end != group) return; + if (end != group) return; /* if succssfull return were done */ + /* otherwise try to get the group from the name */ if ((g = getgrnam(group)) == NULL) { - error("invalid group '%s'", group); + error("invalid group '%s'", group); /* error and abort if failed */ } else { - flags.gid = g->gr_gid; + flags.gid = g->gr_gid; /* update gid */ } } @@ -153,15 +193,18 @@ COMMAND(chown_main) { int start, i; + /* set default flags for chown */ flags.recurse = false; flags.list_changed = false; flags.verbose = false; flags.quiet = false; + /* parse argument */ start = parse_args(argc, argv, help, short_arg, NULL); + /* if no more arguments error and abort since no ownership passed */ if (argc - start < 1) { - if (!flags.quiet) { + if (!flags.quiet) { /* if not set to hide errors */ error("no onwership passed"); } else { return EXIT_FAILURE; @@ -170,17 +213,19 @@ COMMAND(chown_main) { parse_ownership(argv[start]); + /* if not more arugumnets error and abort since no files passed */ if (argc - start < 1) { - if (!flags.quiet) { - error("no files passed"); + if (!flags.quiet) { /* if not set to hide errors */ + error("no files passed"); } else { return EXIT_FAILURE; } } + /* change ownership for each file passed */ for (i = start + 1; i < argc; i++) { chown_file(argv[i]); } - return EXIT_SUCCESS; + return EXIT_SUCCESS; /* done */ } diff --git a/command/ls.c b/command/ls.c index 788f2ff..f40cdf3 100644 --- a/command/ls.c +++ b/command/ls.c @@ -1,3 +1,8 @@ +/** + * file: ls.c + * author: Tyler Murphy + */ + #include "command.h" #include "lslib.h" @@ -37,12 +42,12 @@ enum When { * Flags that are to be used with ls */ static struct { - bool hidden; /* -a */ - bool hide_dot; /* -A */ - bool more_info; /* -l */ - bool one_column; /* -1 */ - bool recurse; /* -R */ - bool octets; /* -o */ + bool hidden; /* -a if to show hidden files */ + bool hide_dot; /* -A if to hide dot dirs */ + bool more_info; /* -l if to print info as a long list */ + bool one_column; /* -1 if to print files as a single column */ + bool recurse; /* -R if to recurse directorys */ + bool octets; /* -o if to print mode as its octet instead of romanized */ enum When colored; /* --color=never/no/yes/always/auto */ } flags; diff --git a/lib/convert.c b/lib/convert.c index c3e011d..899b5fd 100644 --- a/lib/convert.c +++ b/lib/convert.c @@ -67,66 +67,3 @@ bool prefix(const char* pre, const char* str) { return strncmp(pre, str, strlen(pre)) == 0; } -static char fs_types[5] = {'K','M','G','T','P'}; -void print_file_size(size_t bytes, char buf[5]) { - int index, n; - float next; - - index = 0; - next = bytes; - - while (true) { - if (next < 1000) { - break; - } - - if (index == 5) { - printf("999P"); - return; - } - - next /= 1024; - index++; - } - - n = snprintf(buf, 4, "%u", (int)(next+.5)); - - if (index > 0) { - buf[n] = (fs_types[index - 1]); - n++; - } - - buf[n] = '\0'; -} - -static char* months[12] = - {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; -void print_date_time(time_t mills, char buf[13]) { - struct tm* info; - int n; - - info = localtime(&mills); - n = snprintf(buf, 5, "%s ", months[info->tm_mon]); - - if (info->tm_mday < 10) { - buf[n] = ' '; - n++; - } - - snprintf(buf + n, 13 - n, "%d %02d:%02d ", info->tm_mday, info->tm_hour, info->tm_sec); -} - -void print_file_path(char* path) { - if (streql("-", path)) { - printf("(standard input)"); - } else { - printf("%s", path); - } -} - -void nuke_str(char* type) { - *type = 0; - while(*(++type)) { - *type = 0; - } -} diff --git a/lib/lslib.h b/lib/lslib.h index 0836e44..e31f5b1 100644 --- a/lib/lslib.h +++ b/lib/lslib.h @@ -1,3 +1,8 @@ +/** + * file: lslib.h + * author: Tyler Murphy + */ + #ifndef SHARED_H #define SHARED_H @@ -6,9 +11,9 @@ #include #include - -#define ANSCII "\x1b[" -#define NEXT ";" +/* create define flags to be used with color anscii codes */ +#define ANSCII "\x1b[" /* anscii start escape code */ +#define NEXT ";" /* anscii seperator */ #define RESET "0" #define BOLD "1" @@ -26,119 +31,414 @@ #define TURQUOISE "6" #define WHITE "7" -#define COLOR "m" - +#define COLOR "m" /* color anscii code */ +/** + * Define bool cause c89 dont have it + */ typedef uint8_t bool; #define true 1 #define false 0 - +/* mark argument unused */ #define UNUSED(x) (void)(x) -#define ARG_UNUSED 0 -#define ARG_USED 1 -#define ARG_IGNORE 2 -#define ARG_INVALID 3 +/* + * Flags to return from parse_args fn pointers + */ +#define ARG_UNUSED 0 /* state that the next char* wasnt used */ +#define ARG_USED 1 /* state that the next char* was used */ +#define ARG_IGNORE 2 /* stop parsing arguments */ +#define ARG_INVALID 3 /* print error message and die */ + +/* + * Die is argument is null + * @param arg argument to check + */ void check_arg (char* arg); + +/** + * Print help message with lazysphere title then exit + * @param help fn pointer to call to display fn specific help msg + */ void global_help(void (*help)(void)); + +/** + * Parse arguments and only check for --help message otherwise do nothing + * @param argc argument count + * @param argv argument data + * @param help fn pointer to call and display fn specific help msg + */ void parse_help (int argc, char** argv, void (*help)(void)); + +/** + * Parse arguments with given short and long arg pointers, and call help fn if --help supplied + * @param argv argument count + * @param argv argument data + * @param help fn pointer to call and display fn specific help msg + * @param short_arg fn pointer to check char after a -, 2nd char* is the next unparsed argv for something like -s [str] + * @param long_arg fn pointer to check string after a --, 2nd char* is the next unparsed argv for something like --string [str] + * @returns argc where arguments ended + */ int parse_args (int argc, char** argv, void (*help)(void), int (*short_arg)(char, char*), int (*long_arg)(char*, char*)); - +/* + * Open a file with a given path and type, and print error if failed + * @param path the path to the file + * @param type the mode to open the file with + * @return the file pointer if opened, NULL if failed + */ FILE* get_file_s(const char* path, const char* type); + +/* + * Open a file with a given path and type, and print error and die if failed + * @param path the path to the file + * @param type the mode to open the file with + * @return the file pointer + */ FILE* get_file(const char* path, const char* type); + +/** + * Open a tty and error and die if failed + * @return the file descripter to the tty + */ int get_tty(void); + +/** + * Open a tty stream with the given mode and error and die if failed + * @param type the mode to open the tty with + * @return the file pointer to the tty + */ FILE* get_tty_stream(char* type); -void nuke_str(char* type); - +/** + * Get a reference to the first path buffer + * @return the pointer to the first path buffer + */ char* get_path_buffer(void); + +/** + * Push a string to the first path buffer, a / as added before string if it doesnt allready exist at the end + * @param stirng the local file path to push to the first path buffer + * @return the integer index to revert to then done + */ int push_path_buffer(const char* string); + +/** + * Revert the first path buffer to the index provided by push_path_buffer + * @param i the index to revert to + */ void pop_path_buffer(int i); +/** + * Get a reference to the second path buffer + * @return the pointer to the second path buffer + */ char* get_path_buffer_2(void); + +/** + * Push a string to the second path buffer, a / as added before string if it doesnt allready exist at the end + * @param stirng the local file path to push to the first path buffer + * @return the integer index to revert to then done + */ int push_path_buffer_2(const char* string); + +/** + * Revert the second path buffer to the index provided by push_path_buffer_2 + * @param i the index to revert to + */ void pop_path_buffer_2(int i); - - +/** + * Get a base 10 number from a string and error and die if failed + * @param text the string that contains the number + * @return the parsed integer if successfull + */ long int get_number(const char* text); + +/** + * Get a blkm (1024m, 38b, 26G) from a string and error and die if failed + * @param text the string that contains the blkm + * @return the blkm in bytes if successfull + */ long int get_blkm(const char* text); + +/** + * Get a mode_t from a string and error and die if failed + * @param text the string that contains the mode_t + * @return the mode_t if successfull + */ mode_t get_mode(const char* text); +/** + * Check if two strings are exactly equal + * @param a null terminated string a + * @param b null terminated string b + * @returns true if the two strings are exactly equal else false + */ bool streql(const char* a, const char* b); + +/** + * Check if a string has a given prefix + * @param pre the null terminated prefix + * @param str the null terminated string + * @returns true if str is prefixed with pre else false + */ bool prefix(const char* pre, const char* str); +/** + * Put a human redable file size (1024M) into buf with the given byte count + * @param bytes the byte count + * @param buf a char buf of length 5 to contain the parsed size + */ void print_file_size(size_t bytes, char buf[5]); + +/** + * Put a human redable date into buf with the given mills since unix epoch + * @param mills mills since the unix epoch + * @param buf a char buf of length 13 to contain the parsed date + */ void print_date_time(time_t mills, char buf[13]); + +/** + * Print a given file path to stdout or (standard input) if '-' + * @param path the file path + */ void print_file_path(char* path); + +/** +* Nuke a given string in memory +* @param the stirng to nuke +*/ +void nuke_str(char* type); + +/** + * Checks if a given character is printable symbol + * @returns if its printable + */ +bool printable_char(char c); + +/** + * Checks if a directory name is . or .. + * @param path the directory name + * @return if a directory is one of the . or .. directorys + */ bool is_dot_dir(const char* path); + +/** + * Get the last component of a path + * @param path the path to parse + * @return a const reference to the last component + */ const char* get_last_component(const char* path); - +/** +* Die +*/ void die (void); +/** + * Print error message to stdout + * @param format the format string + * @param ... the rest of the arguments + */ __attribute__ ((__format__(printf, 1, 2))) void error_s(const char* format, ...); +/** + * Print error message to stdout and die + * @param format the format string + * @param ... the rest of the arguments + */ __attribute__ ((__format__(printf, 1, 2))) void error(const char* format, ...); +/** + * Output message as the given command + * @param format the format string + * @param ... the rest of the arguments + */ __attribute__ ((__format__(printf, 1, 2))) void output(const char* format, ...); - +/** + * Refine the regex as a ADT + */ typedef struct regex_t* re_t; + +/** + * Compile a given regex pattern + * @param pattern the regex to compile + * @return the compiled regex + */ re_t re_compile(const char* pattern); + +/** + * Match a given regex pattern with the string + * @param pattern the pattern to match with + * @param text the text to match + * @param matchlength a pointer to how much was matched + * @return the index where the match was found, -1 if nothing matched + */ int re_matchp(re_t pattern, const char* text, int* matchlength); + +/** + * Compile and match a given regex pattern with the string + * @param pattern the pattern to compile and match with + * @param text the text to match + * @param matchlength a pointer to how much was matched + * @return the index where the match was found, -1 if nothing matched + */ int re_match(const char* pattern, const char* text, int* matchlength); - +/** + * A struct containing a stack + */ struct Stack { - size_t size; - size_t capacity; - void* data; + size_t size; /* The size of the stack */ + size_t capacity; /* The capacity of the stack */ + void* data; /* THe data stored in the stack */ }; +/** + * Initalize a stack with a given size + * @param stack a allocated stack struct to inatalize + * @param size the initial stack capacity + */ void stack_init(struct Stack* stack, size_t size); + +/** + * Push data to the stack + * @param stack the stack to push to + * @param data the data to push + * @param len the length of the data to push + */ void stack_push(struct Stack* stack, void* data, size_t len); + +/** + * Pop the data from the stack (move the pointer back by len doesn't delete) + * @param stack the stack to pop from + * @param len the length of the data to pop + * @return the pointer to the data popped (not yet destroyed until pushed) + */ void* stack_pop(struct Stack* stack, size_t len); + +/** + * Free a stacks allocated memory + * @param stack the stack to free + */ void stack_free(struct Stack* stack); +/** + * Wrapper function to push a int to the stack + * @param stack the stack to push to + * @param value the int to push + */ void stack_push_int(struct Stack* stack, int value); + +/** + * Wrapper function to pop a int from the stack + * @param stack the stack to pop from + * @param value the int pointer to pop + * @returns if a int was successfully popped + */ bool stack_pop_int(struct Stack* stack, int* value); - +/* The default shell if no shell is provided */ #define DEFAULT_SHELL "/bin/sh" + +/* The default PATH env variable */ #define DEFAULT_PATH "/sbin:/usr/sbin:/bin:/usr/bin" -void setup_environment(const char *shell, bool new_env, bool clear_env, const struct passwd *pw); -void exec_shell(const char *shell, bool loginshell, const char **additional_args); +/** + * Setup the environment variables for a given user + * @param shell the shell to set + * @param new_env if to update the env variables according to pw + * @param clear_env if to remove the old env variables + * @param pw the user to update from + */ +void setup_environment(const char* shell, bool new_env, bool clear_env, const struct passwd *pw); +/** + * Exec a shell using the current environment, function will not return + * @param shell the shell to execute + * @param loginshell if to set the shell as login + * @param additional_args additional arguments to pass to the shell command + */ +void exec_shell(const char* shell, bool loginshell, const char** additional_args); -int check_password(const struct passwd *pw, char* plaintext); -int prompt_password(const struct passwd *pw, char* prompt); +#define PASSWORD_INVALID 0 /* if the password was invalid */ +#define PASSWORD_VALID 1 /* if the password was valid */ +#define PASSWORD_EMPTY 2 /* if the user has an empty password */ +/** + * Check if a given plaintext password matches the users /etc/shadow hash + * @param pw the user to check + * @param plaintext the plaintext password to check + * @return if the password was invalid, valid, or empty + */ +int check_password(const struct passwd* pw, char* plaintext); +/** + * Prompt the user for their password and then check the given password + * @param pw the user to check + * @param prompt the pompt to give to the user + * @return if the password was invalid, valid, or empty + */ +int prompt_password(const struct passwd* pw, char* prompt); + +/** + * Set UID and GID to a given user + * @param user to change to + */ void change_identity(const struct passwd* pw); - +/** + * Alloc memory and die if failed + * @param size the amount of memory to allocate in bytes + * @return the pointer to the allocated data + */ void* xalloc(size_t size); + +/** + * Realloc memory and die if failed + * @param ptr the pointer to realloc + * @param size the new size of the data + * @return the pointer to the reallocated data + */ void* xrealloc(void* ptr, size_t size); + +/** + * Alloc memory and zero it, die if failed + * @param size the amouint of memory to allocate in bytes + * @return the zeroed pointer to the allocated data + */ void* xzalloc(size_t size); -void xsetenv(const char *name, const char *value); + +/** + * Set the env, die if failed + * @param name the key to set + * @param value to value to set the key to + */ +void xsetenv(const char* name, const char* value); + +/** + * Set the uid, die if failed + * @param uid the uid to set to + */ void xsetuid(uid_t uid); + +/** + * Set the gid, die if failed + * @param gid the gid to set to + */ void xsetgid(gid_t gid); + +/** + * Get pw by name, die if failed + * @param name the name of the user to get + * @return the pw of the given user + */ struct passwd* xgetpwnam(char* name); - -char* crypt(const char* plaintext, const char* pw_pass); - - -#define PASSWORD_INVALID 0 -#define PASSWORD_VALID 1 -#define PASSWORD_EMPTY 2 - - -#endif +#endif /* SHARED_H */ diff --git a/lib/string.c b/lib/string.c new file mode 100644 index 0000000..13e414e --- /dev/null +++ b/lib/string.c @@ -0,0 +1,79 @@ +#include "lslib.h" + +#include +#include +#include + +static char fs_types[5] = {'K','M','G','T','P'}; +void print_file_size(size_t bytes, char buf[5]) { + int index, n; + float next; + + index = 0; + next = bytes; + + while (true) { + if (next < 1000) { + break; + } + + if (index == 5) { + printf("999P"); + return; + } + + next /= 1024; + index++; + } + + n = snprintf(buf, 4, "%u", (int)(next+.5)); + + if (index > 0) { + buf[n] = (fs_types[index - 1]); + n++; + } + + buf[n] = '\0'; +} + +static char* months[12] = + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; +void print_date_time(time_t mills, char buf[13]) { + struct tm* info; + int n; + + info = localtime(&mills); + n = snprintf(buf, 5, "%s ", months[info->tm_mon]); + + if (info->tm_mday < 10) { + buf[n] = ' '; + n++; + } + + snprintf(buf + n, 13 - n, "%d %02d:%02d ", info->tm_mday, info->tm_hour, info->tm_sec); +} + +void print_file_path(char* path) { + if (streql("-", path)) { + printf("(standard input)"); + } else { + printf("%s", path); + } +} + +void nuke_str(char* type) { + *type = 0; + while(*(++type)) { + *type = 0; + } +} + +bool printable_char(char c) { + switch (c) { + case '\n': return true; + case '\r': return true; + case '\b': return true; + case '\t': return true; + default: return isprint(c) == 0; + } +}