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