romko11l

Untitled

Nov 16th, 2019
49
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 14.54 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/types.h>
  4. #include <sys/wait.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7. #include <sys/stat.h>
  8. #include <fcntl.h>
  9.  
  10.  
  11. const int n = 5; // на сколько элементов выделится память (символов) при заполнении строки (read_line) (не делать меньше 3)
  12. const int m = 5; // на сколько элементов (символов) выделится память в функции strtok
  13. const int t = 5; // на сколько строк выделится память в функции parcer
  14.  
  15. void freedom (char **base)
  16. {
  17.     int pos=0;
  18.     while (base[pos])
  19.     {
  20.         free(base[pos]);
  21.         pos++;
  22.     }
  23.     free(base);
  24. }
  25.  
  26. char *read_line(FILE *f, int *check) // в check-е вернется 1, если в строке обнаружен EOF; num_quotes - число кавычек
  27. {
  28.     int c, pos=0, size;
  29.     char *str, *temp;
  30.     size=n;
  31.     str=malloc(sizeof(char)*size);
  32.     *check=0;
  33.    
  34.     if (!str)
  35.     {
  36.         printf("memory allocation error\n");
  37.         exit(1);
  38.     }
  39.    
  40.     while (1)
  41.     {
  42.         c=fgetc(f);
  43.         if ((c==EOF)||(c=='\n'))
  44.         {
  45.             str[pos]='\0';
  46.             if (c==EOF)
  47.             {
  48.                 *check=1;
  49.             }
  50.             return str;
  51.         }
  52.         else
  53.         {
  54.             str[pos]=c;
  55.             pos++;
  56.         }
  57.    
  58.         if (pos==size)
  59.         {
  60.             size=size+n;
  61.             temp=str;
  62.             str=realloc(str,size*sizeof(char));
  63.             if (!str)
  64.             {
  65.                 free(temp);
  66.                 printf("memory allocation error\n");
  67.                 exit(1);
  68.             }
  69.         }
  70.     }
  71.    
  72. }
  73.  
  74. char *mystrtok (char *line, int *check, int *num) //вернет 1 в случае нахождения конца строки
  75. {
  76.     int size, pos=0, hpos=0, pos1, hpos1;
  77.     char *str, *temp;
  78.     size=m;
  79.     str=malloc(sizeof(char)*size);
  80.     if (!str)
  81.     {
  82.         printf("memory allocation error\n");
  83.         *check=2;
  84.         free(str);
  85.         return NULL;
  86.     }
  87.    
  88.     while (1)
  89.     {
  90.         // Обработка кавычек
  91.         if (line[pos]=='"')
  92.         {
  93.             pos1=pos+1;
  94.             hpos1=hpos;
  95.             while (1)
  96.             {
  97.                 if (line[pos1]=='"')
  98.                 {
  99.                     hpos=hpos1;
  100.                     pos=pos1+1;
  101.                     break;
  102.                 }
  103.                 if ((line[pos1]==EOF)||(line[pos1]=='\0'))
  104.                 {
  105.                     break; // не найдено парной кавычки -> кавычка должна считаться как обычный символ
  106.                 }
  107.                 str[hpos1]=line[pos1];
  108.                 hpos1++;
  109.                 pos1++;
  110.                 if (hpos1==size)
  111.                 {
  112.                     temp=str;
  113.                     size=size+m;
  114.                     str=realloc(str,size*sizeof(char));
  115.                     if (!str)
  116.                     {
  117.                         free(temp);
  118.                         printf("memory allocation error\n");
  119.                         *check=2;
  120.                         return NULL;
  121.                     }
  122.                 }
  123.             }
  124.         }
  125.         // Обработка иных случаев
  126.         if (line[pos]==' ')
  127.         {
  128.             if (hpos==0)
  129.             {
  130.                 pos++;
  131.             }
  132.             else
  133.             {
  134.                 str[hpos]='\0';
  135.                 *check=0;
  136.                 *num=pos; // чтобы в следующий раз отправить в эту функцию другую строку
  137.                 return str;
  138.                
  139.             }
  140.         }
  141.         else
  142.         {
  143.             if (line[pos]=='\0')
  144.             {
  145.                 if (hpos==0)
  146.                 {
  147.                     *check=1;
  148.                     free(str);
  149.                     return NULL;
  150.                 }
  151.                 else
  152.                 {
  153.                     str[hpos]='\0';
  154.                     *check=1;
  155.                     return str;
  156.                 }
  157.             }
  158.             else // обнаружен элемент, который можно записать в строку
  159.             {
  160.                 // Обрабатываем спецсимволы
  161.                 if ((line[pos]=='|')||(line[pos]=='&')||(line[pos]=='>')||(line[pos]=='<')||(line[pos]==';')||(line[pos]==')')||(line[pos]=='('))
  162.                 {
  163.                     if (hpos>0) //до этого уже сформирована строка
  164.                     {
  165.                         str[hpos]='\0';
  166.                         *check=0;
  167.                         *num=pos;
  168.                         return str;
  169.                     }
  170.                     else // строка еще не сформирована (hpos==0)
  171.                     {
  172.                         // |
  173.                         if (line[pos]=='|')
  174.                         {
  175.                             if (line[pos+1]=='|')
  176.                             {
  177.                                 str[0]='|';
  178.                                 str[1]='|';
  179.                                 str[2]='\0';
  180.                                 *check=0;
  181.                                 *num=pos+2;
  182.                                 return str;
  183.                             }
  184.                             else
  185.                             {
  186.                                 str[0]='|';
  187.                                 str[1]='\0';
  188.                                 *check=0;
  189.                                 *num=pos+1;
  190.                                 return str;
  191.                             }
  192.                         }
  193.                         // &
  194.                         if (line[pos]=='&')
  195.                         {
  196.                             if (line[pos+1]=='&')
  197.                             {
  198.                                 str[0]='&';
  199.                                 str[1]='&';
  200.                                 str[2]='\0';
  201.                                 *check=0;
  202.                                 *num=pos+2;
  203.                                 return str;
  204.                             }
  205.                             else
  206.                             {
  207.                                 str[0]='&';
  208.                                 str[1]='\0';
  209.                                 *check=0;
  210.                                 *num=pos+1;
  211.                                 return str;
  212.                             }
  213.                         }
  214.                         // >
  215.                         if (line[pos]=='>')
  216.                         {
  217.                             if (line[pos+1]=='>')
  218.                             {
  219.                                 str[0]='>';
  220.                                 str[1]='>';
  221.                                 str[2]='\0';
  222.                                 *check=0;
  223.                                 *num=pos+2;
  224.                                 return str;
  225.                             }
  226.                             else
  227.                             {
  228.                                 str[0]='>';
  229.                                 str[1]='\0';
  230.                                 *check=0;
  231.                                 *num=pos+1;
  232.                                 return str;
  233.                             }
  234.                         }
  235.                         // <
  236.                         if (line[pos]=='<')
  237.                         {
  238.                             str[0]='<';
  239.                             str[1]='\0';
  240.                             *check=0;
  241.                             *num=pos+1;
  242.                             return str;
  243.                         }
  244.                         // ;
  245.                         if (line[pos]==';')
  246.                         {
  247.                             str[0]=';';
  248.                             str[1]='\0';
  249.                             *check=0;
  250.                             *num=pos+1;
  251.                             return str;
  252.                         }
  253.                         // )
  254.                         if (line[pos]==')')
  255.                         {
  256.                             str[0]=')';
  257.                             str[1]='\0';
  258.                             *check=0;
  259.                             *num=pos+1;
  260.                             return str;
  261.                         }
  262.                         // (
  263.                         if (line[pos]=='(')
  264.                         {
  265.                             str[0]='(';
  266.                             str[1]='\0';
  267.                             *check=0;
  268.                             *num=pos+1;
  269.                             return str;
  270.                         }
  271.                     }
  272.                 }
  273.                 //Если встречен обычный символ
  274.                 str[hpos]=line[pos];
  275.                 hpos++;
  276.                 pos++;
  277.                 if (hpos==size)
  278.                 {
  279.                     temp=str;
  280.                     size=size+m;
  281.                     str=realloc(str,size*sizeof(char));
  282.                     if (!str)
  283.                     {
  284.                         free(temp);
  285.                         printf("memory allocation error\n");
  286.                         *check=2;
  287.                         return NULL;
  288.                     }
  289.                 }
  290.             }
  291.         }
  292.        
  293.     }
  294. }
  295.  
  296. char **parcer (char *line) // последний элемент массива всегда будет иметь значение NULL
  297. {
  298.     int check, pos=0, size=0, strpos=0, hstrpos=0;
  299.     char **base, **temp;
  300.    
  301.     size=t;
  302.     base=malloc(sizeof(char *)*size);
  303.     if (!base)
  304.     {
  305.         printf("memory allocation error\n");
  306.         free(line);
  307.         exit(1);
  308.     }
  309.    
  310.     while(1)
  311.     {
  312.         base[pos]=mystrtok(line+strpos, &check, &hstrpos);
  313.         if (check==2)
  314.         {
  315.             base[pos]=NULL;
  316.             freedom(base);
  317.             exit(1);
  318.         }
  319.         if (check==1)
  320.         {
  321.             if (!base[pos]) // вернулась NULL - парсинг строки завершен
  322.             {
  323.                 return base; //может быть даже такое, что первый элемент этого массива - NULL
  324.             }
  325.             else // вернулась не пустая строка, но обнаружен конец основной строки
  326.             {
  327.                 pos++;
  328.                 if (pos==size)
  329.                 {
  330.                     size=size+1;
  331.                     temp=base;
  332.                     base=realloc(base,size*sizeof(char *));
  333.                     if (!base)
  334.                     {
  335.                         free(temp[pos-1]); // т.к. на новый pos места уже нет
  336.                         temp[pos-1]=NULL;
  337.                         freedom(base);
  338.                         exit(1);
  339.                     }
  340.                 }
  341.                 base[pos]=NULL;
  342.                 return base;
  343.             }
  344.         }
  345.         if (check==0)
  346.         {
  347.             strpos+=hstrpos;
  348.             pos++;
  349.             if (pos==size)
  350.             {
  351.                 size=size+t;
  352.                 temp=base;
  353.                 base=realloc(base,size*sizeof(char *));
  354.                 if (!base)
  355.                 {
  356.                     free(temp[pos-1]); // т.к. на новый pos места уже нет
  357.                     temp[pos-1]=NULL;
  358.                     freedom(base);
  359.                     exit(1);
  360.                 }
  361.             }
  362.         }
  363.     }
  364. }
  365.  
  366. int cd (char *str) // проверка на корректность количества аргументов команды cd производится раньше
  367. {
  368.     int k;
  369.     if (str==NULL) //значит пользователю надо перейти в домашний каталог
  370.     {
  371.         k=chdir(getenv("HOME"));
  372.         if (k==-1)
  373.         {
  374.             printf ("В указанный каталог перейти не удалось\n");
  375.         }
  376.         return k;
  377.     }
  378.     else
  379.     {
  380.         k=chdir(str);
  381.         if (k==-1)
  382.         {
  383.             printf ("В указанный каталог перейти не удалось\n");
  384.         }
  385.         return k;
  386.     }
  387. }
  388.  
  389. int function_call (char **base) // вернет -1 в случае неудачного fork, -2  в случае неудачного exec
  390. {
  391.     // base представляет из себя массив строк, заканчивающийся NULL - ссылкой
  392.     int a,status;
  393.     char str[3]="cd";
  394.     if (base[0]==NULL)
  395.     {
  396.         return 0;
  397.     }
  398.     if (strcmp(str,base[0])==0)
  399.     {
  400.         if ((base[1]!=NULL)&&(base[2]!=NULL)) //ошибки не случится, т.к. при false в первом условии проверки второго не осуществиться
  401.         {
  402.             printf("cd: Некорректное число аргументов\n");
  403.         }
  404.         else
  405.         {
  406.             cd(base[1]);
  407.         }
  408.         return 0;
  409.     }
  410.     a=fork();
  411.     if (a==-1)
  412.     {
  413.         printf("Не удалось породить процесс\n");
  414.         return (-1);
  415.     }
  416.     if (a>0)
  417.     {
  418.         wait(&status);
  419.     }
  420.     else
  421.     {
  422.         a=execvp(base[0],base);
  423.         if (a==-1)
  424.         {
  425.             printf("Не удалось запустить программу - %s\n",base[0]);
  426.             return -2;
  427.         }
  428.     }
  429.     return 0;
  430. }
  431.  
  432. void all_str_output (char **base)
  433. {
  434.     int pos=0;
  435.     while ((base[pos]))
  436.     {
  437.         printf("%s\n",base[pos]);
  438.         pos++;
  439.     }
  440. }
  441.  
  442.  
  443. // требуем, чтобы перенаправления были последними
  444. int redirection (char **base)
  445. {
  446.     int len=0,fdrd,fdwr,hfd1,hfd2,checkrd=0,checkwr=0,res=0;
  447.     char *str;
  448.     while (base[len]) // кол-во переданных слов
  449.     {
  450.         len++;
  451.     }
  452.     hfd1=dup(1);
  453.     hfd2=dup(0);
  454.     if (len>=2) // потому что ситуация подачи на ввод, например >> text - корректна
  455.     {
  456.         if (strcmp(base[len-2],">")==0)
  457.         {
  458.             fdwr=open(base[len-1], O_CREAT | O_TRUNC | O_WRONLY | O_EXCL, 0666);
  459.             if (fdwr==-1)
  460.             {
  461.                 fdwr=open(base[len-1], O_TRUNC | O_WRONLY); // возможно, файл уже существует
  462.                 if (fdwr==-1)
  463.                 {
  464.                     printf("Перенаправление вывода организовать не удалось\n");
  465.                     goto jmp;
  466.                 }
  467.             }
  468.             checkwr=1;
  469.             dup2(fdwr,1);
  470.         }
  471.         if (strcmp(base[len-2],">>")==0)
  472.         {
  473.             fdwr=open(base[len-1], O_CREAT | O_APPEND | O_WRONLY | O_EXCL, 0666);
  474.             if (fdwr==-1)
  475.             {
  476.                 fdwr=open(base[len-1], O_APPEND| O_WRONLY);
  477.                 if (fdwr==-1)
  478.                 {
  479.                     printf("Перенаправление вывода организовать не удалось\n");
  480.                     goto jmp;
  481.                 }
  482.             }
  483.             checkwr=1;
  484.             dup2(fdwr,1);
  485.         }
  486.         if (strcmp(base[len-2],"<")==0)
  487.         {
  488.             fdrd=open(base[len-1], O_RDONLY);
  489.             if (fdrd==-1)
  490.             {
  491.                 printf("Перенаправление ввода организовать не удалось\n");
  492.                 goto jmp;
  493.             }
  494.             checkrd=1;
  495.             dup2(fdrd,0);
  496.         }
  497.         if (len>=4)
  498.         {
  499.             if ((checkrd==1)||(checkwr==1))
  500.             {
  501.                 if ((checkrd==1)&&(strcmp(base[len-4],">")==0))
  502.                 {
  503.                     fdwr=open(base[len-3], O_CREAT | O_TRUNC | O_WRONLY | O_EXCL, 0666);
  504.                     if (fdwr==-1)
  505.                     {
  506.                         fdwr=open(base[len-3], O_TRUNC | O_WRONLY);
  507.                         if (fdwr==-1)
  508.                         {
  509.                             printf("Перенаправление вывода организовать не удалось\n");
  510.                             goto jmp;
  511.                         }
  512.                     }
  513.                     checkwr=1;
  514.                     dup2(fdwr,1);
  515.                 }
  516.                 if ((checkrd==1)&&(strcmp(base[len-4],">>")==0))
  517.                 {
  518.                     fdwr=open(base[len-3], O_CREAT | O_APPEND | O_WRONLY | O_EXCL, 0666);
  519.                     if (fdwr==-1)
  520.                     {
  521.                         fdwr=open(base[len-3], O_APPEND| O_WRONLY);
  522.                         if (fdwr==-1)
  523.                         {
  524.                             printf("Перенаправление вывода организовать не удалось\n");
  525.                             goto jmp;
  526.                         }
  527.                     }
  528.                     checkwr=1;
  529.                     dup2(fdwr,1);
  530.                 }
  531.                 if ((checkwr==1)&&(strcmp(base[len-4],"<")==0))
  532.                 {
  533.                     fdrd=open(base[len-3], O_RDONLY);
  534.                     if (fdrd==-1)
  535.                     {
  536.                         printf("Перенаправление ввода организовать не удалось\n");
  537.                         goto jmp;
  538.                     }
  539.                     checkrd=1;
  540.                     dup2(fdrd,0);
  541.                 }
  542.                 if ((checkwr==1)&&(checkrd==1))
  543.                 {
  544.                     str=base[len-4];
  545.                     base[len-4]=NULL;
  546.                     res=function_call(base);
  547.                     base[len-4]=str;
  548.                 }
  549.                 else
  550.                 {
  551.                     str=base[len-2];
  552.                     base[len-2]=NULL;
  553.                     res=function_call(base);
  554.                     base[len-2]=str;
  555.                 }
  556.             }
  557.             else
  558.             {
  559.                 res=function_call(base);
  560.             }
  561.         }
  562.         else // меньше 4 слов в команде
  563.         {
  564.             if ((checkrd==1)||(checkwr==1)) // только одно из перенаправлений имело место
  565.             {
  566.                 str=base[len-2];
  567.                 base[len-2]=NULL;
  568.                 res=function_call(base);
  569.                 base[len-2]=str;
  570.             }
  571.             else // перенаправлений не было
  572.             {
  573.                 res=function_call(base);
  574.             }
  575.         }
  576.     }
  577.     else // меньше 2 слов в команде
  578.     {
  579.         res=function_call(base);
  580.     }
  581.     jmp:
  582.     if (checkwr==1)
  583.     {
  584.         dup2(hfd1,1);;
  585.         close(fdwr);
  586.     }
  587.     if (checkrd==1)
  588.     {
  589.         dup2(hfd2,0);
  590.         close(fdrd);
  591.     }
  592.     close(hfd1);
  593.     close(hfd2);
  594.     return res;
  595. }
  596.  
  597. /*
  598. // пока что отказываемся от использования этой функции
  599. int parsing_sequence_of_commands (char **base) // в этой функции потом надо будет реализовывать фоновый режим
  600. {
  601.     int i=0,lastarg=-1;
  602.     char str[2], *hstr;
  603.     str[0]=';';
  604.     str[1]='\0';
  605.     while (base[i]!=NULL)
  606.     {
  607.         if (strcmp(base[i],str)==0)
  608.         {
  609.             hstr=base[i];
  610.             base[i]=NULL;
  611.             if (function_call(base+lastarg+1)==-2)
  612.             {
  613.                 base[i]=hstr;
  614.                 return -1; // возврат при неккоректном exec-е
  615.             } // здесь нужен будет вызов функции, которая продолжит дальнейший разбор
  616.             base[i]=hstr;
  617.             lastarg=i;
  618.         }
  619.         i++;
  620.     }
  621.     if ((lastarg+1)!=i)
  622.     {
  623.         if (function_call(base+lastarg+1)==-2)
  624.         {
  625.             return -1;
  626.         }
  627.     }
  628.     // иначе - пустая команда
  629.     return 0;
  630. } */
  631.  
  632. int main (int argc, char **argv)
  633. {
  634.     int a, check=0;
  635.     char *s, **base;
  636.     FILE *f;
  637.     if (argc==1)
  638.     {
  639.         f=stdin;
  640.     }
  641.     else
  642.     {
  643.         if (argc==2)
  644.         {
  645.             f=fopen(argv[1], "r");
  646.             check=1;
  647.             if (f==NULL)
  648.             {
  649.                 printf("Нет доступа к файлу\n");
  650.                 return 0;
  651.             }
  652.         }
  653.         else
  654.         {
  655.             printf("Некорректное число аргументов командной строки\n");
  656.             return 0;
  657.         }
  658.     }
  659.     do {
  660.     s=read_line(f,&a);
  661.     //printf("%d\n",a);
  662.     //printf("\n");
  663.     //printf("%s\n",s);
  664.     base=parcer(s);
  665.     //printf("В массив строк занесены следующие строки\n");
  666.     //all_str_output(base);
  667.     if (redirection(base)==-2)
  668.     { // возврат в сыновний процесс при некорректном exec-е
  669.         freedom(base);
  670.         free(s);
  671.         return 0;
  672.     }
  673.     freedom(base);
  674.     free(s);
  675.     } while (a==0);
  676.     if (check==1)
  677.     {
  678.         fclose(f);
  679.     }
  680.     return 0;
  681. }
Add Comment
Please, Sign In to add comment