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