/****************************************************************************** * This file is part of TinTin++ * * * * Copyright 2004-2020 Igor van den Hoven * * * * TinTin++ is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with TinTin++. If not, see https://www.gnu.org/licenses. * ******************************************************************************/ /****************************************************************************** * T I N T I N + + * * * * coded by Igor van den Hoven 2008 * ******************************************************************************/ #include "tintin.h" struct line_type { char * name; LINE * fun; char * desc; }; struct line_type line_table[] = { { "BACKGROUND", line_background, "Execute line without stealing session focus." }, { "BENCHMARK", line_benchmark, "Execute line and provide timing information." }, { "CAPTURE", line_capture, "Capture output in the given variable." }, { "CONVERT", line_convert, "Execute line in convert meta data mode." }, { "DEBUG", line_debug, "Execute line in debug mode." }, { "GAG", line_gag, "Gag the next line." }, { "IGNORE", line_ignore, "Execute line with triggers ignored." }, { "JSON", line_json, "Execute line with json conversion." }, { "LOCAL", line_local, "Execute line with local scope." }, { "LOG", line_log, "Log the next line or given line." }, { "LOGMODE", line_logmode, "Execute line with given log mode." }, { "LOGVERBATIM", line_logverbatim, "Log the line as plain text verbatim." }, { "MSDP", line_msdp, "Execute line with msdp conversion." }, { "MULTISHOT", line_multishot, "Execute line creating multishot triggers." }, { "ONESHOT", line_oneshot, "Execute line creating oneshot triggers." }, { "QUIET", line_quiet, "Execute line with all system messages off." }, { "STRIP", line_strip, "Execute line with escape codes stripped." }, { "SUBSTITUTE", line_substitute, "Execute line with given substitution." }, { "VERBATIM", line_verbatim, "Execute line as plain text." }, { "VERBOSE", line_verbose, "Execute line with all system messages on." }, { "", NULL, "" } }; DO_COMMAND(do_line) { int cnt; arg = get_arg_in_braces(ses, arg, arg1, GET_ONE); if (*arg1 == 0) { info: tintin_header(ses, 80, " LINE OPTIONS "); for (cnt = 0 ; *line_table[cnt].fun != NULL ; cnt++) { if (*line_table[cnt].desc) { tintin_printf2(ses, " [%-13s] %s", line_table[cnt].name, line_table[cnt].desc); } } tintin_header(ses, 80, ""); return ses; } else { for (cnt = 0 ; *line_table[cnt].name ; cnt++) { if (is_abbrev(arg1, line_table[cnt].name)) { break; } } if (*line_table[cnt].name == 0) { goto info; } else { ses = line_table[cnt].fun(ses, arg, arg1, arg2, arg3); } } return ses; } DO_LINE(line_background) { arg = get_arg_in_braces(ses, arg, arg1, GET_ALL); if (*arg1 == 0) { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {BACKGROUND} {command}."); return ses; } gtd->level->background++; ses = script_driver(ses, LIST_COMMAND, arg1); gtd->level->background--; return ses; } DO_LINE(line_benchmark) { long long start, end; arg = get_arg_in_braces(ses, arg, arg1, GET_ALL); if (*arg1 == 0) { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {BENCHMARK} {command}."); return ses; } start = utime(); ses = script_driver(ses, LIST_COMMAND, arg1); end = utime(); tintin_printf2(ses, "#LINE BENCHMARK: %lld USEC.", end - start); return ses; } DO_LINE(line_capture) { arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN); arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN); if (*arg1 && *arg2) { if (ses->line_capturefile) { free(ses->line_capturefile); } ses->line_capturefile = strdup(arg1); ses->line_captureindex = 1; ses = script_driver(ses, LIST_COMMAND, arg2); if (ses->line_capturefile) { free(ses->line_capturefile); ses->line_capturefile = NULL; } } else { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE CAPTURE {VARIABLE} {command}."); } return ses; } DO_LINE(line_convert) { arg = get_arg_in_braces(ses, arg, arg1, GET_ALL); if (*arg1 == 0) { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {CONVERT} {command}."); return ses; } // May need a clearer flag here. gtd->level->convert++; ses = script_driver(ses, LIST_COMMAND, arg1); gtd->level->convert--; return ses; } DO_LINE(line_debug) { arg = get_arg_in_braces(ses, arg, arg1, GET_ALL); if (*arg1 == 0) { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {DEBUG} {command}."); return ses; } gtd->level->debug++; ses = script_driver(ses, LIST_COMMAND, arg1); gtd->level->debug--; return ses; } DO_LINE(line_gag) { arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN); switch (*arg1) { case '-': ses->gagline -= get_number(ses, arg1+1); break; case '+': ses->gagline += get_number(ses, arg1+1); break; case 0: ses->gagline = 1; break; default: ses->gagline = get_number(ses, arg1); break; } if (ses->gagline < 0) { ses->gagline = 0; } show_debug(ses, LIST_GAG, COLOR_DEBUG "#DEBUG LINE GAG " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} " COLOR_COMMAND "[" COLOR_STRING "%d" COLOR_COMMAND "]", arg1, ses->gagline); return ses; } DO_LINE(line_ignore) { arg = get_arg_in_braces(ses, arg, arg1, GET_ALL); if (*arg1 == 0) { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {IGNORE} {command}."); return ses; } gtd->level->ignore++; ses = script_driver(ses, LIST_COMMAND, arg1); gtd->level->ignore--; return ses; } DO_LINE(line_local) { arg = get_arg_in_braces(ses, arg, arg1, GET_ALL); if (*arg1 == 0) { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOCAL} {command}."); return ses; } gtd->level->local++; SET_BIT(gtd->flags, TINTIN_FLAG_LOCAL); ses = script_driver(ses, LIST_COMMAND, arg1); gtd->level->local--; return ses; } // Without an argument mark next line to be logged, otherwise log the given line to file. DO_LINE(line_log) { FILE *logfile; arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN); arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN); if (*arg1 && *arg2) { substitute(ses, arg2, arg2, SUB_ESC|SUB_COL|SUB_LNF); if (ses->log->file && !strcmp(ses->log->name, arg1)) { logit(ses, arg2, ses->log->file, LOG_FLAG_NONE); } else if (ses->log->line_time == gtd->time && !strcmp(ses->log->line_name, arg1)) { logit(ses, arg2, ses->log->line_file, LOG_FLAG_NONE); } else { if ((logfile = fopen(arg1, "a"))) { if (ses->log->line_file) { fclose(ses->log->line_file); } free(ses->log->line_name); ses->log->line_name = strdup(arg1); ses->log->line_file = logfile; ses->log->line_time = gtd->time; logheader(ses, ses->log->line_file, LOG_FLAG_APPEND | HAS_BIT(ses->log->mode, LOG_FLAG_HTML)); logit(ses, arg2, ses->log->line_file, LOG_FLAG_NONE); } else { show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOG {%s} - COULDN'T OPEN FILE.", arg1); } } } else if (*arg1) { if (ses->log->next_time == gtd->time && !strcmp(ses->log->next_name, arg1)) { SET_BIT(ses->log->mode, LOG_FLAG_NEXT); } else if ((logfile = fopen(arg1, "a"))) { if (ses->log->next_file) { fclose(ses->log->next_file); } free(ses->log->next_name); ses->log->next_name = strdup(arg1); ses->log->next_file = logfile; ses->log->next_time = gtd->time; SET_BIT(ses->log->mode, LOG_FLAG_NEXT); } else { show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOG {%s} - COULDN'T OPEN FILE.", arg1); } } else { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOG} {filename} [string]"); } return ses; } DO_LINE(line_logverbatim) { FILE *logfile; arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN); arg = get_arg_in_braces(ses, arg, arg2, GET_ALL); if (*arg1 && *arg2) { if (ses->log->file && !strcmp(ses->log->name, arg1)) { logit(ses, arg2, ses->log->file, LOG_FLAG_LINEFEED); } else if (ses->log->line_time == gtd->time && !strcmp(ses->log->line_name, arg1)) { logit(ses, arg2, ses->log->line_file, LOG_FLAG_LINEFEED|LOG_FLAG_PLAIN); } else { if ((logfile = fopen(arg1, "a"))) { if (ses->log->line_file) { fclose(ses->log->line_file); } free(ses->log->line_name); ses->log->line_name = strdup(arg1); ses->log->line_file = logfile; ses->log->line_time = gtd->time; logit(ses, arg2, ses->log->line_file, LOG_FLAG_LINEFEED|LOG_FLAG_PLAIN); } else { show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOGVERBATIM {%s} - COULDN'T OPEN FILE.", arg1); } } } else if (*arg1) { if (ses->log->next_time == gtd->time && !strcmp(ses->log->next_name, arg1)) { SET_BIT(ses->log->mode, LOG_FLAG_NEXT); } else if ((logfile = fopen(arg1, "a"))) { if (ses->log->next_file) { fclose(ses->log->next_file); } free(ses->log->next_name); ses->log->next_name = strdup(arg1); ses->log->next_file = logfile; ses->log->next_time = gtd->time; SET_BIT(ses->log->mode, LOG_FLAG_NEXT); } else { show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOGVERBATIM {%s} - COULDN'T OPEN FILE.", arg1); } } else { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOGVERBATIM} {filename} {string}"); } return ses; } DO_LINE(line_logmode) { struct session *active_ses; int old_mode = ses->log->mode; arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN); if (is_abbrev(arg1, "HTML")) { SET_BIT(ses->log->mode, LOG_FLAG_HTML); DEL_BIT(ses->log->mode, LOG_FLAG_PLAIN); DEL_BIT(ses->log->mode, LOG_FLAG_RAW); } else if (is_abbrev(arg1, "PLAIN")) { SET_BIT(ses->log->mode, LOG_FLAG_PLAIN); DEL_BIT(ses->log->mode, LOG_FLAG_HTML); DEL_BIT(ses->log->mode, LOG_FLAG_RAW); } else if (is_abbrev(arg1, "RAW")) { SET_BIT(ses->log->mode, LOG_FLAG_RAW); DEL_BIT(ses->log->mode, LOG_FLAG_HTML); DEL_BIT(ses->log->mode, LOG_FLAG_PLAIN); } else if (is_abbrev(arg1, "STAMP")) { SET_BIT(ses->log->mode, LOG_FLAG_STAMP); } else { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOGMODE} {HTML|PLAIN|RAW|STAMP} {command}."); return ses; } arg = get_arg_in_braces(ses, arg, arg1, GET_ALL); active_ses = script_driver(ses, LIST_COMMAND, arg1); ses->log->mode = old_mode; return active_ses; } DO_LINE(line_msdp) { arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN); if (*arg1 == 0) { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {MSDP} {command}."); return ses; } tintin2msdp(arg1, arg2); ses = script_driver(ses, LIST_COMMAND, arg2); return ses; } DO_LINE(line_json) { arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN); arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN); if (*arg1 == 0) { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {JSON} {command}."); return ses; } char *str_sub = str_alloc_stack(0); // struct listroot *root = ses->list[LIST_VARIABLE]; struct listnode *node = search_nest_node_ses(ses, arg1); if (node) { if (node->root) { view_nest_node_json(node, &str_sub, 0, TRUE); // print_lines(ses, SUB_NONE, "", "%s\n", str_sub); } else { sprintf(str_sub, "\"%s\"\n", node->arg2); } } else { show_error(ses, LIST_COMMAND, "#LINE JSON {%s}: VARIABLE NOT FOUND.", arg1); } RESTRING(gtd->cmds[0], str_sub); substitute(ses, arg2, str_sub, SUB_CMD); ses = script_driver(ses, LIST_COMMAND, str_sub); return ses; } DO_LINE(line_multishot) { unsigned int shots; arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN); arg = get_arg_in_braces(ses, arg, arg2, GET_ALL); shots = (unsigned int) get_number(ses, arg1); if (!is_math(ses, arg1) || *arg2 == 0) { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {MULTISHOT} {number} {command}."); return ses; } gtd->level->shots++; gtd->level->mshot = shots; ses = script_driver(ses, LIST_COMMAND, arg2); gtd->level->mshot = 1; gtd->level->shots--; return ses; } DO_LINE(line_oneshot) { arg = get_arg_in_braces(ses, arg, arg1, GET_ALL); if (*arg1 == 0) { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {ONESHOT} {command}."); return ses; } gtd->level->shots++; gtd->level->mshot = 1; ses = script_driver(ses, LIST_COMMAND, arg1); gtd->level->shots--; return ses; } DO_LINE(line_quiet) { arg = get_arg_in_braces(ses, arg, arg1, GET_ALL); if (*arg1 == 0) { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {QUIET} {command}."); return ses; } gtd->level->quiet++; ses = script_driver(ses, LIST_COMMAND, arg1); gtd->level->quiet--; return ses; } DO_LINE(line_strip) { arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_ESC|SUB_COL); if (*arg1 == 0) { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {STRIP} {command}."); return ses; } strip_vt102_codes(arg1, arg2); ses = script_driver(ses, LIST_COMMAND, arg2); return ses; } DO_LINE(line_substitute) { int i, flags = 0; arg = get_arg_in_braces(ses, arg, arg1, GET_ONE); arg = get_arg_in_braces(ses, arg, arg2, GET_ALL); if (*arg2 == 0) { for (i = 0 ; *substitution_table[i].name ; i++) { tintin_printf2(ses, "#SYNTAX: #LINE {SUBSTITUTE} {%s} {command}.", substitution_table[i].name); } return ses; } arg = arg1; while (*arg) { arg = get_arg_in_braces(ses, arg, arg3, GET_ONE); for (i = 0 ; *substitution_table[i].name ; i++) { if (is_abbrev(arg3, substitution_table[i].name)) { SET_BIT(flags, substitution_table[i].bitvector); } } if (*arg == COMMAND_SEPARATOR) { arg++; } } substitute(ses, arg2, arg3, flags); ses = script_driver(ses, LIST_COMMAND, arg3); return ses; } DO_LINE(line_verbatim) { arg = get_arg_in_braces(ses, arg, arg1, GET_ALL); if (*arg1 == 0) { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {VERBATIM} {command}."); return ses; } gtd->level->verbatim++; ses = parse_input(ses, arg1); gtd->level->verbatim--; return ses; } DO_LINE(line_verbose) { arg = get_arg_in_braces(ses, arg, arg1, GET_ALL); if (*arg1 == 0) { show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {VERBOSE} {command}."); return ses; } gtd->level->verbose++; ses = script_driver(ses, LIST_COMMAND, arg1); gtd->level->verbose--; return ses; }