summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Murphy <tylerm@tylerm.dev>2023-05-16 19:15:01 -0400
committerTyler Murphy <tylerm@tylerm.dev>2023-05-16 19:15:01 -0400
commit67173fb97117a41cebb82a1364ae686a9574927b (patch)
treee631e7515bcb7420b6348c0e3159336298d4e3df
parentupdate ls (diff)
downloadlazysphere-67173fb97117a41cebb82a1364ae686a9574927b.tar.gz
lazysphere-67173fb97117a41cebb82a1364ae686a9574927b.tar.bz2
lazysphere-67173fb97117a41cebb82a1364ae686a9574927b.zip
slight refactor and start documenting
-rw-r--r--command/cat.c89
-rw-r--r--command/chmod.c122
-rw-r--r--command/chown.c123
-rw-r--r--command/ls.c17
-rw-r--r--lib/convert.c63
-rw-r--r--lib/lslib.h374
-rw-r--r--lib/string.c79
7 files changed, 654 insertions, 213 deletions
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 <ctype.h>
#include <stdlib.h>
+/**
+ * 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 <dirent.h>
#include <string.h>
+/**
+ * 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 <sys/types.h>
#include <pwd.h>
+/**
+ * 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 <sys/stat.h>
#include <pwd.h>
-
-#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));
-int parse_args (int argc, char** argv, void (*help)(void), int (*short_arg)(char, char*), int (*long_arg)(char*, char*));
+/**
+ * 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);
-FILE* get_tty_stream(char* type);
-void nuke_str(char* type);
+/**
+ * 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);
+/**
+ * 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);
-int push_path_buffer_2(const char* string);
-void pop_path_buffer_2(int i);
+/**
+ * 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);
-const char* get_last_component(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);
-int re_match(const char* 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);
-bool stack_pop_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);
-void change_identity(const struct passwd* pw);
+/**
+ * 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);
-void* xzalloc(size_t size);
-void xsetenv(const char *name, const char *value);
-void xsetuid(uid_t uid);
-void xsetgid(gid_t gid);
-struct passwd* xgetpwnam(char* name);
+/**
+ * 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);
-char* crypt(const char* plaintext, const char* pw_pass);
+/**
+ * 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);
-#define PASSWORD_INVALID 0
-#define PASSWORD_VALID 1
-#define PASSWORD_EMPTY 2
+/**
+ * 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);
-#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 <ctype.h>
+#include <stddef.h>
+#include <time.h>
+
+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;
+ }
+}