#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <wait.h>
#include <signal.h>

int split(char *string, char c, char **result);
void skip();
int isBackGround(char *command);
void (*oldhandler)();
int bbazig();

int main(int argc,char *argv[],char *envp[]){
  char command[PATH_MAX];
  char *commands[64];
  int pid,c,status,command_num,counter,n;
 
  oldhandler=signal(SIGINT,bbazig);
   
  while(1){
    int fd,i;
    char *temp[64];
    int process_counter;
    int flag; /* bg 인지 확인하는 명령임. */
   
    do{
      /* 입력을 받기를 기다리다가 명령을 받는다.  */
      waitpid(-1,&status,WNOHANG);
      printf("11982241>#");  /* 프롬프트 */
      flag = 0;
      gets(command);  /* 명령 입력받기 */
     
      /* 파이프 처리....  */
      command_num = split(command,'|',commands);
     
      n = split(commands[0],' ',temp);
    }  
    while(strcmp(temp[0],"") == 0);
   
    if((c = strcmp(temp[0],"exit")) == 0){
      for(counter = 0 ;counter < n ; counter++)
        free(temp[counter]);
      break;    /* 군소리 없이 끝내기 */
    }
    if((c = strcmp(temp[0],"help")) == 0){
        printf ("이 셸을 끝내시려면 exit를 치시는 것이 가장 좋습니다.\n");
    printf ("그렇지 않으면 반항을 하는 특징이 있습니다.\n");
    printf ("혹시 Ctrl+C로 종료하시려 하신다면 3초간 기다려 주세요.\n");
    printf ("파이프나 리디렉션 사용시 상당히 반항하는 특징이 있습니다.\n");
    printf ("웬만하면 사용하지 마세요..... 기타 등등. 중얼중얼중얼....\n");
    } /*도움말이지만 도움이 될 지는 의문*/

    /* cd 명령에서 문제 생겼을 때 */
    if((c = strcmp(temp[0],"cd")) == 0){
      if(chdir(temp[1]) == -1)
    printf("%s:%s\n",temp[1],"그런 녀석 없답니다.^^;;;;");
      for(counter = 0;counter < n; counter++)
    free(temp[counter]);
      continue;
    }
   
    for(counter = 0; counter < command_num; counter++){
      int n,m;
      char *options[64];
      char *redirect[4];
     
      if(counter != command_num -1){
        printf("여기서는 파이프 처리가 될 리가 없죠? ^^;;;;\n");
        printf("아직 파이프를 쓰면 죽어 버리는데요......\n");
        printf("그럴 경우에는 주저없이 Ctrl+C 해 주세요.\n");
      }
     
      flag = isBackGround(commands[counter]);
     
      pid = fork();
      if(pid == 0){
        /* 파이프를 쓸 때  */
        if(command_num != 1) printf("");
        /* 리디렉션이 들어왔을 때 */
        if(split(commands[counter],'>',redirect) > 1||split(commands[counter],'<',redirect) > 1){
            printf("리디렉션은 먹지않습니다!!!! 꺄하하하하하하~~~~~\n");
            printf("실력이 이것밖에 안 되는데 어떻게 하라고요!!!!!! ^^;;;;\n");
        }else{
          n = split(commands[counter],' ',options);
          execvp(options[0],options);
        }
        printf("%s\n%s\n",options[0],"command not found");
        _exit(1);
      }else{ 
   
        if(counter != 0 && command_num != 1){
          close(fd);
        }
        if(counter != command_num -1){
          printf("");

        }
   
        for(i = 0;i < n;i++) free(options[i]);
      }
    }
   
    for(i = 0;i < command_num;i++) free(commands[i]);

    if(flag == 0){
      for(process_counter=0;process_counter<command_num;process_counter++)
        wait(&status);
    }
  }
 
  exit(0);
}

/* 문자열 자르는 함수. 인터넷 뒤지다가 찾은 함수를 그냥 인용. */
/* 출처는 북마크를 안 해서 잊어버림. --+ */
  int split(char *string,char c,char **result){
  int counter = 0;
  char *workspace;
  char *workspace_backup;
  char *temp;
 
  workspace = (char *)malloc(strlen(string) +1);
  if(workspace == NULL){
    printf("%s\n","Memory allocation error");
    return 0;
  }

  workspace_backup = workspace;
  strcpy(workspace,string);
 
  while(*workspace == c){
    workspace++;
  }
 
  while((temp = strchr(workspace,c)) != NULL){
    temp[0] = '\0';
   
    while(temp[1] == c){
      temp++;
    }
   
   
    result[counter] = (char *)malloc(strlen(workspace) + 1);
    if(result[counter] == NULL){
      printf("%s\n","Memory allocation error");
      return 0;
    }
    strcpy(result[counter],workspace);
    workspace = ++temp;
    ++counter;
  }
 
  result[counter] = (char *)malloc(strlen(workspace) + 1);
  if(result[counter] == NULL){
    printf("%s\n","Memory allocation error");
    return 0;
  }
  strcpy(result[counter],workspace);
  ++counter;
  result[counter] = '\0';   /* Null Termination */
 
  free(workspace_backup);
  return counter;
}

/* 한줄 내리기...... */
void skip(){
  putchar('\n');
}

/* &를 구현합니다.  */
int isBackGround(char *command){
  char *temp;
  temp = strchr(command,'&');
  if(temp == NULL){
    return 0;
  }else{
    *temp = '\0';
    return 1;
  }
}

/* Ctrl+C 눌렀을 때.... */
int bbazig() {
    printf("허억~~~~~ 내가 사용자에게 살해당하다니~~~~!!!!!!!\n");
    printf("죽기 전에 마지막으로 하나 알려드리자면\n");
    printf("이 셸을 만들고 있는 사람은 \n");
    printf("학번은 11982241. 수학과 4학년 전혜진입니다.\n");
    alarm(1);
//*(oldhandler)();
}