0

非常に基本的なコマンド ライン インタープリターを作成しようとしているときに、理解できないセクションに出くわしました。必要な区切り文字のトークンをチェックしている間、&& と || を正しく有効にできないようです。機能。以下にリストされているのは、引数を挿入してからプロセスを作成するループです。

現時点では && に焦点を当てており、その実装を使用して || を支援する予定です。関数。皆さん、見て、私を正しい方向に向けるのを手伝ってもらえますか?

補足: これは私が C でプログラムを書くのも初めてなので、そのためにコードにエラーがあるかもしれません。

これは宿題の問題です。

ありがとう

私がこれまでに持っている完全なプログラムコードで更新されました。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#define ARG_SIZE 1<<16
#define MAXLINE 100

char *args[ARG_SIZE];
int place = 0;
int return_status;

void insert( char *token ){
    args[ place ] = token;
    place++;
}

void create() {
    size_t nargs = place;
    pid_t pid;

    if ( nargs == 0 ) return;
    if ( !strcmp( args[0], "exit" ) ) exit(0);
    pid = fork();
    if ( pid ) {
        pid = wait( return_status );
    } else {
        if ( access( args[ 0 ], X_OK ) ){
            if( execvp( args[ 0 ], args ) ) {
                puts( strerror( errno ) );
                exit( 127 );
            }
        }else{
            puts( strerror( errno ) );
            exit( 127 );
        }
    }

    int i = 0;
    for ( i ; i < place + 1; i++)
        args[ i ] = NULL;
    place = 0;
}

int main( int argc, char *argv[] ){

    char line[MAXLINE+1];                       /* an input line */
    int c;                                      /* a single input char or EOF */
    int n;                                      /* line length */
    char *token;                                /* pointer to an input token */

    for(;;) {                                   /* repeat until end of file */ 
        write( 1, "#>", 2 );

        if (fgets(line,MAXLINE,stdin) == NULL)  /* end of file? */
            exit(0);

        n = strlen(line);                       /* get length of line */

        if (n == 0)                             /* if line is empty */
            continue;

        if (line[n-1] != '\n') {                /* does input end with '\n' ? */
            fprintf(stderr,"Line too long.\n"); /* no, so line is too long. */

            /*--------------------------------------------*/
            /* Read and ignore input through end of line. */
            /*--------------------------------------------*/
            while ((c = fgetc(stdin)) != '\n') {
                if (c == EOF) {
                    fprintf(stderr,"Unexpected end of file\n");
                    exit(1);
                }
            }
            continue;
        }

        write( 1, line, strlen( line ) );
        line[n-1] = '\0';                      /* remove the end of line */
        /*-------------------------------------------------------------*/
        /* Identify and process each token (i.e. sequence of non-blank */
        /* characters delimited by whitespace). For "ordinary" tokens  */
        /* (i.e. "words") we just display them. For the ||, &&, and ;  */
        /* items we display them with a textual explanation.           */
        /*-------------------------------------------------------------*/
        token = strtok(line," \t");
        while (token != NULL ) {
            insert( token );
            if (!strcmp(token,"&&")){
                place--;
                args[ place ] = NULL;
                create();
                if( return_status == -1)
                    write( 1, "Wait failed.\n", 12 );
                if( return_status & 0xff ){
                    int i = 0;
                    for( i; i < place; i++)
                        args[ i ] = NULL;
                    place = 0;
                    while( strcmp( token, "||" ) || strcmp( token, ";" ) ) ;
                }
            }
            else if (!strcmp(token,"||")){
                place--;
                args[ place ] = NULL;
                completed = 0;
                create();                
            }
            else if (!strcmp(token,";")){
                place--;
                args[ place ] = NULL;
                create();
            }
            else{
            }
            token = strtok(NULL," \t");
        }
        create();
    }
    return 0;
}
4

2 に答える 2

1

wait() は、整数ではなく整数ポインターを取ります。そのためのコンパイラ警告が必要です。そうでない場合は、警告フラグを使用することをお勧めします。

#include <sys.wait.h>
wait(&return_code);

access() は成功すると 0 を返すため、このチェックは正しくありません。現在のディレクトリにないコマンドをチェックするためにアクセスを使用できるようには見えません。たとえば、「ls」は「/bin/ls」に展開する必要があります。

if ( access( args[ 0 ], X_OK ) ){
            if( execvp( args[ 0 ], args ) ) {
                puts( strerror( errno ) );
                exit( 127 );
            }

return_status のこのチェックは最初のバイトを見ていますが、forked() または execvp() されたプログラムは 2 番目のバイトでそのステータスを返します。返されたもののチェック:

if( return_status & 0xff ){

次のいずれかである必要があります。

if ( WEXITSTATUS(return_status) != 0 ){

また

if ( (return_status & 0xff00) >> 8 ){

if 本体:

      for( int i = 0; i < place; i++)
                        args[ i ] = NULL;
       place = 0;
       while( strcmp( token, "||" ) || strcmp( token, ";" ) ) ;

次のように置き換えることができます:

 break;

for ループを実行し、create() 内で場所を 0 に設定しているため、while ループは私にとって無限でした。囲んでいる while を抜け出すだけで、コマンド シーケンスが終了し、別のタイプのコマンド ラインの読み取りに戻ります。

  //if ( return_status == -1)

wait() ステータス マクロを使用できます。

  if ( ! WIFEXITED(return_status) )
于 2012-09-24T17:16:17.637 に答える
0

このコードは、他の回答で言及したことを示しており、「false && ls」に対して機能し、&& が失敗した後にさらにコマンドに対処するために更新されます。

    #include <unistd.h>
    #include <string.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #define ARG_SIZE 1 << 16
    #define MAXLINE 100

    char *args[ARG_SIZE];
    int place = 0;
    int return_status;

    char message[200];

    void insert( char *token ){
        args[ place ] = token;
        place++;
    }

    void reset_args(void)
    {
        for (int i = 0 ; i < place + 1; i++)
            args[ i ] = NULL;
        place = 0;
    }

    #define EXECVP_FAILED 127

    char last_command[200];

    void create() {
        size_t nargs = place;
        pid_t pid;

        if ( nargs == 0 ) return;
        if ( args[0] )
            strcpy(last_command,args[0]);
        else
           last_command[0] = '\0';
        if ( !strcmp( args[0], "exit" ) ) exit(0);
        pid = fork();
        if ( pid ) {
            pid = wait( &return_status );
        } else {
            if( execvp( args[ 0 ], args ) ) 
            {
               puts( strerror( errno ) );
               exit( EXECVP_FAILED );
            }
        }
        reset_args();
    }

    int main( void ){

       char line[MAXLINE+1];                       /* an input line */
       int c;                                      /* a single input char or EOF */
       int n;                                      /* line length */
       char *token;                                /* pointer to an input token */
       enum states { NORMAL, AND_CMD_FAILED };
       enum states state  = NORMAL;
       for(;;) {                                   /* repeat until end of file */ 
          state = NORMAL;
          write( 1, "#>", 2 );

          if (fgets(line,MAXLINE,stdin) == NULL)  /* end of file? */
             exit(0);

          n = strlen(line);                       /* get length of line */

          if (n == 0)                             /* if line is empty */
             continue;

          if (line[n-1] != '\n') {                /* does input end with '\n' ? */
             fprintf(stderr,"Line too long.\n"); /* no, so line is too long. */

             /*--------------------------------------------*/
             /* Read and ignore input through end of line. */
             /*--------------------------------------------*/
             while ((c = fgetc(stdin)) != '\n') {
                if (c == EOF) {
                   fprintf(stderr,"Unexpected end of file\n");
                   exit(1);
                }
             }
             continue;
          }

          write( 1, line, strlen( line ) );
          line[n-1] = '\0';                      /* remove the end of line */
          /*-------------------------------------------------------------*/
          /* Identify and process each token (i.e. sequence of non-blank */
          /* characters delimited by whitespace). For "ordinary" tokens  */
          /* (i.e. "words") we just display them. For the ||, &&, and ;  */
          /* items we display them with a textual explanation.           */
          /*-------------------------------------------------------------*/
          token = strtok(line," \t");
          while (token != NULL ) {
             insert( token );
             if (!strcmp(token,"&&")){
                    place--;
                args[ place ] = NULL;                      
                            if ( state == NORMAL )
                               create();
                            else
                               reset_args();

                if ( ! (WIFEXITED(return_status) ) || ( WEXITSTATUS(return_status)  ) )
                {
                   // command did not execute successfully
                   if ( ! WIFEXITED(return_status) )
                   {
                      sprintf(message,"Wait failed for %s\n",last_command);
                      write( 1, message, strlen(message) );
                   }
                   else if ( WEXITSTATUS(return_status) == EXECVP_FAILED )
                   {
                      sprintf(message,"execvp failed for %s\n",last_command);
                      write( 1, message, strlen(message) );
                   }
                   else  if ( WEXITSTATUS(return_status) != 0 ) {
                      sprintf(message,"%s command failed - exit status %d\n",
                              last_command,WEXITSTATUS(return_status));
                      write( 1, message, strlen(message) );
                   }
                   // bypass next command(s) up to || or ; delimiters
                   state = AND_CMD_FAILED;
                }
             }
             else if (!strcmp(token,"||")){
                place--;
                args[ place ] = NULL;
                //completed = 0;
                if ( state == NORMAL )
                   create();
                else
                   reset_args();
                state = NORMAL;         
             }
             else if (!strcmp(token,";")){
                place--;
                args[ place ] = NULL;
                if ( state == NORMAL )
                   create();
                else
                   reset_args();
                state = NORMAL;
             }
             else{
             }
             token = strtok(NULL," \t");
          }
          if ( state == NORMAL )
             create();
          else
             reset_args();
       }
       return 0;
  }
于 2012-09-25T09:04:08.997 に答える