1// builtins.c
2// 쉘 내장 명령어 구현
3// cd, pwd, echo, help, export, env 등
4// 컴파일: gcc -c builtins.c 또는 다른 파일과 함께 링크
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <unistd.h>
10
11// 내장 명령어 이름들
12const char* builtin_names[] = {
13 "cd",
14 "pwd",
15 "echo",
16 "exit",
17 "help",
18 "export",
19 "env",
20 NULL
21};
22
23// cd: 디렉토리 변경
24int builtin_cd(char** args) {
25 const char* path;
26
27 if (args[1] == NULL) {
28 // 인자 없으면 홈 디렉토리
29 path = getenv("HOME");
30 if (path == NULL) {
31 fprintf(stderr, "cd: HOME 환경변수가 설정되지 않음\n");
32 return 1;
33 }
34 } else if (strcmp(args[1], "-") == 0) {
35 // cd - : 이전 디렉토리
36 path = getenv("OLDPWD");
37 if (path == NULL) {
38 fprintf(stderr, "cd: OLDPWD 환경변수가 설정되지 않음\n");
39 return 1;
40 }
41 printf("%s\n", path);
42 } else if (strcmp(args[1], "~") == 0) {
43 path = getenv("HOME");
44 } else {
45 path = args[1];
46 }
47
48 // 현재 디렉토리 저장
49 char oldpwd[1024];
50 getcwd(oldpwd, sizeof(oldpwd));
51
52 if (chdir(path) != 0) {
53 perror("cd");
54 return 1;
55 }
56
57 // OLDPWD, PWD 환경변수 갱신
58 setenv("OLDPWD", oldpwd, 1);
59
60 char newpwd[1024];
61 getcwd(newpwd, sizeof(newpwd));
62 setenv("PWD", newpwd, 1);
63
64 return 0;
65}
66
67// pwd: 현재 디렉토리 출력
68int builtin_pwd(char** args) {
69 (void)args; // 사용하지 않음
70
71 char cwd[1024];
72 if (getcwd(cwd, sizeof(cwd)) != NULL) {
73 printf("%s\n", cwd);
74 return 0;
75 }
76 perror("pwd");
77 return 1;
78}
79
80// echo: 인자 출력
81int builtin_echo(char** args) {
82 int newline = 1;
83 int start = 1;
84
85 // -n 옵션: 줄바꿈 없이 출력
86 if (args[1] && strcmp(args[1], "-n") == 0) {
87 newline = 0;
88 start = 2;
89 }
90
91 for (int i = start; args[i]; i++) {
92 printf("%s", args[i]);
93 if (args[i + 1]) printf(" ");
94 }
95
96 if (newline) printf("\n");
97 return 0;
98}
99
100// help: 도움말
101int builtin_help(char** args) {
102 (void)args;
103
104 printf("\n=== Mini Shell 도움말 ===\n\n");
105 printf("내장 명령어:\n");
106 printf(" cd [디렉토리] - 디렉토리 변경\n");
107 printf(" pwd - 현재 디렉토리 출력\n");
108 printf(" echo [텍스트] - 텍스트 출력\n");
109 printf(" export VAR=값 - 환경변수 설정\n");
110 printf(" env - 환경변수 목록\n");
111 printf(" help - 이 도움말\n");
112 printf(" exit - 쉘 종료\n");
113 printf("\n외부 명령어는 PATH에서 검색됩니다.\n\n");
114
115 return 0;
116}
117
118// export: 환경변수 설정
119int builtin_export(char** args) {
120 if (args[1] == NULL) {
121 // 인자 없으면 환경변수 목록 출력
122 extern char** environ;
123 for (char** env = environ; *env; env++) {
124 printf("export %s\n", *env);
125 }
126 return 0;
127 }
128
129 // VAR=value 형식 파싱
130 for (int i = 1; args[i]; i++) {
131 char* eq = strchr(args[i], '=');
132 if (eq) {
133 *eq = '\0';
134 setenv(args[i], eq + 1, 1);
135 *eq = '=';
136 } else {
137 // = 없으면 빈 값으로 설정
138 setenv(args[i], "", 1);
139 }
140 }
141
142 return 0;
143}
144
145// env: 환경변수 출력
146int builtin_env(char** args) {
147 (void)args;
148
149 extern char** environ;
150 for (char** env = environ; *env; env++) {
151 printf("%s\n", *env);
152 }
153 return 0;
154}
155
156// 내장 명령어인지 확인하고 실행
157// 반환: -1 (내장 명령어 아님), 0+ (실행 결과)
158int execute_builtin(char** args) {
159 if (args[0] == NULL) return -1;
160
161 if (strcmp(args[0], "cd") == 0) return builtin_cd(args);
162 if (strcmp(args[0], "pwd") == 0) return builtin_pwd(args);
163 if (strcmp(args[0], "echo") == 0) return builtin_echo(args);
164 if (strcmp(args[0], "help") == 0) return builtin_help(args);
165 if (strcmp(args[0], "export") == 0) return builtin_export(args);
166 if (strcmp(args[0], "env") == 0) return builtin_env(args);
167
168 return -1; // 내장 명령어 아님
169}
170
171// 테스트용 메인 함수 (독립 실행 가능)
172#ifdef TEST_BUILTINS
173int main(void) {
174 char input[1024];
175 char* args[64];
176
177 printf("=== 내장 명령어 테스트 ===\n");
178 printf("테스트 명령어: cd, pwd, echo, help, export, env, exit\n\n");
179
180 while (1) {
181 printf("builtin> ");
182 fflush(stdout);
183
184 if (fgets(input, sizeof(input), stdin) == NULL) {
185 break;
186 }
187
188 // 파싱
189 int argc = 0;
190 char* token = strtok(input, " \t\n");
191 while (token && argc < 63) {
192 args[argc++] = token;
193 token = strtok(NULL, " \t\n");
194 }
195 args[argc] = NULL;
196
197 if (argc == 0) continue;
198
199 // exit 체크
200 if (strcmp(args[0], "exit") == 0) {
201 printf("종료합니다.\n");
202 break;
203 }
204
205 // 내장 명령어 실행
206 int result = execute_builtin(args);
207 if (result == -1) {
208 printf("알 수 없는 명령어: %s\n", args[0]);
209 }
210 }
211
212 return 0;
213}
214#endif