1 /******************************************************************************
2 *   This file is part of TinTin++                                             *
3 *                                                                             *
4 *   Copyright 2004-2020 Igor van den Hoven                                    *
5 *                                                                             *
6 *   TinTin++ is free software; you can redistribute it and/or modify          *
7 *   it under the terms of the GNU General Public License as published by      *
8 *   the Free Software Foundation; either version 3 of the License, or         *
9 *   (at your option) any later version.                                       *
10 *                                                                             *
11 *   This program is distributed in the hope that it will be useful,           *
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
14 *   GNU General Public License for more details.                              *
15 *                                                                             *
16 *   You should have received a copy of the GNU General Public License         *
17 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
18 ******************************************************************************/
19 
20 /******************************************************************************
21 *                               T I N T I N + +                               *
22 *                                                                             *
23 *                      coded by Igor van den Hoven 2008                       *
24 ******************************************************************************/
25 
26 #include "tintin.h"
27 
DO_COMMAND(do_line)28 DO_COMMAND(do_line)
29 {
30 	int cnt;
31 
32 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
33 
34 	if (*arg1 == 0)
35 	{
36 		info:
37 
38 		tintin_header(ses, 80, " LINE OPTIONS ");
39 
40 		for (cnt = 0 ; *line_table[cnt].fun != NULL ; cnt++)
41 		{
42 			if (*line_table[cnt].desc)
43 			{
44 				tintin_printf2(ses, "  [%-13s] %s", line_table[cnt].name, line_table[cnt].desc);
45 			}
46 		}
47 		tintin_header(ses, 80, "");
48 
49 		return ses;
50 	}
51 	else
52 	{
53 		for (cnt = 0 ; *line_table[cnt].name ; cnt++)
54 		{
55 			if (is_abbrev(arg1, line_table[cnt].name))
56 			{
57 				break;
58 			}
59 		}
60 
61 		if (*line_table[cnt].name == 0)
62 		{
63 			goto info;
64 		}
65 		else
66 		{
67 			ses = line_table[cnt].fun(ses, arg, arg1, arg2, arg3);
68 		}
69 	}
70 	return ses;
71 }
72 
DO_LINE(line_background)73 DO_LINE(line_background)
74 {
75 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
76 
77 	if (*arg1 == 0)
78 	{
79 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {BACKGROUND} {command}.");
80 
81 		return ses;
82 	}
83 
84 	gtd->level->background++;
85 
86 	ses = script_driver(ses, LIST_COMMAND, arg1);
87 
88 	gtd->level->background--;
89 
90 	return ses;
91 }
92 
DO_LINE(line_benchmark)93 DO_LINE(line_benchmark)
94 {
95 	long long start, end;
96 
97 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
98 
99 	if (*arg1 == 0)
100 	{
101 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {BENCHMARK} {command}.");
102 
103 		return ses;
104 	}
105 
106 	start = utime();
107 
108 	ses = script_driver(ses, LIST_COMMAND, arg1);
109 
110 	end = utime();
111 
112 	tintin_printf2(ses, "#LINE BENCHMARK: %lld USEC.", end - start);
113 
114 	return ses;
115 }
116 
DO_LINE(line_capture)117 DO_LINE(line_capture)
118 {
119 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
120 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
121 
122 	if (*arg1 && *arg2)
123 	{
124 		if (ses->line_capturefile)
125 		{
126 			free(ses->line_capturefile);
127 		}
128 		ses->line_capturefile  = strdup(arg1);
129 		ses->line_captureindex = 1;
130 
131 		ses = script_driver(ses, LIST_COMMAND, arg2);
132 
133 		if (ses->line_capturefile)
134 		{
135 			free(ses->line_capturefile);
136 			ses->line_capturefile = NULL;
137 		}
138 	}
139 	else
140 	{
141 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE CAPTURE {VARIABLE} {command}.");
142 	}
143 	return ses;
144 }
145 
DO_LINE(line_convert)146 DO_LINE(line_convert)
147 {
148 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
149 
150 	if (*arg1 == 0)
151 	{
152 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {CONVERT} {command}.");
153 
154 		return ses;
155 	}
156 
157 	// May need a clearer flag here.
158 
159 	gtd->level->convert++;
160 
161 	ses = script_driver(ses, LIST_COMMAND, arg1);
162 
163 	gtd->level->convert--;
164 
165 	return ses;
166 }
167 
DO_LINE(line_debug)168 DO_LINE(line_debug)
169 {
170 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
171 
172 	if (*arg1 == 0)
173 	{
174 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {DEBUG} {command}.");
175 
176 		return ses;
177 	}
178 
179 	gtd->level->debug++;
180 
181 	ses = script_driver(ses, LIST_COMMAND, arg1);
182 
183 	gtd->level->debug--;
184 
185 	return ses;
186 }
187 
DO_LINE(line_gag)188 DO_LINE(line_gag)
189 {
190 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
191 
192 	switch (*arg1)
193 	{
194 		case '-':
195 			ses->gagline -= get_number(ses, arg1+1);
196 			break;
197 		case '+':
198 			ses->gagline += get_number(ses, arg1+1);
199 			break;
200 		case 0:
201 			ses->gagline = 1;
202 			break;
203 		default:
204 			ses->gagline = get_number(ses, arg1);
205 			break;
206 	}
207 
208 	show_debug(ses, LIST_GAG, "#DEBUG LINE GAG {%s}", arg1);
209 
210 //	SET_BIT(ses->flags, SES_FLAG_GAG);
211 
212 	return ses;
213 }
214 
DO_LINE(line_ignore)215 DO_LINE(line_ignore)
216 {
217 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
218 
219 	if (*arg1 == 0)
220 	{
221 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {IGNORE} {command}.");
222 
223 		return ses;
224 	}
225 
226 	gtd->level->ignore++;
227 
228 	ses = script_driver(ses, LIST_COMMAND, arg1);
229 
230 	gtd->level->ignore--;
231 
232 	return ses;
233 }
234 
DO_LINE(line_local)235 DO_LINE(line_local)
236 {
237 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
238 
239 	if (*arg1 == 0)
240 	{
241 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOCAL} {command}.");
242 
243 		return ses;
244 	}
245 
246 	gtd->level->local++;
247 
248 	SET_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
249 
250 	ses = script_driver(ses, LIST_COMMAND, arg1);
251 
252 	gtd->level->local--;
253 
254 	return ses;
255 }
256 
257 // Without an argument mark next line to be logged, otherwise log the given line to file.
258 
DO_LINE(line_log)259 DO_LINE(line_log)
260 {
261 	FILE *logfile;
262 
263 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
264 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
265 
266 	if (*arg1 && *arg2)
267 	{
268 		substitute(ses, arg2, arg2, SUB_ESC|SUB_COL|SUB_LNF);
269 
270 		if (ses->log->file && !strcmp(ses->log->name, arg1))
271 		{
272 			logit(ses, arg2, ses->log->file, LOG_FLAG_NONE);
273 		}
274 		else if (ses->log->line_time == gtd->time && !strcmp(ses->log->line_name, arg1))
275 		{
276 			logit(ses, arg2, ses->log->line_file, LOG_FLAG_NONE);
277 		}
278 		else
279 		{
280 			if ((logfile = fopen(arg1, "a")))
281 			{
282 				if (ses->log->line_file)
283 				{
284 					fclose(ses->log->line_file);
285 				}
286 				free(ses->log->line_name);
287 
288 				ses->log->line_name = strdup(arg1);
289 				ses->log->line_file = logfile;
290 				ses->log->line_time = gtd->time;
291 
292 				logheader(ses, ses->log->line_file, LOG_FLAG_APPEND | HAS_BIT(ses->log->mode, LOG_FLAG_HTML));
293 
294 				logit(ses, arg2, ses->log->line_file, LOG_FLAG_NONE);
295 			}
296 			else
297 			{
298 				show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOG {%s} - COULDN'T OPEN FILE.", arg1);
299 			}
300 		}
301 	}
302 	else
303 	{
304 		if (ses->log->next_time == gtd->time && !strcmp(ses->log->next_name, arg1))
305 		{
306 			SET_BIT(ses->log->mode, LOG_FLAG_NEXT);
307 		}
308 		else if ((logfile = fopen(arg1, "a")))
309 		{
310 			if (ses->log->next_file)
311 			{
312 				fclose(ses->log->next_file);
313 			}
314 			free(ses->log->next_name);
315 
316 			ses->log->next_name = strdup(arg1);
317 			ses->log->next_file = logfile;
318 			ses->log->next_time = gtd->time;
319 
320 			SET_BIT(ses->log->mode, LOG_FLAG_NEXT);
321 		}
322 		else
323 		{
324 			show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOG {%s} - COULDN'T OPEN FILE.", arg1);
325 		}
326 	}
327 	return ses;
328 }
329 
DO_LINE(line_logmode)330 DO_LINE(line_logmode)
331 {
332 	struct session *active_ses;
333 
334 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
335 
336 	DEL_BIT(ses->log->mode, LOG_FLAG_OLD_HTML|LOG_FLAG_OLD_PLAIN|LOG_FLAG_OLD_RAW);
337 
338 	switch (HAS_BIT(ses->log->mode, LOG_FLAG_HTML|LOG_FLAG_PLAIN|LOG_FLAG_RAW))
339 	{
340 		case LOG_FLAG_HTML:
341 			SET_BIT(ses->log->mode, LOG_FLAG_OLD_HTML);
342 			break;
343 		case LOG_FLAG_PLAIN:
344 			SET_BIT(ses->log->mode, LOG_FLAG_OLD_PLAIN);
345 			break;
346 		case LOG_FLAG_RAW:
347 			SET_BIT(ses->log->mode, LOG_FLAG_OLD_RAW);
348 			break;
349 	}
350 
351 	if (is_abbrev(arg1, "HTML"))
352 	{
353 		SET_BIT(ses->log->mode, LOG_FLAG_HTML);
354 		DEL_BIT(ses->log->mode, LOG_FLAG_PLAIN);
355 		DEL_BIT(ses->log->mode, LOG_FLAG_RAW);
356 	}
357 	else if (is_abbrev(arg1, "PLAIN"))
358 	{
359 		SET_BIT(ses->log->mode, LOG_FLAG_PLAIN);
360 		DEL_BIT(ses->log->mode, LOG_FLAG_HTML);
361 		DEL_BIT(ses->log->mode, LOG_FLAG_RAW);
362 	}
363 	else if (is_abbrev(arg1, "RAW"))
364 	{
365 		SET_BIT(ses->log->mode, LOG_FLAG_RAW);
366 		DEL_BIT(ses->log->mode, LOG_FLAG_HTML);
367 		DEL_BIT(ses->log->mode, LOG_FLAG_PLAIN);
368 	}
369 	else
370 	{
371 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOGMODE} {HTML|PLAIN|RAW} {command}.");
372 
373 		return ses;
374 	}
375 
376 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
377 
378 	active_ses = script_driver(ses, LIST_COMMAND, arg1);
379 
380 	DEL_BIT(ses->log->mode, LOG_FLAG_HTML|LOG_FLAG_PLAIN|LOG_FLAG_RAW);
381 
382 	switch (HAS_BIT(ses->log->mode, LOG_FLAG_OLD_HTML|LOG_FLAG_OLD_PLAIN|LOG_FLAG_OLD_RAW))
383 	{
384 		case LOG_FLAG_OLD_HTML:
385 			SET_BIT(ses->log->mode, LOG_FLAG_HTML);
386 			break;
387 		case LOG_FLAG_OLD_PLAIN:
388 			SET_BIT(ses->log->mode, LOG_FLAG_PLAIN);
389 			break;
390 		case LOG_FLAG_OLD_RAW:
391 			SET_BIT(ses->log->mode, LOG_FLAG_RAW);
392 			break;
393 	}
394 
395 	return ses = active_ses;
396 }
397 
DO_LINE(line_logverbatim)398 DO_LINE(line_logverbatim)
399 {
400 	FILE *logfile;
401 
402 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
403 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
404 
405 	if (*arg1 && *arg2)
406 	{
407 		if (!strcmp(ses->log->line_name, arg1))
408 		{
409 			logit(ses, arg2, ses->log->line_file, LOG_FLAG_LINEFEED);
410 		}
411 		else
412 		{
413 			if ((logfile = fopen(arg1, "a")))
414 			{
415 				if (ses->log->line_file)
416 				{
417 					fclose(ses->log->line_file);
418 				}
419 				free(ses->log->line_name);
420 				ses->log->line_name = strdup(arg1);
421 				ses->log->line_file = logfile;
422 
423 				logheader(ses, ses->log->line_file, LOG_FLAG_APPEND | HAS_BIT(ses->log->mode, LOG_FLAG_HTML));
424 
425 				logit(ses, arg2, ses->log->line_file, LOG_FLAG_LINEFEED);
426 			}
427 			else
428 			{
429 				show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOGVERBATIM {%s} - COULDN'T OPEN FILE.", arg1);
430 			}
431 		}
432 	}
433 	else
434 	{
435 		if (!strcmp(ses->log->next_name, arg1))
436 		{
437 			SET_BIT(ses->log->mode, LOG_FLAG_NEXT);
438 		}
439 		else if ((logfile = fopen(arg1, "a")))
440 		{
441 			if (ses->log->next_file)
442 			{
443 				fclose(ses->log->next_file);
444 			}
445 			free(ses->log->next_name);
446 			ses->log->next_name = strdup(arg1);
447 			ses->log->next_file = logfile;
448 
449 			SET_BIT(ses->log->mode, LOG_FLAG_NEXT);
450 		}
451 		else
452 		{
453 			show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOGVERBATIM {%s} - COULDN'T OPEN FILE.", arg1);
454 		}
455 	}
456 	return ses;
457 }
458 
DO_LINE(line_msdp)459 DO_LINE(line_msdp)
460 {
461 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
462 
463 	if (*arg1 == 0)
464 	{
465 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {STRIP} {command}.");
466 
467 		return ses;
468 	}
469 
470 	tintin2msdp(arg1, arg2);
471 
472 	ses = script_driver(ses, LIST_COMMAND, arg2);
473 
474 	return ses;
475 }
476 
DO_LINE(line_multishot)477 DO_LINE(line_multishot)
478 {
479 	unsigned int shots;
480 
481 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
482 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
483 
484 	shots = (unsigned int) get_number(ses, arg1);
485 
486 	if (!is_math(ses, arg1) || *arg2 == 0)
487 	{
488 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {MULTISHOT} {number} {command}.");
489 
490 		return ses;
491 	}
492 
493 	gtd->level->shots++;
494 
495 	gtd->level->mshot = shots;
496 
497 	ses = script_driver(ses, LIST_COMMAND, arg2);
498 
499 	gtd->level->mshot = 1;
500 
501 	gtd->level->shots--;
502 
503 	return ses;
504 }
505 
DO_LINE(line_oneshot)506 DO_LINE(line_oneshot)
507 {
508 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
509 
510 	if (*arg1 == 0)
511 	{
512 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {ONESHOT} {command}.");
513 
514 		return ses;
515 	}
516 
517 	gtd->level->shots++;
518 
519 	gtd->level->mshot = 1;
520 
521 	ses = script_driver(ses, LIST_COMMAND, arg1);
522 
523 	gtd->level->shots--;
524 
525 	return ses;
526 }
527 
DO_LINE(line_quiet)528 DO_LINE(line_quiet)
529 {
530 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
531 
532 	if (*arg1 == 0)
533 	{
534 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {QUIET} {command}.");
535 
536 		return ses;
537 	}
538 
539 	gtd->level->quiet++;
540 
541 	ses = script_driver(ses, LIST_COMMAND, arg1);
542 
543 	gtd->level->quiet--;
544 
545 	return ses;
546 }
547 
DO_LINE(line_strip)548 DO_LINE(line_strip)
549 {
550 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_ESC|SUB_COL);
551 
552 	if (*arg1 == 0)
553 	{
554 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {STRIP} {command}.");
555 
556 		return ses;
557 	}
558 
559 	strip_vt102_codes(arg1, arg2);
560 
561 	ses = script_driver(ses, LIST_COMMAND, arg2);
562 
563 	return ses;
564 }
565 
DO_LINE(line_substitute)566 DO_LINE(line_substitute)
567 {
568 	int i, flags = 0;
569 
570 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
571 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
572 
573 	if (*arg2 == 0)
574 	{
575 		for (i = 0 ; *substitution_table[i].name ; i++)
576 		{
577 			tintin_printf2(ses, "#SYNTAX: #LINE {SUBSTITUTE} {%s} {command}.", substitution_table[i].name);
578 		}
579 		return ses;
580 	}
581 
582 	arg = arg1;
583 
584 	while (*arg)
585 	{
586 		arg = get_arg_in_braces(ses, arg, arg3, GET_ONE);
587 
588 		for (i = 0 ; *substitution_table[i].name ; i++)
589 		{
590 			if (is_abbrev(arg3, substitution_table[i].name))
591 			{
592 				SET_BIT(flags, substitution_table[i].bitvector);
593 			}
594 		}
595 
596 		if (*arg == COMMAND_SEPARATOR)
597 		{
598 			arg++;
599 		}
600 	}
601 
602 	substitute(ses, arg2, arg3, flags);
603 
604 	ses = script_driver(ses, LIST_COMMAND, arg3);
605 
606 	return ses;
607 }
608 
DO_LINE(line_verbatim)609 DO_LINE(line_verbatim)
610 {
611 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
612 
613 	if (*arg1 == 0)
614 	{
615 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {VERBATIM} {command}.");
616 
617 		return ses;
618 	}
619 
620 	gtd->level->verbatim++;
621 
622 	ses = parse_input(ses, arg1);
623 
624 	gtd->level->verbatim--;
625 
626 	return ses;
627 }
628 
DO_LINE(line_verbose)629 DO_LINE(line_verbose)
630 {
631 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
632 
633 	if (*arg1 == 0)
634 	{
635 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {VERBOSE} {command}.");
636 
637 		return ses;
638 	}
639 
640 	gtd->level->verbose++;
641 
642 	ses = script_driver(ses, LIST_COMMAND, arg1);
643 
644 	gtd->level->verbose--;
645 
646 	return ses;
647 }
648 
649