summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLAN-TW <lantw44@gmail.com>2013-11-08 15:01:44 +0800
committerb01902062 <b01902062@linux5.csie.ntu.edu.tw>2013-11-08 15:01:44 +0800
commit2b896398274fbb2f47526c6a5607e5591801660d (patch)
treee3eeddfabc54868badc7eb6319cda5bea36565c0
parent4fe722d31f139f21cde77536027c2c4abd86b585 (diff)
downloadcn2013-2b896398274fbb2f47526c6a5607e5591801660d.tar.gz
cn2013-2b896398274fbb2f47526c6a5607e5591801660d.tar.zst
cn2013-2b896398274fbb2f47526c6a5607e5591801660d.zip
HW1: 更新 shell parser 並將 builtin command 移出 shell.c
-rw-r--r--hw1/Makefile.am1
-rw-r--r--hw1/shell-builtin.c143
-rw-r--r--hw1/shell-builtin.h22
-rw-r--r--hw1/shell.c169
-rw-r--r--hw1/shell.h30
5 files changed, 202 insertions, 163 deletions
diff --git a/hw1/Makefile.am b/hw1/Makefile.am
index 70e2fb9..82ecd78 100644
--- a/hw1/Makefile.am
+++ b/hw1/Makefile.am
@@ -18,6 +18,7 @@ libras_a_SOURCES = \
shell_sources = \
shell.c shell.h \
+ shell-builtin.c shell-builtin.h \
$(NULL)
ras_server_SOURCES = \
diff --git a/hw1/shell-builtin.c b/hw1/shell-builtin.c
new file mode 100644
index 0000000..87d0632
--- /dev/null
+++ b/hw1/shell-builtin.c
@@ -0,0 +1,143 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "shell-builtin.h"
+
+#include "xwrap.h"
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+const RasShellBuiltin ras_shell_builtins[] = {
+ { "cd", ras_shell_builtin_cd },
+ { "echo", ras_shell_builtin_echo },
+ { "exit", ras_shell_builtin_exit },
+ { "logout", ras_shell_builtin_logout },
+ { "printenv", ras_shell_builtin_printenv },
+ { "pwd", ras_shell_builtin_pwd },
+ { "setenv", ras_shell_builtin_setenv },
+ { "umask", ras_shell_builtin_umask },
+ { NULL, NULL }
+};
+
+int ras_shell_builtin_cd (int argc, char* argv[], RasShell* shell) {
+ if (shell->attr_rshell) {
+ fprintf (stderr, "%s: you are not permitted to run this command\n", argv[0]);
+ return 1;
+ }
+ char* dest = argv[1];
+ if (dest == NULL) {
+ dest = getenv ("HOME");
+ if (dest == NULL) {
+ dest = ".";
+ }
+ }
+ if (chdir (dest) < 0) {
+ fprintf (stderr, "cd: %s: %s\n", dest, strerror (errno));
+ return 1;
+ }
+ return 0;
+}
+
+int ras_shell_builtin_echo (int argc, char* argv[], RasShell* shell) {
+ for (int i = 1; argv[i] != NULL; i++) {
+ if (i > 1) {
+ putchar (' ');
+ }
+ fputs (argv[i], stdout);
+ }
+ putchar ('\n');
+ return 0;
+}
+
+int ras_shell_builtin_exit (int argc, char* argv[], RasShell* shell) {
+ if (argc > 2) {
+ fprintf (stderr, "%s: too many arguments\n", argv[0]);
+ return 1;
+ }
+ if (argc < 2) {
+ shell->req_exit_status = 0;
+ } else if (sscanf (argv[1], "%d", &shell->req_exit_status) < 1) {
+ fprintf (stderr, "%s: `%s\' is not a number\n", argv[0], argv[1]);
+ return 1;
+ }
+ shell->req_exit = true;
+ return 0;
+}
+
+int ras_shell_builtin_logout (int argc, char* argv[], RasShell* shell) {
+ if (!shell->attr_login) {
+ fprintf (stderr, "%s: not a login shell\n", argv[0]);
+ return 1;
+ }
+ return ras_shell_builtin_exit (argc, argv, shell);
+}
+
+int ras_shell_builtin_printenv (int argc, char* argv[], RasShell* shell) {
+ if (argc > 2) {
+ fprintf (stderr, "%s: too many arguments\n", argv[0]);
+ return 1;
+ }
+ if (argc < 2) {
+ extern char** environ;
+ for (int i = 0; environ[i] != NULL; i++) {
+ puts (environ[i]);
+ }
+ } else {
+ char* res = getenv (argv[1]);
+ if (res == NULL) {
+ return 1;
+ }
+ puts (res);
+ }
+ return 0;
+}
+
+int ras_shell_builtin_pwd (int argc, char* argv[], RasShell* shell) {
+ char* cwd = xgetcwd ();
+ if (cwd == NULL) {
+ fprintf (stderr, "%s: cannot get working directory: %s\n", argv[0], strerror (errno));
+ return 1;
+ }
+ puts (cwd);
+ free (cwd);
+ return 0;
+}
+
+int ras_shell_builtin_setenv (int argc, char* argv[], RasShell* shell) {
+ if (argc != 3) {
+ fprintf (
+ stderr, "%s: too %s arguments\n", argv[0], argc > 3 ? "many" : "few");
+ return 1;
+ }
+ return - setenv (argv[1], argv[2], 1);
+}
+
+int ras_shell_builtin_umask (int argc, char* argv[], RasShell* shell) {
+ if (argc > 2) {
+ fprintf (stderr, "%s: too many arguments\n", argv[0]);
+ return 1;
+ }
+
+ if (argc < 2) {
+ mode_t old_mode = umask (0777);
+ umask (old_mode);
+ printf ("%04o\n", old_mode);
+ } else {
+ int mode_int;
+ if (sscanf (argv[1], "%o", &mode_int) < 0) {
+ fprintf (stderr, "%s: `%s\' is not a valid octal number\n", argv[0], argv[1]);
+ return 1;
+ }
+ mode_t new_mode = mode_int;
+ umask (new_mode);
+ }
+ return 0;
+}
diff --git a/hw1/shell-builtin.h b/hw1/shell-builtin.h
new file mode 100644
index 0000000..ebdec2f
--- /dev/null
+++ b/hw1/shell-builtin.h
@@ -0,0 +1,22 @@
+#ifndef RAS_SHELL_BUILTIN_H
+#define RAS_SHELL_BUILTIN_H
+
+#include "shell.h"
+
+typedef struct {
+ char* cmd;
+ RasShellFunc func;
+} RasShellBuiltin;
+
+extern const RasShellBuiltin ras_shell_builtins[];
+
+int ras_shell_builtin_cd (int argc, char* argv[], RasShell* shell);
+int ras_shell_builtin_echo (int argc, char* argv[], RasShell* shell);
+int ras_shell_builtin_exit (int argc, char* argv[], RasShell* shell);
+int ras_shell_builtin_logout (int argc, char* argv[], RasShell* shell);
+int ras_shell_builtin_printenv (int argc, char* argv[], RasShell* shell);
+int ras_shell_builtin_pwd (int argc, char* argv[], RasShell* shell);
+int ras_shell_builtin_setenv (int argc, char* argv[], RasShell* shell);
+int ras_shell_builtin_umask (int argc, char* argv[], RasShell* shell);
+
+#endif /* RAS_SHELL_BUILTIN_H */
diff --git a/hw1/shell.c b/hw1/shell.c
index a9095d7..7c67d91 100644
--- a/hw1/shell.c
+++ b/hw1/shell.c
@@ -2,9 +2,12 @@
# include "config.h"
#endif
+#include "shell.h"
+
#include "basic-array.h"
#include "basic-list.h"
#include "xwrap.h"
+#include "shell-builtin.h"
#include <ctype.h>
#include <errno.h>
@@ -52,34 +55,6 @@ typedef struct {
pid_t pgid; /* process group ID */
} RasShellCmd;
-typedef struct {
- char* name; /* This is argv[0]. Do not modify or free it. */
- uint64_t count;
- List* saved_list; /* A list of RasShellSaved */
- char* saved_tmpdir;
- int last_rval;
- pid_t pid;
- pid_t pgid;
- int attr_login : 1; /* login shell */
- int attr_rshell : 1; /* restricted shell */
- int attr_debug : 1; /* debug message */
- int attr_isterm : 1; /* shell is run in a terminal */
- char* user_name;
- char user_ps;
- int req_exit : 1; /* request for exit */
- int req_exit_status; /* requested exit status */
- int term_fd; /* shell terminal fd */
- struct termios tmode; /* shell terminal mode */
-} RasShell;
-
-typedef int (*RasShellFunc) (int argc, char* argv[], RasShell* shell);
-typedef char* (*RasShellRead) (void* data);
-
-typedef struct {
- char* cmd;
- RasShellFunc func;
-} RasShellBuiltin;
-
#define PARSE_QUOTE_REGULAR '\"'
#define PARSE_QUOTE_SUPER '\''
#define PARSE_ESCAPE '\\'
@@ -93,121 +68,6 @@ typedef enum {
APPEND_LAST
} RasShellCmdMode;
-static int ras_shell_builtin_cd (int argc, char* argv[], RasShell* shell) {
- if (shell->attr_rshell) {
- fprintf (stderr, "%s: you are not permitted to run this command\n", argv[0]);
- return 1;
- }
- char* dest = argv[1];
- if (dest == NULL) {
- dest = getenv ("HOME");
- if (dest == NULL) {
- dest = ".";
- }
- }
- if (chdir (dest) < 0) {
- fprintf (stderr, "cd: %s: %s\n", dest, strerror (errno));
- return 1;
- }
- return 0;
-}
-
-static int ras_shell_builtin_echo (int argc, char* argv[], RasShell* shell) {
- for (int i = 1; argv[i] != NULL; i++) {
- if (i > 1) {
- putchar (' ');
- }
- fputs (argv[i], stdout);
- }
- putchar ('\n');
- return 0;
-}
-
-static int ras_shell_builtin_exit (int argc, char* argv[], RasShell* shell) {
- if (argc > 2) {
- fprintf (stderr, "%s: too many arguments\n", argv[0]);
- return 1;
- }
- if (argc < 2) {
- shell->req_exit_status = 0;
- } else if (sscanf (argv[1], "%d", &shell->req_exit_status) < 1) {
- fprintf (stderr, "%s: `%s\' is not a number\n", argv[0], argv[1]);
- return 1;
- }
- shell->req_exit = true;
- return 0;
-}
-
-static int ras_shell_builtin_logout (int argc, char* argv[], RasShell* shell) {
- if (!shell->attr_login) {
- fprintf (stderr, "%s: not a login shell\n", argv[0]);
- return 1;
- }
- return ras_shell_builtin_exit (argc, argv, shell);
-}
-
-static int ras_shell_builtin_printenv (int argc, char* argv[], RasShell* shell) {
- if (argc > 2) {
- fprintf (stderr, "%s: too many arguments\n", argv[0]);
- return 1;
- }
- if (argc < 2) {
- extern char** environ;
- for (int i = 0; environ[i] != NULL; i++) {
- puts (environ[i]);
- }
- } else {
- char* res = getenv (argv[1]);
- if (res == NULL) {
- return 1;
- }
- puts (res);
- }
- return 0;
-}
-
-static int ras_shell_builtin_pwd (int argc, char* argv[], RasShell* shell) {
- char* cwd = xgetcwd ();
- if (cwd == NULL) {
- fprintf (stderr, "%s: cannot get working directory: %s\n", argv[0], strerror (errno));
- return 1;
- }
- puts (cwd);
- free (cwd);
- return 0;
-}
-
-static int ras_shell_builtin_setenv (int argc, char* argv[], RasShell* shell) {
- if (argc != 3) {
- fprintf (
- stderr, "%s: too %s arguments\n", argv[0], argc > 3 ? "many" : "few");
- return 1;
- }
- return - setenv (argv[1], argv[2], 1);
-}
-
-static int ras_shell_builtin_umask (int argc, char* argv[], RasShell* shell) {
- if (argc > 2) {
- fprintf (stderr, "%s: too many arguments\n", argv[0]);
- return 1;
- }
-
- if (argc < 2) {
- mode_t old_mode = umask (0777);
- umask (old_mode);
- printf ("%04o\n", old_mode);
- } else {
- int mode_int;
- if (sscanf (argv[1], "%o", &mode_int) < 0) {
- fprintf (stderr, "%s: `%s\' is not a valid octal number\n", argv[0], argv[1]);
- return 1;
- }
- mode_t new_mode = mode_int;
- umask (new_mode);
- }
- return 0;
-}
-
static void ras_shell_cmd_comp_init (RasShellCmdComp* comp) {
comp->arg = array_create (sizeof (char*), 0);
comp->redir_stdin = array_create (sizeof (char), 0);
@@ -230,10 +90,6 @@ static void ras_shell_cmd_comp_destroy (RasShellCmdComp* comp) {
static void complete_string (Array*** ws, int* append,
RasShellCmdComp* comp, bool reinit) {
- if (array_getmax (*ws[*append]) <= 0) {
- return;
- }
-
char zero = '\0';
array_pushback (*ws[*append], &zero);
if (*append == APPEND_STR) {
@@ -294,8 +150,6 @@ static int ras_shell_cmd_parse (
}
if (is_quoted) {
if (*p == quote_char) {
- /* complete a string */
- complete_string (ws, &append, &comp, true);
is_quoted = false;
is_escaped = false;
ignore_esc = false;
@@ -378,17 +232,6 @@ static void ras_shell_cmd_print (RasShellCmd* cmd) {
}
static int ras_shell_cmd_run (RasShellCmd* cmd, RasShell* shell) {
- const static RasShellBuiltin builtins[] = {
- { "cd", ras_shell_builtin_cd },
- { "echo", ras_shell_builtin_echo },
- { "exit", ras_shell_builtin_exit },
- { "logout", ras_shell_builtin_logout },
- { "printenv", ras_shell_builtin_printenv },
- { "pwd", ras_shell_builtin_pwd },
- { "setenv", ras_shell_builtin_setenv },
- { "umask", ras_shell_builtin_umask },
- { NULL, NULL }
- };
ListNode* iter = list_node_front (cmd->argrp);
pid_t child;
@@ -407,13 +250,13 @@ static int ras_shell_cmd_run (RasShellCmd* cmd, RasShell* shell) {
RasShellCmdComp* comp = list_data (iter);
RasShellFunc builtin_func = NULL;
- for (int j = 0; builtins[j].cmd != NULL; j++) {
+ for (int j = 0; ras_shell_builtins[j].cmd != NULL; j++) {
char* cmd = STRV (array_data (comp->arg))[0];
if (cmd == NULL) {
continue;
}
- if (strcmp (builtins[j].cmd, cmd) == 0) {
- builtin_func = builtins[j].func;
+ if (strcmp (ras_shell_builtins[j].cmd, cmd) == 0) {
+ builtin_func = ras_shell_builtins[j].func;
break;
}
}
diff --git a/hw1/shell.h b/hw1/shell.h
index 1b73d35..4b9e343 100644
--- a/hw1/shell.h
+++ b/hw1/shell.h
@@ -1,6 +1,36 @@
#ifndef RAS_SHELL_H
#define RAS_SHELL_H
+#include "basic-list.h"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <unistd.h>
+
+typedef struct {
+ char* name; /* This is argv[0]. Do not modify or free it. */
+ uint64_t count;
+ List* saved_list; /* A list of RasShellSaved */
+ char* saved_tmpdir;
+ int last_rval;
+ pid_t pid;
+ pid_t pgid;
+ int attr_login : 1; /* login shell */
+ int attr_rshell : 1; /* restricted shell */
+ int attr_debug : 1; /* debug message */
+ int attr_isterm : 1; /* shell is run in a terminal */
+ char* user_name;
+ char user_ps;
+ int req_exit : 1; /* request for exit */
+ int req_exit_status; /* requested exit status */
+ int term_fd; /* shell terminal fd */
+ struct termios tmode; /* shell terminal mode */
+} RasShell;
+
+typedef int (*RasShellFunc) (int argc, char* argv[], RasShell* shell);
+typedef char* (*RasShellRead) (void* data);
+
int ras_shell_main (int argc, char* argv[]);
#endif /* RAS_SHELL_H */