修正前 修正後
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>   // fork, execvp #include <unistd.h>   // fork, execvp
#include <sys/wait.h> // waitpid #include <sys/wait.h> // waitpid
#include <glob.h>     // glob #include <glob.h>     // glob
   
#define MAX_CMD_LEN 1024 #define MAX_CMD_LEN 1024
#define MAX_ARGS 100 #define MAX_ARGS 100
   
// コマンドをスペースで分割する関数 // コマンドをスペースで分割する関数
void parse_command(char *cmd, char *argv[]) { void parse_command(char *cmd, char *argv[]) {
    char *token = strtok(cmd, " \n");     char *token = strtok(cmd, " \n");
    int i = 0;     int i = 0;
    while (token != NULL) {     while (token != NULL) {
        argv[i++] = token;         argv[i++] = token;
        token = strtok(NULL, " \n");         token = strtok(NULL, " \n");
    }     }
    argv[i] = NULL; // 最後の引数をNULLで終わらせる     argv[i] = NULL; // 最後の引数をNULLで終わらせる
} }
   
.  // 引用符を削除する関数
  void remove_quotes(char *str) {
      char *src = str, *dst = str;
      while (*src) {
          if (*src == '"' || *src == '\'') {
              src++;  // 引用符をスキップ
          } else {
              *dst++ = *src++;
          }
      }
      *dst = '\0';  // 文字列の終端を追加
  }
   
// 引数リストにパス名展開を適用する関数 // 引数リストにパス名展開を適用する関数
int expand_arguments(char *argv[], char **expanded_argv) { int expand_arguments(char *argv[], char **expanded_argv) {
    glob_t glob_result;     glob_t glob_result;
    int argc = 0; // 展開後の引数数     int argc = 0; // 展開後の引数数
   
    for (int i = 0; argv[i] != NULL; i++) {     for (int i = 0; argv[i] != NULL; i++) {
.        if (strchr(argv[i], '*') || strchr(argv[i], '?') || strchr(argv[i], '[')) {          // 引用符が含まれている場合は展開しない 
            // パス名展開が必要な場合          if ((strchr(argv[i], '*') || strchr(argv[i], '?') || strchr(argv[i], '[')) && 
              (argv[i][0] != '"' && argv[i][0] != '\'')) { // 引用符外でパス名展開 
            if (glob(argv[i], GLOB_NOCHECK | GLOB_TILDE, NULL, &glob_result) != 0) {             if (glob(argv[i], GLOB_NOCHECK | GLOB_TILDE, NULL, &glob_result) != 0) {
                perror("glob failed");                 perror("glob failed");
                return -1;                 return -1;
            }             }
            // 展開された結果を追加             // 展開された結果を追加
            for (size_t j = 0; j < glob_result.gl_pathc; j++) {             for (size_t j = 0; j < glob_result.gl_pathc; j++) {
                if (argc >= MAX_ARGS - 1) {                 if (argc >= MAX_ARGS - 1) {
                    fprintf(stderr, "Too many arguments after glob expansion\n");                     fprintf(stderr, "Too many arguments after glob expansion\n");
                    globfree(&glob_result);                     globfree(&glob_result);
                    return -1;                     return -1;
                }                 }
                expanded_argv[argc++] = strdup(glob_result.gl_pathv[j]);                 expanded_argv[argc++] = strdup(glob_result.gl_pathv[j]);
            }             }
            globfree(&glob_result); // メモリを解放             globfree(&glob_result); // メモリを解放
        } else {         } else {
.              // 引用符を取り除く
              remove_quotes(argv[i]);
   
            // パス名展開が不要な場合             // パス名展開が不要な場合
            if (argc >= MAX_ARGS - 1) {             if (argc >= MAX_ARGS - 1) {
                fprintf(stderr, "Too many arguments\n");                 fprintf(stderr, "Too many arguments\n");
                return -1;                 return -1;
            }             }
            expanded_argv[argc++] = strdup(argv[i]);             expanded_argv[argc++] = strdup(argv[i]);
        }         }
    }     }
    expanded_argv[argc] = NULL; // 最後にNULLを追加     expanded_argv[argc] = NULL; // 最後にNULLを追加
    return argc;     return argc;
} }
   
int main() { int main() {
    char cmd[MAX_CMD_LEN]; // コマンド入力用のバッファ     char cmd[MAX_CMD_LEN]; // コマンド入力用のバッファ
    char *argv[MAX_ARGS];  // コマンド引数     char *argv[MAX_ARGS];  // コマンド引数
    char *expanded_argv[MAX_ARGS]; // 展開後の引数     char *expanded_argv[MAX_ARGS]; // 展開後の引数
    pid_t pid;     pid_t pid;
    int status;     int status;
   
    // シェルのメインループ     // シェルのメインループ
    while (1) {     while (1) {
        // プロンプトを表示         // プロンプトを表示
        fprintf(stderr, "mysh> ");         fprintf(stderr, "mysh> ");
   
        // コマンドを読み込む         // コマンドを読み込む
        if (fgets(cmd, sizeof(cmd), stdin) == NULL) {         if (fgets(cmd, sizeof(cmd), stdin) == NULL) {
            if (feof(stdin)) {             if (feof(stdin)) {
                break; // EOFが入力された場合、終了                 break; // EOFが入力された場合、終了
            }             }
            perror("fgets failed");             perror("fgets failed");
            continue;             continue;
        }         }
   
        // コマンドを解析         // コマンドを解析
        parse_command(cmd, argv);         parse_command(cmd, argv);
   
        // 空のコマンドの場合は次の入力へスキップ         // 空のコマンドの場合は次の入力へスキップ
        if (argv[0] == NULL) {         if (argv[0] == NULL) {
            continue;             continue;
        }         }
   
        // 終了コマンドの場合         // 終了コマンドの場合
        if (strcmp(argv[0], "exit") == 0) {         if (strcmp(argv[0], "exit") == 0) {
            break;             break;
        }         }
   
        // 引数を展開         // 引数を展開
        if (expand_arguments(argv, expanded_argv) == -1) {         if (expand_arguments(argv, expanded_argv) == -1) {
            fprintf(stderr, "Argument expansion failed\n");             fprintf(stderr, "Argument expansion failed\n");
            continue;             continue;
        }         }
   
        // 子プロセスを作成してコマンドを実行         // 子プロセスを作成してコマンドを実行
        pid = fork();         pid = fork();
        if (pid == -1) {         if (pid == -1) {
            perror("fork failed");             perror("fork failed");
            exit(1);             exit(1);
        }         }
   
        // 子プロセス         // 子プロセス
        if (pid == 0) {         if (pid == 0) {
            // execvpを使用してコマンドを実行             // execvpを使用してコマンドを実行
            if (execvp(expanded_argv[0], expanded_argv) == -1) {             if (execvp(expanded_argv[0], expanded_argv) == -1) {
                perror("exec failed");                 perror("exec failed");
                exit(1);                 exit(1);
            }             }
        }         }
   
        // 親プロセス         // 親プロセス
        if (waitpid(pid, &status, 0) == (pid_t)-1) { // 子プロセスの終了を待つ         if (waitpid(pid, &status, 0) == (pid_t)-1) { // 子プロセスの終了を待つ
            perror("waitpid failed");             perror("waitpid failed");
            exit(1);             exit(1);
        }         }
   
        // メモリを解放         // メモリを解放
        for (int i = 0; expanded_argv[i] != NULL; i++) {         for (int i = 0; expanded_argv[i] != NULL; i++) {
            free(expanded_argv[i]);             free(expanded_argv[i]);
        }         }
    }     }
   
    printf("Exiting shell...\n");     printf("Exiting shell...\n");
    return 0;     return 0;
} }