summaryrefslogtreecommitdiff
path: root/42sh/src/builtins
diff options
context:
space:
mode:
Diffstat (limited to '42sh/src/builtins')
-rw-r--r--42sh/src/builtins/Makefile.am20
-rw-r--r--42sh/src/builtins/break.c27
-rw-r--r--42sh/src/builtins/builtins.h21
-rw-r--r--42sh/src/builtins/cd.c74
-rw-r--r--42sh/src/builtins/continue.c27
-rw-r--r--42sh/src/builtins/dot.c43
-rw-r--r--42sh/src/builtins/echo.c94
-rw-r--r--42sh/src/builtins/exit.c28
-rw-r--r--42sh/src/builtins/export.c68
-rw-r--r--42sh/src/builtins/false.c10
-rw-r--r--42sh/src/builtins/true.c10
-rw-r--r--42sh/src/builtins/unset.c44
12 files changed, 466 insertions, 0 deletions
diff --git a/42sh/src/builtins/Makefile.am b/42sh/src/builtins/Makefile.am
new file mode 100644
index 0000000..4a16c3d
--- /dev/null
+++ b/42sh/src/builtins/Makefile.am
@@ -0,0 +1,20 @@
+lib_LIBRARIES = libbuiltins.a
+
+libbuiltins_a_SOURCES = \
+ builtins.h \
+ true.c \
+ false.c \
+ echo.c \
+ exit.c \
+ break.c \
+ export.c \
+ continue.c \
+ unset.c \
+ dot.c \
+ cd.c
+
+libbuiltins_a_CPPFLAGS = -I$(top_srcdir)/src
+
+libbuiltins_a_CFLAGS = -std=c99 -Werror -Wall -Wextra -Wvla -pedantic
+
+noinst_LIBRARIES = libbuiltins.a
diff --git a/42sh/src/builtins/break.c b/42sh/src/builtins/break.c
new file mode 100644
index 0000000..6718de1
--- /dev/null
+++ b/42sh/src/builtins/break.c
@@ -0,0 +1,27 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "builtins.h"
+#include "utils/env.h"
+
+int my_break(struct string **args)
+{
+ char *n = "1";
+ if (args[0] != NULL)
+ {
+ char *end;
+ long num = strtol(args[0]->data, &end, 10);
+ if (*end != '\0' || num <= 0)
+ {
+ fprintf(stderr, "break: %s: numeric argument required\n",
+ args[1]->data);
+ return 2;
+ }
+ n = args[0]->data;
+ }
+ env_set("BREAK", n);
+ fflush(stdout);
+ return 0;
+}
diff --git a/42sh/src/builtins/builtins.h b/42sh/src/builtins/builtins.h
new file mode 100644
index 0000000..6b99918
--- /dev/null
+++ b/42sh/src/builtins/builtins.h
@@ -0,0 +1,21 @@
+#ifndef BUILTINS_H
+#define BUILTINS_H
+
+#include "utils/libstring.h"
+
+#define NB_BUILTINS 10
+
+typedef int (*builtin)(struct string **);
+
+int echo(struct string **args);
+int my_true(struct string **args);
+int my_false(struct string **args);
+int my_exit(struct string **args);
+int cd(struct string **args);
+int my_continue(struct string **args);
+int my_break(struct string **args);
+int dot(struct string **args);
+int unset(struct string **args);
+int export(struct string **args);
+
+#endif /* ! BUILTINS_H */
diff --git a/42sh/src/builtins/cd.c b/42sh/src/builtins/cd.c
new file mode 100644
index 0000000..90fd9db
--- /dev/null
+++ b/42sh/src/builtins/cd.c
@@ -0,0 +1,74 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "builtins.h"
+#include "utils/env.h"
+
+int cd_pointpoint(char *path, char *old)
+{
+ char *current = strrchr(path, '/');
+ size_t len = current - path;
+ if (len == 0)
+ {
+ fprintf(stderr, "cd: error with ..\n");
+ return 2;
+ }
+ char *parent = malloc(len + 1);
+ memcpy(parent, current, len);
+ parent[len] = '\0';
+ old = path;
+ path = parent;
+ env_set("OLDPWD", old);
+ env_set("PWD", path);
+ free(parent);
+
+ return 0;
+}
+
+int cd(struct string **args)
+{
+ if (args[0] == NULL || args[1] != NULL)
+ {
+ fprintf(stderr, "cd: error too many arguments\n");
+ fflush(stdout);
+ return 2;
+ }
+ if (strcmp(env_get("PWD"), "") == 0)
+ {
+ fprintf(stderr, "cd: error with PWD\n");
+ fflush(stdout);
+ return 2;
+ }
+ char *old = env_get("OLDPWD");
+ char *path = env_get("PWD");
+ char *tmp = old;
+ if (strcmp(args[0]->data, "-") == 0)
+ {
+ if (strcmp(old, "") == 0)
+ {
+ fprintf(stderr, "cd: error with OLDPWD\n");
+ fflush(stdout);
+ return 2;
+ }
+ printf("%s\n", old);
+ old = path;
+ path = tmp;
+ }
+ else if (strcmp(args[0]->data, "..") == 0)
+ {
+ int res = cd_pointpoint(path, old);
+ fflush(stdout);
+ return res;
+ }
+ else
+ {
+ old = path;
+ path = args[0]->data;
+ }
+ env_set("OLDPWD", old);
+ env_set("PWD", path);
+ fflush(stdout);
+ return 0;
+}
diff --git a/42sh/src/builtins/continue.c b/42sh/src/builtins/continue.c
new file mode 100644
index 0000000..295fb8c
--- /dev/null
+++ b/42sh/src/builtins/continue.c
@@ -0,0 +1,27 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "builtins.h"
+#include "utils/env.h"
+
+int my_continue(struct string **args)
+{
+ char *n = "1";
+ if (args[0] != NULL)
+ {
+ char *end;
+ long num = strtol(args[0]->data, &end, 10);
+ if (*end != '\0' || num <= 0)
+ {
+ fprintf(stderr, "continue: %s: numeric argument required\n",
+ args[1]->data);
+ return 2;
+ }
+ n = args[0]->data;
+ }
+ env_set("CONTINUE", n);
+ fflush(stdout);
+ return 0;
+}
diff --git a/42sh/src/builtins/dot.c b/42sh/src/builtins/dot.c
new file mode 100644
index 0000000..6cec097
--- /dev/null
+++ b/42sh/src/builtins/dot.c
@@ -0,0 +1,43 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "builtins.h"
+#include "utils/env.h"
+
+int dot(struct string **args)
+{
+ if (args[0] == NULL)
+ {
+ fprintf(stderr, ".: filename argument required\n");
+ fflush(stdout);
+ return 2;
+ }
+ if (args[1] != NULL)
+ {
+ fprintf(stderr, ".: too many arguments\n");
+ fflush(stdout);
+ return 2;
+ }
+
+ FILE *file = fopen(args[0]->data, "r");
+ if (file == NULL)
+ {
+ fprintf(stderr, ".: filename does not exist\n");
+ fflush(stdout);
+ return 1;
+ }
+
+ char line[1024];
+ while (fgets(line, sizeof(line), file))
+ {
+ // TODO : execute file
+ fputs(line, stdout);
+ }
+ fclose(file);
+ fflush(stdout);
+ return 0;
+}
diff --git a/42sh/src/builtins/echo.c b/42sh/src/builtins/echo.c
new file mode 100644
index 0000000..f330050
--- /dev/null
+++ b/42sh/src/builtins/echo.c
@@ -0,0 +1,94 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "builtins.h"
+
+static void print_echo(struct string **args, int escapes, int newline, int i)
+{
+ while (args[i] != NULL)
+ {
+ if (escapes)
+ {
+ size_t j = 0;
+ while (j < args[i]->length)
+ {
+ if (args[i]->data[j] == '\\' && args[i]->data[j] != '\0')
+ {
+ j += 1;
+ switch (args[i]->data[j])
+ {
+ case 'n':
+ putchar('\n');
+ break;
+ case 't':
+ putchar('\t');
+ break;
+ case '\\':
+ putchar('\\');
+ break;
+ default:
+ putchar('\\');
+ putchar(args[i]->data[j]);
+ break;
+ }
+ j += 1;
+ }
+ else
+ {
+ putchar(args[i]->data[j]);
+ j += 1;
+ }
+ }
+ }
+ else
+ {
+ fputs(args[i]->data, stdout);
+ }
+ if (args[i + 1] != NULL)
+ {
+ putchar(' ');
+ }
+ i += 1;
+ }
+ if (newline)
+ {
+ putchar('\n');
+ }
+}
+
+int echo(struct string **args)
+{
+ int newline = 1;
+ int escapes = 0;
+ size_t i = 0;
+ if (args[0] == NULL)
+ {
+ putchar('\n');
+ return 0;
+ }
+ while (args[i] != NULL && args[i]->data[0] == '-')
+ {
+ if (args[i]->length == 2 && args[i]->data[1] == 'n')
+ {
+ newline = 0;
+ i += 1;
+ }
+ else if (args[i]->length == 2 && args[i]->data[1] == 'e')
+ {
+ escapes = 1;
+ i += 1;
+ }
+ else if (args[i]->length == 2 && args[i]->data[1] == 'E')
+ {
+ escapes = 0;
+ i += 1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ print_echo(args, escapes, newline, i);
+ fflush(stdout);
+ return 0;
+}
diff --git a/42sh/src/builtins/exit.c b/42sh/src/builtins/exit.c
new file mode 100644
index 0000000..943c22f
--- /dev/null
+++ b/42sh/src/builtins/exit.c
@@ -0,0 +1,28 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "builtins.h"
+
+int my_exit(struct string **args)
+{
+ unsigned int res = 0;
+ if (args[0] != NULL)
+ {
+ char *c;
+ long status = strtol(args[0]->data, &c, 10);
+ if (*c != '\0' || status < 0 || status > 255)
+ {
+ fprintf(stderr, "exit: %s: numeric argument required\n",
+ args[0]->data);
+ res = 2;
+ }
+ else
+ {
+ res = (unsigned int)status;
+ }
+ }
+ fflush(stdout);
+ exit(res);
+}
diff --git a/42sh/src/builtins/export.c b/42sh/src/builtins/export.c
new file mode 100644
index 0000000..358cfc7
--- /dev/null
+++ b/42sh/src/builtins/export.c
@@ -0,0 +1,68 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "builtins.h"
+#include "utils/env.h"
+
+extern char **environ;
+
+void printenv(void)
+{
+ size_t i = 0;
+ while (environ[i] != NULL)
+ {
+ printf("export %s\n", environ[i]);
+ i += 1;
+ }
+}
+
+void export_var(struct string *arg)
+{
+ char *equal = strchr(arg->data, '=');
+ if (equal != NULL)
+ {
+ size_t len = equal - arg->data;
+ char *var = malloc(len + 1);
+ memcpy(var, arg->data, len);
+ char *value = equal + 1;
+ var[len] = '\0';
+ env_set(var, value);
+ free(var);
+ }
+ else
+ {
+ env_set(arg->data, "");
+ }
+}
+
+int export(struct string **args)
+{
+ if (args[0] == NULL)
+ {
+ printenv();
+ fflush(stdout);
+ return 0;
+ }
+ int flagp = 0;
+ size_t i = 0;
+ if (strcmp(args[0]->data, "-p") == 0)
+ {
+ flagp = 1;
+ i += 1;
+ }
+ if (args[1] == NULL && flagp)
+ {
+ printenv();
+ fflush(stdout);
+ return 0;
+ }
+ while (args[i] != NULL)
+ {
+ export_var(args[i]);
+ i += 1;
+ }
+ fflush(stdout);
+ return 0;
+}
diff --git a/42sh/src/builtins/false.c b/42sh/src/builtins/false.c
new file mode 100644
index 0000000..17ab256
--- /dev/null
+++ b/42sh/src/builtins/false.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#include "builtins.h"
+
+int my_false(struct string **args)
+{
+ (void)args;
+ fflush(stdout);
+ return 1;
+}
diff --git a/42sh/src/builtins/true.c b/42sh/src/builtins/true.c
new file mode 100644
index 0000000..ed7c7d1
--- /dev/null
+++ b/42sh/src/builtins/true.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#include "builtins.h"
+
+int my_true(struct string **args)
+{
+ (void)args;
+ fflush(stdout);
+ return 0;
+}
diff --git a/42sh/src/builtins/unset.c b/42sh/src/builtins/unset.c
new file mode 100644
index 0000000..77b323a
--- /dev/null
+++ b/42sh/src/builtins/unset.c
@@ -0,0 +1,44 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "builtins.h"
+#include "utils/env.h"
+
+int unset(struct string **args)
+{
+ size_t i = 0;
+ int var = 0;
+ int fun = 0;
+ while (args[i] != NULL && args[i]->data[0] == '-')
+ {
+ if (args[i]->data[1] == 'v')
+ {
+ var = 1;
+ i += 1;
+ }
+ else if (args[i]->data[1] == 'f')
+ {
+ fun = 1;
+ i += 1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (var == 0 && fun == 0)
+ {
+ var = 1;
+ fun = 1;
+ }
+ // TODO unset with flag -f
+ while (args[i] != NULL)
+ {
+ env_unset(args[i]->data);
+ i += 1;
+ }
+ fflush(stdout);
+ return 0;
+}