PageRenderTime 44ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/bash.c

https://github.com/kimquy/bashlike
C | 526 lines | 436 code | 79 blank | 11 comment | 72 complexity | bb0878d43a6697e136b028c8e9477dc4 MD5 | raw file
  1. // Long Nguyen
  2. // Spring 2012
  3. // Build a bash-liked shell
  4. // New features added: aliasing, history, and pipe
  5. // list of new commands: alias, unalias, history, and |
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include <sys/types.h>
  10. #include <unistd.h>
  11. struct node{
  12. char key[10];
  13. char command[100];
  14. struct node *next;
  15. struct node *parent;
  16. struct node *last;
  17. int count;
  18. };
  19. typedef struct node* nodeptr;
  20. void add_node(nodeptr n, char k[], char cmd[]){
  21. n->count = n->count + 1;
  22. if(n==NULL){
  23. strcpy(n->key,k);
  24. strcpy(n->command, cmd);
  25. n->next = NULL;
  26. n->parent = NULL;
  27. }
  28. else{
  29. nodeptr temp;
  30. temp = malloc(sizeof(struct node));
  31. strcpy(temp->key,k);
  32. strcpy(temp->command, cmd);
  33. if(n->count == 1 ){
  34. n->next = temp;
  35. temp->next = NULL;
  36. temp->parent = n;
  37. n->last = temp;
  38. }
  39. else{
  40. n->next->parent = temp;
  41. temp->next = n->next;
  42. temp->parent = n;
  43. n->next = temp;
  44. }
  45. }
  46. }
  47. void delete_node(nodeptr n, char k[]){
  48. nodeptr temp;
  49. temp = n;
  50. while(temp != NULL){
  51. if(strcmp(temp->key, k) == 0){
  52. if(n->count == 1){
  53. n = NULL;
  54. return;
  55. }
  56. nodeptr temp1;
  57. temp1 = temp->parent;
  58. temp1->next = temp->next;
  59. free(temp);
  60. }
  61. temp = temp->next;
  62. }
  63. }
  64. // break the command into arguments then storing it
  65. voids store_arg(char* arg[], char command[]){
  66. int i=0;
  67. char *temp;
  68. int count = 0;
  69. temp = strtok(command," :1234567890'=");
  70. while(temp != NULL){
  71. arg[i] = temp;
  72. temp = strtok(NULL," :1234567890'=");
  73. i++;
  74. }
  75. arg[i] = NULL;
  76. }
  77. // read command from standard input
  78. void read_cmd_from_file(char cmd[], FILE *f){
  79. char c = 's';
  80. int i=0;
  81. while(c != '\n' && !feof(f)){
  82. c = fgetc(f);
  83. cmd[i] = c;
  84. i++;
  85. }
  86. cmd[i-1] = '\0';
  87. }
  88. // execute the command
  89. int exec_cmd(char* arg[], char command[]){
  90. int status;
  91. pid_t child;
  92. child = fork();
  93. if(child != 0){
  94. wait(&status);
  95. }
  96. else{
  97. if (execvp(arg[0],arg) == -1){
  98. //cd command
  99. if(strcmp(arg[0], "cd") ==0){
  100. if(arg[1] == NULL){
  101. printf("There is no directory.\n");
  102. return;
  103. }
  104. else{
  105. chdir(arg[1]);
  106. return;
  107. }
  108. }
  109. printf("Unknown command.\n");
  110. exit(1);
  111. }
  112. else{
  113. execvp(arg[0], arg);
  114. EXIT_SUCCESS;
  115. }
  116. }
  117. }
  118. // empty argument list
  119. void empty(char *arg[]){
  120. int i=0;
  121. while(i<30){
  122. arg[i] = NULL;
  123. i++;
  124. }
  125. }
  126. void cmd_in_alias(char str[], char cmd[]){
  127. int i;
  128. int first;
  129. char c;
  130. for(i=0; i<100; i++){
  131. if(str[i] == '\''){
  132. first = i+1;
  133. break;
  134. }
  135. }
  136. c = str[first];
  137. i=0;
  138. while(c!= '\''){
  139. cmd[i] = str[first];
  140. i++;
  141. first++;
  142. c = str[first];
  143. }
  144. }
  145. int find_cmd_in_alias_list(nodeptr n, char key[]){
  146. nodeptr temp;
  147. temp = n;
  148. while(temp != NULL){
  149. if(strcmp(temp->key, key) == 0){
  150. char *arg_list[30];
  151. store_arg(arg_list, temp->command);
  152. exec_cmd(arg_list, key);
  153. return 1;
  154. }
  155. temp = temp->next;
  156. }
  157. return 0;
  158. }
  159. void unalias(nodeptr n, char key[]){
  160. delete_node(n, key);
  161. }
  162. void exec_by_num_history(char cmd[], char *arg_list[], FILE *f, FILE *h){
  163. int counter = history_counter();
  164. char str[100];
  165. int i=0;
  166. int j=1;
  167. int num;
  168. while(j<strlen(cmd)){
  169. str[i] = cmd[j];
  170. j++;
  171. i++;
  172. }
  173. num = atoi(str);
  174. i=1;
  175. char c;
  176. char command[200];
  177. fseek(h,0,SEEK_SET);
  178. if(num > counter){
  179. printf("bash: !%d: event not found\n", num);
  180. return;
  181. }
  182. while(i<=counter){
  183. if(i == num){
  184. read_cmd_from_file(command, h);
  185. store_arg(arg_list, command);
  186. exec_cmd(arg_list,command);
  187. break;
  188. }
  189. while(1){
  190. c = getc(h);
  191. if(c=='\n'){
  192. i++;
  193. break;
  194. }
  195. }
  196. }
  197. }
  198. void exec_path_cmd(FILE *f, char *arg_list[]){
  199. if(strlen(arg_list[2]) == 0){
  200. return;
  201. }else{
  202. fseek(f,0,SEEK_END);
  203. fputc(':',f);
  204. fprintf(f, "%s", arg_list[2]);
  205. }
  206. }
  207. int history_counter(){
  208. FILE *f= fopen(".nsh_history", "r");
  209. char c = getc(f);
  210. int x=1;
  211. while(!feof(f)){
  212. if(c=='\n'){
  213. x++;
  214. }
  215. c =getc(f);
  216. }
  217. fclose(f);
  218. return x;
  219. }
  220. int temp_counter(){
  221. FILE *f= fopen("temporary.txt", "r");
  222. char c = getc(f);
  223. int x=1;
  224. while(!feof(f)){
  225. if(c=='\n'){
  226. x++;
  227. }
  228. c =getc(f);
  229. }
  230. fclose(f);
  231. return x;
  232. }
  233. //store the successfull command to history and write to .nsh_history file
  234. void store_cmd_to_history(char cmd[], FILE *ff){
  235. int counter = history_counter();
  236. int history_limit;
  237. FILE *nhistory = fopen(".login","r");
  238. fscanf(nhistory, "%d", &history_limit);
  239. fclose(nhistory);
  240. if(counter < history_limit){
  241. FILE *f = fopen(".nsh_history", "a");
  242. fprintf(f, "%s\n", cmd);
  243. fclose(f);
  244. }
  245. else{
  246. FILE *f = fopen(".nsh_history","r");
  247. FILE *temp = fopen("temporary.txt","w+");
  248. char str[200];
  249. fgets(str,200,f);
  250. int i=1;
  251. int counter = history_counter();
  252. while(i<=counter){
  253. fgets(str,200,f);
  254. fprintf(temp, "%s", str);
  255. i++;
  256. }
  257. fclose(temp);
  258. FILE *t = fopen("temporary.txt","r");
  259. f = fopen(".nsh_history","w+");
  260. i = 1;
  261. counter = temp_counter();
  262. while(i<=counter){
  263. fgets(str,200,t);
  264. fprintf(f, "%s", str);
  265. i++;
  266. }
  267. fprintf(f, "\n");
  268. fprintf(f, "%s\n", cmd);
  269. remove("temporary.txt");
  270. fclose(f);
  271. }
  272. }
  273. void set_counter_history(FILE *f, int x){
  274. fprintf(f, "%d\n", x);
  275. }
  276. void print_history(FILE *ff){
  277. FILE *f = fopen(".nsh_history", "r");
  278. char str[200];
  279. int counter = history_counter();
  280. int x = 1;
  281. while(x < counter){
  282. fscanf(f,"%[^\n]%*c", str);
  283. printf(" %d %s\n",x,str);
  284. x++;
  285. }
  286. fclose(f);
  287. }
  288. void exec_last_cmd(FILE *l, FILE *h, char *arg_list[]){
  289. int counter = history_counter();
  290. char c;
  291. int i=1;
  292. fseek(h,0,SEEK_SET);
  293. char cmd[200];
  294. while(i<=counter){
  295. if(i==(counter-1)){
  296. read_cmd_from_file(cmd, h);
  297. store_arg(arg_list, cmd);
  298. exec_cmd(arg_list,cmd);
  299. }
  300. read_cmd_from_file(cmd,h);
  301. i++;
  302. }
  303. }
  304. void pipe_cmd(char str[]){
  305. int fd[2];
  306. pipe(fd);
  307. char cmd1[100];
  308. char cmd2[100];
  309. char *arg_list1[10];
  310. char *arg_list2[10];
  311. int i=0;
  312. while(str[i] != '|'){
  313. cmd1[i] = str[i];
  314. i++;
  315. }
  316. i++;
  317. store_arg(arg_list1,cmd1);
  318. int j=0;
  319. while(i < strlen(str)){
  320. cmd2[j] = str[i];
  321. j++;
  322. i++;
  323. }
  324. store_arg(arg_list2,cmd2);
  325. int status;
  326. pid_t pid = fork();
  327. if(pid!=0){
  328. wait(&status);
  329. }else{
  330. if (!fork()) {
  331. close(1);
  332. dup(fd[1]);
  333. close(fd[0]);
  334. execvp(arg_list1[0], arg_list1);
  335. exit(EXIT_SUCCESS);
  336. } else {
  337. close(0);
  338. dup(fd[0]);
  339. close(fd[1]);
  340. execvp(arg_list2[0], arg_list2);
  341. exit(EXIT_SUCCESS);
  342. }
  343. }
  344. }
  345. int find_pipe(char str[]){
  346. int i=0;
  347. while(i<strlen(str)){
  348. if(str[i] == '|'){
  349. return 1;
  350. }
  351. i++;
  352. }
  353. return 0;
  354. }
  355. int main(){
  356. char command[1000];
  357. char *arg_list[30];
  358. char alias_cmd[1000];
  359. char temp[1000];
  360. nodeptr alias_list;
  361. alias_list = malloc(sizeof(struct node));
  362. FILE *input;
  363. input = fopen(".nshsrc", "r");
  364. if(!input){
  365. printf("Failed to open input file\n");
  366. return;
  367. }
  368. FILE* bash;
  369. bash = fopen(".bash_profile","w+");
  370. if(!bash){
  371. printf("Failed to open path file\n");
  372. return;
  373. }
  374. FILE* history_output = fopen(".nsh_history", "r");
  375. if(!history_output){
  376. history_output = fopen(".nsh_history", "w+");
  377. }
  378. fclose(history_output);
  379. FILE *login = fopen(".login","w+");
  380. if(!input){
  381. printf("Failed to open .login\n");
  382. return;
  383. }
  384. set_counter_history(login,20);
  385. fclose(login);
  386. while(!feof(input)){
  387. read_cmd_from_file(command, input);
  388. printf("?: ");
  389. strcpy(temp,command);
  390. if(strcmp(command, "exit") == 0){
  391. store_cmd_to_history(temp, history_output);
  392. break;
  393. }
  394. printf("%s",command);
  395. printf("\n");
  396. store_arg(arg_list, command);
  397. if(strcmp(arg_list[0], "alias") == 0){
  398. cmd_in_alias(temp, alias_cmd);
  399. add_node(alias_list, arg_list[1], alias_cmd);
  400. store_cmd_to_history(temp, history_output);
  401. }
  402. else if(strcmp(arg_list[0], "unalias") == 0){
  403. unalias(alias_list, arg_list[1]);
  404. store_cmd_to_history(temp, history_output);
  405. }
  406. else if(strcmp(arg_list[0], "!!") == 0){
  407. empty(arg_list);
  408. exec_last_cmd(login,history_output,arg_list);
  409. store_cmd_to_history(temp, history_output);
  410. }
  411. else if(strcmp(arg_list[0], "!") == 0){
  412. empty(arg_list);
  413. exec_by_num_history(temp, arg_list, login, history_output);
  414. store_cmd_to_history(temp, history_output);
  415. }
  416. else if(strcmp(arg_list[0], "history") == 0){
  417. store_cmd_to_history(temp, history_output);
  418. print_history(history_output);
  419. }
  420. else if(strcmp(arg_list[0], "$PATH") == 0){
  421. printf("bash: ");
  422. char str[1000];
  423. fseek(bash, 1, SEEK_SET);
  424. fgets(str,1000,bash);
  425. printf("%s",str);
  426. printf("\n");
  427. store_cmd_to_history(temp, history_output);
  428. }
  429. else if(strcmp(arg_list[0], "PATH") == 0 && strcmp(arg_list[1], "$PATH") == 0){
  430. exec_path_cmd(bash,arg_list);
  431. store_cmd_to_history(temp, history_output);
  432. }
  433. else if(find_pipe(temp) == 1 ){
  434. pipe_cmd(temp);
  435. store_cmd_to_history(temp, history_output);
  436. }
  437. else{
  438. if(find_cmd_in_alias_list(alias_list, temp) ==1){
  439. continue;
  440. }
  441. store_cmd_to_history(temp, history_output);
  442. exec_cmd(arg_list, temp);
  443. empty(arg_list);
  444. }
  445. }
  446. return 0;
  447. }