diff options
| author | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:07:58 +0200 |
|---|---|---|
| committer | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:07:58 +0200 |
| commit | 967be9e750221ab2ab783f95df79bb26d290a45e (patch) | |
| tree | 6802900a5e975f9f68b169f0f503f040056d6952 /42sh/src/utils | |
Diffstat (limited to '42sh/src/utils')
| -rw-r--r-- | 42sh/src/utils/Makefile.am | 13 | ||||
| -rw-r--r-- | 42sh/src/utils/basicstring.c | 124 | ||||
| -rw-r--r-- | 42sh/src/utils/env.c | 125 | ||||
| -rw-r--r-- | 42sh/src/utils/env.h | 41 | ||||
| -rw-r--r-- | 42sh/src/utils/libstring.h | 87 |
5 files changed, 390 insertions, 0 deletions
diff --git a/42sh/src/utils/Makefile.am b/42sh/src/utils/Makefile.am new file mode 100644 index 0000000..2418637 --- /dev/null +++ b/42sh/src/utils/Makefile.am @@ -0,0 +1,13 @@ +lib_LIBRARIES = libutils.a + +libutils_a_SOURCES = \ + libstring.h \ + basicstring.c \ + env.c \ + env.h + +libutils_a_CPPFLAGS = -I$(top_srcdir)/src + +libutils_a_CFLAGS = -std=c99 -Werror -Wall -Wextra -Wvla -pedantic + +noinst_LIBRARIES = libutils.a diff --git a/42sh/src/utils/basicstring.c b/42sh/src/utils/basicstring.c new file mode 100644 index 0000000..6efbe1f --- /dev/null +++ b/42sh/src/utils/basicstring.c @@ -0,0 +1,124 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "libstring.h" + +struct string *string_create(char *s) +{ + if (!s) + { + struct string *r = calloc(1, sizeof(struct string)); + char *data = calloc((BASE_STRING_SIZE + 1), sizeof(char)); + if (!r || !data) + { + fprintf(stderr, "string_create: calloc failed.\n"); + return NULL; + } + r->data = data; + r->capacity = BASE_STRING_SIZE; + return r; + } + + struct string *str = malloc(1 * sizeof(struct string)); + if (!str) + { + fprintf(stderr, "string_create: malloc failed.\n"); + return NULL; + } + + // Align the capacity on the string base size + size_t l = strlen(s); + size_t m = (l + 1) % BASE_STRING_SIZE; + str->length = l; + str->capacity = (l + 1) + (BASE_STRING_SIZE - m); + str->data = calloc(str->capacity, sizeof(char)); + if (!str->data) + { + fprintf(stderr, "string_create: malloc failed.\n"); + return NULL; + } + memcpy(str->data, s, l); + + return str; +} + +void string_free(struct string *str) +{ + if (str) + { + free(str->data); + free(str); + } +} + +static bool _resize_string(struct string *str, int p) +{ + char *new_data = realloc( + str->data, ((p >= 0) ? str->capacity * 2 : str->capacity / 2) + 1); + if (!new_data) + { + fprintf(stderr, "_resize_string: realloc failed.\n"); + return false; + } + + str->data = new_data; + str->capacity = ((p >= 0) ? str->capacity * 2 : str->capacity / 2); + return true; +} + +bool string_pushc(struct string *str, char c) +{ + if (str->length == str->capacity) + { + if (!_resize_string(str, 1)) + { + return false; + } + } + str->data[str->length] = c; + str->length++; + str->data[str->length] = 0; + return true; +} + +bool string_pushstr(struct string *str, char *s) +{ + if (!s || !s[0]) + { + return true; + } + size_t l = strlen(s); + while (str->length + l >= str->capacity) + { + if (!_resize_string(str, 1)) + { + return false; + } + } + + memcpy(str->data + str->length, s, l); + str->length += l; + str->data[str->length] = 0; + return true; +} + +bool string_catenate(struct string *dst, struct string *src) +{ + if (!src) + { + return true; + } + + if (!dst || !string_pushstr(dst, src->data)) + { + return false; + } + + string_free(src); + return true; +} + +struct string *string_deepcopy(struct string *str) +{ + return string_create(str->data); +} diff --git a/42sh/src/utils/env.c b/42sh/src/utils/env.c new file mode 100644 index 0000000..e3095a4 --- /dev/null +++ b/42sh/src/utils/env.c @@ -0,0 +1,125 @@ +#define _DEFAULT_SOURCE +#define _POSIX_C_SOURCE 200809L + +#include "utils/env.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "utils/libstring.h" + +void env_set(const char *name, const char *value) +{ + if (setenv(name, value, 1) == -1) + { + fprintf(stderr, "env_set: unable to set \'%s\'=\'%s\'.\n", name, value); + } +} + +void env_unset(const char *name) +{ + if (unsetenv(name) == -1) + { + fprintf(stderr, "env_unset: unable to unset \'%s\'.\n", name); + } +} + +static void _generate_random(void) +{ + int d = rand() % MAX_RAND; + char buf[16] = { 0 }; + sprintf(buf, "%d", d); + env_set("RANDOM", buf); +} + +static struct string *_cat_args(void) +{ + int nb_args = atoi(env_get("#")); + struct string *s = string_create(NULL); + for (int i = 1; i <= nb_args; i++) + { + char buf[16] = { 0 }; + sprintf(buf, "%d", i); + string_pushstr(s, env_get(buf)); + if (i != nb_args) + { + string_pushc(s, ' '); + } + } + return s; +} + +char *env_get(const char *name) +{ + if (STRINGS_ARE_EQUAL(name, "RANDOM")) + { + _generate_random(); + } + if (STRINGS_ARE_EQUAL(name, "*")) + { + struct string *s = _cat_args(); + env_set("*", s->data); + string_free(s); + } + if (STRINGS_ARE_EQUAL(name, "@")) + { + struct string *s = string_create(NULL); + string_pushc(s, '\"'); + struct string *args = _cat_args(); + string_pushstr(s, args->data); + string_pushc(s, '\"'); + if (s->length > 2) + { + env_set("@", s->data); + } + string_free(s); + string_free(args); + } + return getenv(name); +} + +void env_clear(void) +{ + if (clearenv()) + { + fprintf(stderr, "env_clear: unable to clear the environment.\n"); + } +} + +static void _set_pwd(void) +{ + char buf[MAX_PATH_SIZE] = { 0 }; + char *path = getcwd(buf, MAX_PATH_SIZE); + env_set("PWD", path); + env_set("OLDPWD", path); +} + +static void _set_uid(void) +{ + uid_t uid = getuid(); + // Magic value but UID is an integer (POSIX requirement) + // So it won't be more that 10 chars long + char buf[16] = { 0 }; + sprintf(buf, "%u", uid); + env_set("UID", buf); +} + +static void _set_pid(void) +{ + pid_t pid = getpid(); + // Magic value but PID is an integer (POSIX requirement) + // So it won't be more that 10 chars long + char buf[16] = { 0 }; + sprintf(buf, "%d", pid); + env_set("$", buf); +} + +void env_setup(void) +{ + _set_pwd(); + _set_uid(); + _set_pid(); + env_set("IFS", DEFAULT_IFS); + env_set("?", "0"); +} diff --git a/42sh/src/utils/env.h b/42sh/src/utils/env.h new file mode 100644 index 0000000..e349651 --- /dev/null +++ b/42sh/src/utils/env.h @@ -0,0 +1,41 @@ +#ifndef ENV_H +#define ENV_H + +#include <stdlib.h> + +#define DEFAULT_IFS " \t\n" + +#define MAX_PATH_SIZE 4096 +#define MAX_RAND 32768 + +/** + * @brief Sets the variable `name`=`value` into the environment. + */ +void env_set(const char *name, const char *value); + +/** + * @brief Unsets the variable `name` from the environment. + */ +void env_unset(const char *name); + +/** + * @brief Gets the value of the variable `name`. + * @return A string that contains the value. + */ +char *env_get(const char *name); + +/** + * @brief Clears all of the variables that are in the environment. + */ +void env_clear(void); + +/** + * @brief Sets a few variables to default values (that can be found in `env.h`). + * Here is the list of the variables affected by this function: + * `PWD`, + * `OLDPWD`, + * `IFS` + */ +void env_setup(void); + +#endif /* ! ENV_H */ diff --git a/42sh/src/utils/libstring.h b/42sh/src/utils/libstring.h new file mode 100644 index 0000000..e30097c --- /dev/null +++ b/42sh/src/utils/libstring.h @@ -0,0 +1,87 @@ +#ifndef LIBSTRING_H +#define LIBSTRING_H + +#include <stdbool.h> +#include <string.h> + +/** + * @brief Represents the default capacity of the string + */ +#define BASE_STRING_SIZE 8 + +#define STRINGS_ARE_EQUAL(A, B) (strcmp(A, B) == 0) + +/** + * @brief Represents a dynamically allocated string. + * + * This struct manages a dynamically allocated null-terminated string + * along with its length and capacity. + */ +struct string +{ + size_t length; /**< The current length of the string (excluding the null + terminator). */ + size_t capacity; /**< The allocated capacity of the string (always a + multiple of `BASE_STRING_SIZE`). */ + char *data; /**< A pointer to the null-terminated character data. */ +}; + +/** + * @brief Creates a heap-allocated copy of the given string. + * + * The capacity is always a multiple of `BASE_STRING_SIZE`. If `s` is + * heap-allocated, the caller must free it later. The resulting string struct + * and data are freed when `string_free` is called. + * + * @param s A null-terminated string that can be null. + * @return A pointer to a newly heap-allocated `struct string`. + */ +struct string *string_create(char *s); + +/** + * @brief Frees the `struct string` and its associated data. + * + * This function frees the struct `str` and its heap-allocated null-terminated + * character data. + * + * @param str A pointer to the `struct string` to be freed. + */ +void string_free(struct string *str); + +/** + * @brief Pushes a single character into the string. + * + * Resizes the string's data and capacity if needed. + * + * @param str A pointer to the `struct string` where the character will be + * added. + * @param c The character to push into the string. + * @return `true` if the push succeeds, `false` otherwise. + */ +bool string_pushc(struct string *str, char c); + +/** + * @brief Pushes a null-terminated string into the string. + * + * @param str A pointer to the `struct string` where the string will be added. + * @param s A null-terminated string to push into `str`. + * @return `true` if the operation succeeds, `false` otherwise. + */ +bool string_pushstr(struct string *str, char *s); + +/** + * @brief Concatenates two `struct string` objects and frees the source string. + * + * The `src` struct and its data are freed after concatenation. + * + * @param dst A pointer to the destination `struct string` to which `src` will + * be concatenated. + * @param src A pointer to the source `struct string` that will be concatenated + * and freed. + * @return `true` if the concatenation succeeds, `false` otherwise. + */ +bool string_catenate(struct string *dst, struct string *src); + +struct string *string_deepcopy(struct string *str); + +#endif /* ! LIBSTRING_H */ |
