builtins.c

Download
c 215 lines 5.1 KB
  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