/// 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; }
/// 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; }