Esempio n. 1
0
/// This function handles both the 'continue' and the 'break' builtins that are used for loop
/// control.
static int builtin_break_continue(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    int is_break = (std::wcscmp(argv[0], L"break") == 0);
    int argc = builtin_count_args(argv);

    if (argc != 1) {
        streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], argv[1]);

        builtin_print_help(parser, streams, argv[0], streams.err);
        return STATUS_INVALID_ARGS;
    }

    // Find the index of the enclosing for or while loop. Recall that incrementing loop_idx goes
    // 'up' to outer blocks.
    size_t loop_idx;
    for (loop_idx = 0; loop_idx < parser.block_count(); loop_idx++) {
        const block_t *b = parser.block_at_index(loop_idx);
        if (b->type() == WHILE || b->type() == FOR) break;
    }

    if (loop_idx >= parser.block_count()) {
        streams.err.append_format(_(L"%ls: Not inside of loop\n"), argv[0]);
        builtin_print_help(parser, streams, argv[0], streams.err);
        return STATUS_CMD_ERROR;
    }

    // Skip blocks interior to the loop (but not the loop itself)
    size_t block_idx = loop_idx;
    while (block_idx--) {
        parser.block_at_index(block_idx)->skip = true;
    }

    // Mark the loop's status
    block_t *loop_block = parser.block_at_index(loop_idx);
    loop_block->loop_status = is_break ? LOOP_BREAK : LOOP_CONTINUE;
    return STATUS_CMD_OK;
}
Esempio n. 2
0
/// The block builtin, used for temporarily blocking events.
int builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    const wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    block_cmd_opts_t opts;

    int optind;
    int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.out);
        return STATUS_CMD_OK;
    }

    if (opts.erase) {
        if (opts.scope != UNSET) {
            streams.err.append_format(_(L"%ls: Can not specify scope when removing block\n"), cmd);
            return STATUS_INVALID_ARGS;
        }

        if (parser.global_event_blocks.empty()) {
            streams.err.append_format(_(L"%ls: No blocks defined\n"), cmd);
            return STATUS_CMD_ERROR;
        }
        parser.global_event_blocks.pop_front();
        return STATUS_CMD_OK;
    }

    size_t block_idx = 0;
    block_t *block = parser.block_at_index(block_idx);

    event_blockage_t eb = {};
    eb.typemask = (1 << EVENT_ANY);

    switch (opts.scope) {
        case LOCAL: {
            // If this is the outermost block, then we're global
            if (block_idx + 1 >= parser.block_count()) {
                block = NULL;
            }
            break;
        }
        case GLOBAL: {
            block = NULL;
            break;
        }
        case UNSET: {
            while (block != NULL && block->type() != FUNCTION_CALL &&
                   block->type() != FUNCTION_CALL_NO_SHADOW) {
                // Set it in function scope
                block = parser.block_at_index(++block_idx);
            }
            break;
        }
        default: {
            DIE("unexpected scope");
            break;
        }
    }
    if (block) {
        block->event_blocks.push_front(eb);
    } else {
        parser.global_event_blocks.push_front(eb);
    }

    return STATUS_CMD_OK;
}