summaryrefslogtreecommitdiff
path: root/42sh/src/utils
diff options
context:
space:
mode:
authorMartial Simon <msimon_fr@hotmail.com>2025-09-15 01:07:58 +0200
committerMartial Simon <msimon_fr@hotmail.com>2025-09-15 01:07:58 +0200
commit967be9e750221ab2ab783f95df79bb26d290a45e (patch)
tree6802900a5e975f9f68b169f0f503f040056d6952 /42sh/src/utils
add: added projectsHEADmain
Diffstat (limited to '42sh/src/utils')
-rw-r--r--42sh/src/utils/Makefile.am13
-rw-r--r--42sh/src/utils/basicstring.c124
-rw-r--r--42sh/src/utils/env.c125
-rw-r--r--42sh/src/utils/env.h41
-rw-r--r--42sh/src/utils/libstring.h87
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 */