text.c 11 KB

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