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 2004 *
24 ******************************************************************************/
25
26 #include "tintin.h"
27
28
print_line(struct session * ses,char ** str,int prompt)29 void print_line(struct session *ses, char **str, int prompt)
30 {
31 int height, width;
32 char *out;
33
34 push_call("print_line(%p,%p,%d)",ses,*str,prompt);
35
36 if (ses->scroll->line != -1 && HAS_BIT(ses->config_flags, CONFIG_FLAG_SCROLLLOCK))
37 {
38 pop_call();
39 return;
40 }
41
42 if (gtd->level->scan && gtd->level->verbose == 0)
43 {
44 pop_call();
45 return;
46 }
47
48 if (HAS_BIT(ses->flags, SES_FLAG_SPLIT) && ses->wrap != gtd->screen->cols)
49 {
50 SET_BIT(gtd->flags, TINTIN_FLAG_SESSIONUPDATE);
51 SET_BIT(ses->flags, SES_FLAG_PRINTLINE);
52
53 pop_call();
54 return;
55 }
56
57 out = str_alloc_stack(strlen(*str) * 2);
58
59 if (HAS_BIT(ses->config_flags, CONFIG_FLAG_CONVERTMETA) || gtd->level->convert)
60 {
61 convert_meta(*str, out, TRUE);
62
63 str_cpy(str, out);
64 }
65
66 if (HAS_BIT(ses->flags, SES_FLAG_SPLIT) || HAS_BIT(ses->config_flags, CONFIG_FLAG_WORDWRAP))
67 {
68 word_wrap(ses, *str, out, TRUE, &height, &width);
69 }
70 else
71 {
72 str_cpy(&out, *str);
73 }
74
75 if (prompt)
76 {
77 print_stdout(0, 0, "%s", out);
78 }
79 else
80 {
81 print_stdout(0, 0, "%s\n", out);
82 }
83
84 // add_line_screen(out);
85
86 pop_call();
87 return;
88 }
89
print_stdout(int row,int col,char * format,...)90 void print_stdout(int row, int col, char *format, ...)
91 {
92 char *buffer;
93 va_list args;
94 int len;
95
96 va_start(args, format);
97 len = vasprintf(&buffer, format, args);
98 va_end(args);
99
100 if (gtd->detach_port)
101 {
102 if (gtd->detach_sock)
103 {
104 if (write(gtd->detach_sock, buffer, len) == -1)
105 {
106 printf("error: print_stdout: write:\n");
107 }
108 }
109 }
110 else
111 {
112 SET_BIT(gtd->flags, TINTIN_FLAG_DISPLAYUPDATE);
113
114 fputs(buffer, stdout);
115 // printf("%s", buffer);
116
117 if (row && col)
118 {
119 set_line_screen(gtd->ses, buffer, row, col);
120 }
121 }
122 free(buffer);
123 }
124
125 /*
126 Word wrapper, only wraps scrolling region
127 */
128
word_wrap(struct session * ses,char * textin,char * textout,int flags,int * height,int * width)129 int word_wrap(struct session *ses, char *textin, char *textout, int flags, int *height, int *width)
130 {
131 char color[COLOR_SIZE];
132 char *pti, *pto, *lis, *los, *chi, *cho;
133 int cur_height, cur_width, size, i, skip, lines, cur_col, tab, wrap, cur_space;
134
135 push_call("word_wrap(%s,%p,%p)",ses->name,textin,textout);
136
137 pti = chi = lis = textin;
138 pto = cho = los = textout;
139
140 *color = 0;
141 cur_height = 0;
142 lines = 0;
143 *height = 0;
144
145 cur_col = ses->cur_col;
146 ses->cur_col = 1;
147 cur_space = 1;
148
149 cur_width = 0;
150 *width = 0;
151
152 skip = 0;
153
154 wrap = get_scroll_cols(ses);
155
156 while (*pti && pto - textout < BUFFER_SIZE)
157 {
158 skip = skip_vt102_codes(pti);
159
160 if (skip)
161 {
162 if (ses->color)
163 {
164 get_color_codes(color, pti, color, GET_ONE);
165
166 if (HAS_BIT(flags, WRAP_FLAG_DISPLAY))
167 {
168 interpret_vt102_codes(ses, pti, TRUE);
169 }
170
171 for (i = 0 ; i < skip ; i++)
172 {
173 *pto++ = *pti++;
174 }
175 }
176 else
177 {
178 pti += skip;
179 }
180 continue;
181 }
182
183 if (*pti == '\n')
184 {
185 lines++;
186 cur_height++;
187
188 *pto++ = *pti++;
189
190 lis = pti;
191 los = pto;
192
193 if (*pti)
194 {
195 pto += sprintf(pto, "%s", color);
196 }
197
198 if (cur_width > *width)
199 {
200 *width = cur_width;
201 }
202
203 cur_width = 0;
204 ses->cur_col = 1;
205 cur_space = 1;
206
207 continue;
208 }
209
210 if (*pti == ' ' || *pti == '\t')
211 {
212 cur_space = ses->cur_col;
213 los = pto;
214 lis = pti;
215 }
216
217 size = get_vt102_width(ses, pti, &tab);
218
219 if (ses->cur_col > 1 && ses->cur_col + tab > wrap + 1)
220 {
221 cur_height++;
222
223 // printf("cur_col %d tab %d wrap %d pti %d\n", ses->cur_col, tab, wrap, *pti);
224
225 if (HAS_BIT(ses->config_flags, CONFIG_FLAG_WORDWRAP))
226 {
227 if (ses->cur_col - cur_space >= 15 || wrap <= 20 || !SCROLL(ses))
228 {
229 *pto++ = '\n';
230 pto += sprintf(pto, "%s", color);
231
232 los = pto;
233 lis = pti;
234 }
235 else if (lis != chi) // infinite VT loop detection
236 {
237 pto = los;
238 *pto++ = '\n';
239 pto += sprintf(pto, "%s", color);
240 pti = chi = lis;
241 pti++;
242 }
243 else if (los != cho)
244 {
245 pto = cho = los;
246 pto++;
247 pti = chi = lis;
248 pti++;
249 }
250 }
251 else if (ses->wrap)
252 {
253 *pto++ = '\n';
254 }
255 ses->cur_col = 1;
256 cur_space = 1;
257 }
258 else
259 {
260 if (*pti == '\t')
261 {
262 tab = ses->tab_width - (ses->cur_col - 1) % ses->tab_width;
263
264 if (ses->cur_col + tab >= wrap) // xterm tabs
265 {
266 tab = (wrap - ses->cur_col);
267 }
268 pto += sprintf(pto, "%.*s", tab, " ");
269 pti++;
270
271 cur_width += tab;
272 ses->cur_col += tab;
273 cur_space = ses->cur_col;
274 }
275 else
276 {
277 while (size--)
278 {
279 *pto++ = *pti++;
280 }
281 cur_width += tab;
282 ses->cur_col += tab;
283 }
284 }
285 }
286 *pto = 0;
287
288 *height = cur_height + 1;
289
290 if (cur_width > *width)
291 {
292 *width = cur_width;
293 }
294
295 ses->cur_col = cur_col;
296
297 pop_call();
298 return lines + 1;
299 }
300
301 // store whatever falls inbetween skip and keep. Used by #buffer not checking SCROLL().
302
word_wrap_split(struct session * ses,char * textin,char * textout,int wrap,int start,int end,int flags,int * height,int * width)303 int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap, int start, int end, int flags, int *height, int *width)
304 {
305 char color[COLOR_SIZE] = { 0 };
306 char *pti, *pto, *lis, *los;
307 int cur_height, size, i, lines, cur_col, cur_width, tab, skip, cur_space;
308
309 push_call("word_wrap_split(%s,%p,%p,%d,%d,%d,%d)",ses->name,textin,textout,wrap,start,end,flags);
310
311 pti = lis = textin;
312 pto = los = textout;
313
314 if (wrap <= 0)
315 {
316 wrap = ses->wrap;
317
318 if (ses->wrap == 0)
319 {
320 print_stdout(0, 0, "debug: word_wrap_split: wrap is 0\n");
321 pop_call();
322 return 1;
323 }
324 }
325
326 lines = 0;
327 *height = 0;
328 cur_height = 0;
329 cur_width = 0;
330 *width = 0;
331 cur_col = 1;
332 cur_space = cur_col;
333
334 if (HAS_BIT(flags, WRAP_FLAG_SPLIT) && end == 0)
335 {
336 print_stdout(0, 0, "debug: word_wrap_split: end point is 0.");
337 }
338
339 while (*pti && pto - textout < BUFFER_SIZE - 20)
340 {
341 if (cur_height > 10000 || cur_width > 100000)
342 {
343 print_stdout(0, 0, "debug: word_wrap_split: wrap %d height %d width %d los %d start %d end %d\n", wrap, cur_height, cur_width, pto - los, start, end);
344 pop_call();
345 return 1;
346 }
347
348 skip = skip_vt102_codes(pti);
349
350 if (skip)
351 {
352 if (ses->color)
353 {
354 get_color_codes(color, pti, color, GET_ONE);
355
356 for (i = 0 ; i < skip ; i++)
357 {
358 *pto++ = *pti++;
359 }
360 }
361 else
362 {
363 pti += skip;
364 }
365 continue;
366 }
367
368 if (*pti == '\n')
369 {
370 if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
371 {
372 if (cur_width > *width)
373 {
374 *width = cur_width;
375 }
376 }
377
378 lines++;
379 cur_height++;
380
381 lis = pti;
382 los = pto;
383
384 if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height > start && cur_height < end))
385 {
386 *pto++ = *pti++;
387 }
388 else
389 {
390 pti++;
391 }
392
393 if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
394 {
395 if (*pti)
396 {
397 pto += sprintf(pto, "%s", color);
398 }
399 }
400
401 cur_col = 1;
402 cur_space = 1;
403 cur_width = 0;
404 continue;
405 }
406
407 if (*pti == ' ' || *pti == '\t')
408 {
409 cur_space = cur_col;
410 lis = pti;
411 los = pto;
412 }
413
414 size = get_vt102_width(ses, pti, &tab);
415
416 if (cur_col > 1 && cur_col + tab > wrap + 1)
417 {
418 if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
419 {
420 if (wrap > *width)
421 {
422 *width = wrap;
423 }
424 }
425 else
426 {
427 cur_width = 0;
428 }
429
430 cur_height++;
431
432 if (HAS_BIT(ses->config_flags, CONFIG_FLAG_WORDWRAP))
433 {
434 if (cur_col - cur_space > 15 || wrap <= 20)
435 {
436 if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height > start && cur_height < end))
437 {
438 *pto++ = '\n';
439 }
440
441 if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
442 {
443 pto += sprintf(pto, "%s", color);
444 // pto += sprintf(pto, "%s(%d,%d,%d)", color, start, end, cur_height);
445
446 }
447 }
448 else
449 {
450 pti = lis;
451 pto = los;
452
453 if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height > start && cur_height < end))
454 {
455 *pto++ = '\n';
456 }
457
458 if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
459 {
460 pto += sprintf(pto, "%s", color);
461
462 }
463 pti++;
464 }
465 }
466 else
467 {
468 if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height > start && cur_height < end))
469 {
470 *pto++ = '\n';
471 }
472
473 if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
474 {
475 pto += sprintf(pto, "%s", color);
476 }
477 }
478 cur_col = 1;
479 cur_space = 1;
480 continue;
481 }
482
483 if (*pti == '\t')
484 {
485 tab = ses->tab_width - (cur_col - 1) % ses->tab_width;
486
487 if (cur_col + tab >= wrap)
488 {
489 tab = (wrap - cur_col);
490 }
491
492 if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
493 {
494 pto += sprintf(pto, "%.*s", tab, " ");
495 }
496 pti++;
497
498 cur_width += tab;
499 cur_col += tab;
500 cur_space = cur_col;
501 }
502 else
503 {
504 if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
505 {
506 while (size--)
507 {
508 *pto++ = *pti++;
509 }
510 }
511 else
512 {
513 pti += size;
514 }
515 cur_width += tab;
516 cur_col += tab;
517 }
518 }
519 *pto = 0;
520
521 if (cur_width > *width)
522 {
523 *width = cur_width;
524 }
525 *height = cur_height + 1;
526
527 pop_call();
528 return lines + 1;
529 }
530
531