// Les comandes de línia està compostes per un opció que es precedida d'un '-' i llavors pot contenir a continuació un argument,
// indicant el valor de la opció
bool ApplicationCommandLineOptions::parse()
{
    QStringList argumentList = m_argumentList;
    QString parameter;
    bool lastParameterWasAnOption = false, nextParameterHasToBeAnArgumentOption = false;
    CommandLineOption lastOption;

    m_parserErrorMessage = "";
    // Treiem el primer string que és el nom de l'aplicació
    argumentList.removeFirst();

    // Mentre hi hagi arguments per processar o no s'hagi produït un error parsegem els arguments
    while (!argumentList.isEmpty() && m_parserErrorMessage.isEmpty())
    {
        parameter = argumentList.takeFirst();

        if (isAnOption(parameter))
        {
            if (!nextParameterHasToBeAnArgumentOption)
            {
                // Treiem el "-" del paràmetre
                parameter = parameter.right(parameter.length() -1);
                // Comprovem si és una opció vàlida
                if (m_commandLineOptions.contains(parameter))
                {
                    // Si és una opció que ens han especificat com a vàlida l'inserim com a parsejada, de moment com argument de l'opció hi posem ""
                    m_parsedOptions.insert(parameter, "");

                    lastParameterWasAnOption = true;
                    lastOption = m_commandLineOptions.value(parameter);
                    nextParameterHasToBeAnArgumentOption = lastOption.requiresArgument();
                }
                else
                {
                    m_parserErrorMessage += QObject::tr("Unknown option %1").arg(CommandLineOption::OptionSelectorPrefix + parameter) + "\n";
                }
            }
            else
            {
                // Si l'últim paràmetre parsejat era una opció que se li havia de passar obligatòriament un argument ex "-accessionnumber 12345"
                // i no se li ha especificat cap argument ex: "-accessionnumber -studyUID" guardem l'error i parem.
                m_parserErrorMessage += QObject::tr("%1 option requires an argument").arg(lastOption.getName()) + "\n";
            }
        }
        else
        {
            // És un argument
            if (lastParameterWasAnOption)
            {
                if (nextParameterHasToBeAnArgumentOption)
                {
                    // Si tenim un argument i l'últim paràmetre era un opció, vol dir aquest paràmetre és un argument
                    m_parsedOptions[lastOption.getName()] = parameter;
                }
                else
                {
                    m_parserErrorMessage += QObject::tr("%1 option requires an argument").arg(lastOption.getName()) + "\n";
                }
            }
            else
            {
                m_parserErrorMessage += QObject::tr("Unexpected value %1").arg(parameter) + "\n";
            }

            lastParameterWasAnOption = false;
            nextParameterHasToBeAnArgumentOption = false;
        }
    }

    if (nextParameterHasToBeAnArgumentOption)
    {
        m_parserErrorMessage += QObject::tr("%1 option requires an argument").arg(lastOption.getName()) + "\n";
    }

    return m_parserErrorMessage.isEmpty();
}
Esempio n. 2
0
//main function
int main(int argc, char **argv){

    static struct option long_opts[] = 
    {
        /*file flags options*/
        {"append",      no_argument, 0,    'a'},
        {"cloexec",     no_argument, 0,    'l'},
        {"creat",       no_argument, 0,    'C'},
        {"directory",   no_argument, 0,    'd'},
        {"dsync",       no_argument, 0,    'D'},
        {"excl",        no_argument, 0,    'e'},
        {"nofollow",    no_argument, 0,    'n'},
        {"nonblock",    no_argument, 0,    'N'},
        {"rsync",       no_argument, 0,    's'},
        {"sync",        no_argument, 0,    'S'},
        {"trunc",       no_argument, 0,    't'},
        
        /*file opening options*/
        {"rdonly",      required_argument,  0,  'r'},
        {"wronly",      required_argument,  0,  'w'},
        {"rdwr",        required_argument,  0,  'R'},
        {"pipe",        no_argument,        0,  'p'},

        /*subcommand options*/
        {"command",     required_argument,  0,          'c'},
        {"wait",        no_argument,        0,          'W'},
        
        /*miscellaneous options*/
        {"close",       required_argument,  0,  'L'},
        {"verbose",     no_argument,        &verbose_flag, 1},
        {"profile",     no_argument,        &profile_flag, 1},
        {"abort",       no_argument,        0,  'A'},
        {"catch",       required_argument,  0,  'T'},
        {"ignore",      required_argument,  0,  'i'},
        {"default",     required_argument,  0,  'f'},
        {"pause",       no_argument,        0,  'P'},
        {0,             0,                  0,  0}
    };
    
    int long_opts_ind;
    int curr_opt;
    int curr_optind;
    int next_optind;
    int oflags = 0;
    char *option;
    
    int pid_child_ind = 0;
    int fd_ind = 0;
    int cmd_ind = 0;
    int wait_info_ind = 0;

    verbose_flag = 0;
    wait_flag = 0;
    profile_flag = 0;
    ignore_sig = 0;
    default_sig = 0;

    return_val = 0;

    pid_t pid;
    pid_t c_pid;
    
    //signal handling
    struct sigaction sa;
    
    curr_optind = optind;
    curr_opt = getopt_long(argc, argv, "", long_opts, &long_opts_ind);
    next_optind = optind;




    if(curr_opt == -1){
        fprintf(stderr, "error: no options found\n");
    }
    else {
        if(!isAnOption(argv[curr_optind])){
            fprintf(stderr, "error: argument found before options and was ignored\n");
        }
        do {
            //debug message
            //printf("curr_optind = %d | curr_opt = %c | next_optind = %d\n", curr_optind, curr_opt, next_optind);
            //printf("argv[%d] = %s\n", next_optind, argv[next_optind]);
            //printf("optopt = %d\n", optopt);
            if(profile_flag){
                if(getrusage(RUSAGE_SELF, &usage) == -1){
                    fprintf(stderr, "error: cannot get the usage informations\n");
                }
                else{
                    //set the values of ru_utime_prev and ru_stime_prev
                    prev_usertime = (double)usage.ru_utime.tv_sec + (double)usage.ru_utime.tv_usec/1000000;
                    prev_systemtime = (double)usage.ru_stime.tv_sec + (double)usage.ru_stime.tv_usec/1000000;
                } 
            }

    
            switch(curr_opt){
                // append
                case 'a':{
                if((next_optind != argc) && !isAnOption(argv[next_optind])){
                    fprintf(stderr, "error: append can not accept any arguments, all arguments to append were ignored\n");
                    }
                    oflags |= O_APPEND;
                    if(verbose_flag){
                        printf("--append\n");
                    }
                    break;
                }
                // cloexec
                case 'l':{
                    if((next_optind != argc) && !isAnOption(argv[next_optind])){
                        fprintf(stderr, "error: cloexec can not accept any arguments, all arguments to cloexec were ignored\n");
                    }
                    oflags |= O_CLOEXEC;
                    if(verbose_flag){
                        printf("--cloexec\n");
                    }
                    break;
                }
                // creat
                case 'C':{
                    if((next_optind != argc) && !isAnOption(argv[next_optind])){
                        fprintf(stderr, "error: creat can not accept any arguments, all arguments to creat were ignored\n");
                        exit(EXIT_FAILURE);
                    }
                    oflags |= O_CREAT;
                    if(verbose_flag){
                        printf("--creat\n");
                    }
                    break;
                }
                // directory
                case 'd':{
                    if((next_optind != argc) && !isAnOption(argv[next_optind])){
                        fprintf(stderr, "error: directory can not accept any arguments, all arguments to directory were ignored\n");
                    }
                    oflags |= O_DIRECTORY;
                    if(verbose_flag){
                        printf("--directory\n");
                    }
                    break;
                }
                // dsync
                case 'D':{
                    if((next_optind != argc) && !isAnOption(argv[next_optind])){
                        fprintf(stderr, "error: dsync can not accept any arguments, all arguments to dsync were ignored\n");
                    }
                    oflags |= O_DSYNC;
                    if(verbose_flag){
                        printf("--dsync\n");
                    }
                    break;
                }
                // excl
                case 'e':{
                    if((next_optind != argc) && !isAnOption(argv[next_optind])){
                        fprintf(stderr, "error: excl can not accept any arguments, all arguments to excl were ignored\n");
                    }
                    oflags |= O_EXCL;
                    if(verbose_flag){
                        printf("--excl\n");
                    }
                    break;
                }
                // nofollow
                case 'n':{
                    if((next_optind != argc) && !isAnOption(argv[next_optind])){
                        fprintf(stderr, "error: nofollow can not accept any arguments, all arguments to nofollow were ignored\n");
                    }
                    oflags |= O_NOFOLLOW;
                    if(verbose_flag){
                        printf("--nofllow\n");
                    }
                    break;
                }
                // nonblock
                case 'N':{
                    if((next_optind != argc) && !isAnOption(argv[next_optind])){
                        fprintf(stderr, "error: nonblock can not accept any arguments, all arguments to nonblock were ignored\n");
                    }
                    oflags |= O_NONBLOCK;
                    if(verbose_flag){
                        printf("--nonblock\n");
                    }
                    break;
                }
                // rsync
                case 's':{
                    if((next_optind != argc) && !isAnOption(argv[next_optind])){
                        fprintf(stderr, "error: rsync can not accept any arguments, all arguments to rsync were ignored\n");
                    }
                    oflags |= O_RSYNC;
                    if(verbose_flag){
                        printf("--rsync\n");
                    }
                    break;
                }
                // sync
                case 'S':{
                    if((next_optind != argc) && !isAnOption(argv[next_optind])){
                        fprintf(stderr, "error: sync can not accept any arguments, all arguments to sync were ignored\n");
                    }
                    oflags |= O_SYNC;
                    if(verbose_flag){
                        printf("--sync\n");
                    }
                    break;
                }
                // trunc
                case 't':{
                    if((next_optind != argc) && !isAnOption(argv[next_optind])){
                        fprintf(stderr, "error: trunc can not accept any arguments, all arguments to trunc were ignored\n");
                    }
                    oflags |= O_TRUNC;
                    if(verbose_flag){
                        printf("--trunc\n");
                    }
                    break;
                }
                // rdonly, rdwr, wronly
                case 'r':
                case 'R':
                case 'w':
                    if (curr_opt == 'r'){
                        oflags |= O_RDONLY;
                        option = "rdonly";
                    }
                    else if (curr_opt == 'R'){
                        oflags |= O_RDWR;
                        option = "rdwr";
                    }
                    else if (curr_opt == 'w'){
                        oflags |= O_WRONLY;
                        option = "wronly";
                    }
                    if((next_optind != argc) && !isAnOption(argv[next_optind])){
                        fprintf(stderr, "error: %s can only accept one argument, further arguments to %s were ignored\n", option, option);
                    }
                    if(verbose_flag){
                        printf("--%s %s\n", option, optarg);
                    }
                    int temp_fd = open(optarg, oflags, mode);
                    if (errno == EEXIST){
                        fprintf(stderr, "error: file \"%s\" already exists\n", optarg);
                        exit(errno);
                    }
                    if (errno == ENOTDIR){
                        fprintf(stderr, "error: file \"%s\" is a non-direcotry file\n", optarg);
                        exit(errno);
                    }
                    if (temp_fd == -1){
                        fprintf(stderr, "error: could not open file \"%s\"\n", optarg);
                        exit(errno);
                    }
                    fd[fd_ind++] = temp_fd;
                    fd_pipe[fd_ind] = 0;
                    
                    
                    
                    /*clean oflags*/
                    oflags = 0;
                    
                    if (profile_flag){
                        print_usage(RUSAGE_SELF);
                    }
                    break;
                    
                // pipe
                case 'p':{
                    if((next_optind != argc) && !isAnOption(argv[next_optind])){
                        fprintf(stderr, "error: pipe can not accept any arguments, all arguments to pipe were ignored\n");
                    }
                    if(verbose_flag){
                        printf("--pipe\n");
                    }
                    if(pipe(pipe_fd) == -1){
                        fprintf(stderr, "error: failure to create a pipe\n");
                    }
                
                    /*identify pipe file descriptors to the pipe array*/
                    fd[fd_ind++] = pipe_fd[0];
                    fd_pipe[fd_ind] = 1;
                    fd[fd_ind++] = pipe_fd[1];
                    fd_pipe[fd_ind] = 1;
                    
                    if (profile_flag){
                        print_usage(RUSAGE_SELF);
                    }
                    
                    break;
                }
        
                //command
                case 'c':{
                    while((optind != argc) && !isAnOption(argv[optind])){
                                optind++;
                    }
                    if(optind < (curr_optind + 5))
                        fprintf(stderr, "error: missing arguments to --command, your command will not be run\n");
                    else{
                        cmd_fd[0] = atoi(optarg);
                        cmd_fd[1] = atoi(argv[next_optind++]);
                        cmd_fd[2] = atoi(argv[next_optind++]);

                        cmd_ind = 0;
                        //for(int i = 0; i < 3; i++)
                        //  printf("cmd_fd[%d] = %d\n", i, cmd_fd[i]);
                        
                        flushCmd();
        
                        while((next_optind != argc) && !isAnOption(argv[next_optind])){
                            char *char_ptr = malloc(sizeof(argv[next_optind]));
                            char *wait_cmd_ptr = malloc(sizeof(argv[next_optind]));
                            //printf("%d ", (int)sizeof(argv[next_optind]));
                            cmd[cmd_ind] = char_ptr;
                            wait_infos[wait_info_ind].wait_cmd[cmd_ind] = wait_cmd_ptr;
                            strcpy(cmd[cmd_ind], argv[next_optind]);
                            strcpy(wait_infos[wait_info_ind].wait_cmd[cmd_ind], argv[next_optind]);
                            cmd_ind++;
                            next_optind++;
                        }
                        
                        if(verbose_flag){
                            printf("--command");
                            for(int i = 0; i < 3; i++){
                                printf(" %d", cmd_fd[i]);
                            }
                            for(int i = 0; i < cmd_size; i++){
                                if(cmd[i] != NULL){
                                    printf(" %s", cmd[i]);
                                }
                            }
                            printf("\n");
                        }
                                
                        c_pid = fork();
                        if(c_pid == 0){ 
                            
                            /*close unused side of the pipe*/
                            if (fd_pipe[cmd_fd[0]])
                                close(fd[cmd_fd[0]+1]);
                            if (fd_pipe[cmd_fd[1]])
                                close(fd[cmd_fd[1]-1]);
                            if (fd_pipe[cmd_fd[2]])
                                close(fd[cmd_fd[2]-1]);
                        
                            /*direct file descriptors*/
                            dup2(fd[cmd_fd[0]], STDIN_FILENO);
                            dup2(fd[cmd_fd[1]], STDOUT_FILENO);
                            dup2(fd[cmd_fd[2]], STDERR_FILENO);

                            /*execute command*/
                            if(execvp(cmd[0], cmd) == -1){
                                fprintf(stderr, "error: command failed\n");
                            }
                        }
                        else if(c_pid > 0){
                            
                            pid_child[pid_child_ind] = c_pid;
                            pid_child_ind++;
                            wait_infos[wait_info_ind].wait_pid = c_pid;

                            /*close unused side of the pipe*/
                            if (fd_pipe[cmd_fd[0]]){
                                close(fd[cmd_fd[0]]);
                                fd[cmd_fd[0]] = -1;
                            }
                            if (fd_pipe[cmd_fd[1]]){
                                close(fd[cmd_fd[1]]);
                                fd[cmd_fd[1]] = -1;
                            }
                            if (fd_pipe[cmd_fd[2]]){
                                close(fd[cmd_fd[2]]);
                                fd[cmd_fd[2]] = -1;
                            }
                        }
                        else { //couldn't create child process
                            fprintf(stderr, "error: could not create child process\n");
                        }

                        for(int i = 0; i < cmd_size; i++)
                            free(cmd[i]);
                    }
                    
                    wait_info_ind++;
                    
                    if (profile_flag){
                        print_usage(RUSAGE_SELF);
                    }
                    
                    break;
                }

                //wait
                case 'W':{
                    if (verbose_flag)
                        printf("--wait\n");
                    
                    int status;
                    int exit_status;

                    for (int i = 0; i < wait_info_ind; i++) {
                        exit_status = waitpid(-1, &status, 0);
                        printf("%d ", status);
                        
                        int j;
                        for (j = 0; j < wait_info_ind; j++)
                            if (exit_status == wait_infos[j].wait_pid)
                                break;
                        int k = 0;
                        for (; wait_infos[j].wait_cmd[k]!= NULL; k++)
                            printf("%s ", wait_infos[j].wait_cmd[k]);
                        
                        printf("\n");
                    }
                    if (profile_flag) {
                        printf("Parent Usage:\n");
                        print_usage(RUSAGE_SELF);
                        printf("Children Usage:\n");
                        print_usage(RUSAGE_CHILDREN);
                    }
                    
                    break;
                }

                // close
                case 'L':{
                    if (verbose_flag)
                        printf("--close %s\n", optarg);
                    if (!isNumber(optarg)){
                        fprintf(stderr, "error: close requires an integer argument\n");
                        exit(EXIT_FAILURE);
                    }
                    close_fd = atoi(optarg);
                    if (close_fd > fd_ind){
                        fprintf(stderr, "error: the entered file descriptor number is invalid\n");
                        exit(EXIT_FAILURE);
                    }
                    close(fd[close_fd]);
                    fd[close_fd] = -1;
                    
                    if (profile_flag){
                        print_usage(RUSAGE_SELF);
                    }
                    
                    break;
                }
                // abort
                case 'A':{
                    if (verbose_flag)
                        printf("--abort\n");
                    raise(SIGSEGV);
                    break;
                }
                // catch
                case 'T':{
                    if (verbose_flag) {
                        printf("--catch %s\n", optarg);
                    }
                    catch_sig = atoi(optarg);
                    if (!isNumber(optarg) || catch_sig < 0){
                        fprintf(stderr, "error: catch requires a valid integer argument\n");
                        continue;
                    }
                    sa.sa_handler = catch_handler;
                    sigemptyset(&sa.sa_mask);
                    sa.sa_flags = SA_SIGINFO;
                    
                    if (sigaction(catch_sig, &sa, NULL) < 0){
                        /*handle error*/
                        fprintf(stderr, "error: fail to handle signal catch %d.\n",catch_sig);
                        exit(EXIT_FAILURE);
                    }
                    
                    if (profile_flag){
                        print_usage(RUSAGE_SELF);
                    }
                    
                    break;
                }
                // ignore
                case 'i':{
                    ignore_sig = atoi(optarg);
                    if (verbose_flag) {
                        printf("--ignore %s\n", optarg);
                    }
                    if (!isNumber(optarg) || ignore_sig < 0){
                        fprintf(stderr, "error: ignore requires a valid integer argument\n");
                        continue;
                    }
                    
                    sa.sa_sigaction = &ignore_handler;
                    sa.sa_flags = SA_SIGINFO;
                    
                    if (sigaction(ignore_sig, &sa, NULL) < 0){
                        /*handle error*/
                        fprintf(stderr, "error: fail to ignore signal %d.\n",ignore_sig);
                        exit(EXIT_FAILURE);
                    }
                    
                    if (profile_flag){
                        print_usage(RUSAGE_SELF);
                    }
                    
                    break;
                }
                // default
                case 'f':{
                    default_sig = atoi(optarg);
                    if (verbose_flag) {
                        printf("--default %s\n", optarg);
                    }
                    if (!isNumber(optarg) || default_sig < 0){
                        fprintf(stderr, "error: default requires a valid integer argument\n");
                        continue;
                    }
                    if (signal(default_sig, SIG_DFL) < 0){
                        /* Handle error */
                        fprintf(stderr, "error: fail to handle signal %d with default\n", default_sig);
                        exit(EXIT_FAILURE);
                        break;
                    }
                    
                    if (profile_flag){
                        print_usage(RUSAGE_SELF);
                    }
                    
                    break;
                }
                // pause
                case 'P':{
                    if (verbose_flag) {
                        printf("--pause %s\n", optarg);
                    }
                    pause();
                    
                    if (profile_flag){
                        print_usage(RUSAGE_SELF);
                    }
                    
                    break;
                }
                case '?':{
                    fprintf(stderr, "error: option not recognized or no option argument found\n");
                    break;
                }
            }

            //move to next option
            while((optind != argc) && !isAnOption(argv[optind]))
                optind++;
            curr_optind = optind;
            curr_opt = getopt_long(argc, argv, "", long_opts, &long_opts_ind);
            next_optind = optind;
        } while(curr_opt != -1);
    }

    /*close all file descriptors that were opened*/
    for(int i = 0; i < fd_ind; i++){
        if (fd[i] != -1){
            if(close(fd[i]) != 0){
                fprintf(stderr, "error: could not close file at logical index %d\n", i);
                exit(EXIT_FAILURE);
            }
        }
    }
    
    int status;
    for (int i = 0; i < pid_child_ind; i++){
        waitpid(pid_child[i], &status, 0);
        int exit_status = WEXITSTATUS(status);
        
    /*calculate the largest exit status*/
    if(exit_status > return_val)
        return_val = exit_status;
    }
    
    /*free the memory allocated for --wait commnands and arguments*/
    for (int i = 0; i < wait_info_ind; i++){
        for (int j = 0; j < cmd_size; j++)
            free(wait_infos[i].wait_cmd[j]);
    }

    return return_val;
}