slight refactor and start documenting

This commit is contained in:
Murphy 2023-05-16 19:15:01 -04:00
parent 6458a0f9e0
commit 67173fb971
7 changed files with 655 additions and 214 deletions

View file

@ -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 */
}

View file

@ -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 */
}

View file

@ -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 */
}

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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));
/**
* 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 */

79
lib/string.c Normal file
View file

@ -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;
}
}