render.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. #include "render.h"
  2. #include "terminal.h"
  3. #include "utils.h"
  4. #include "zf_log.h"
  5. #include <ctype.h>
  6. #include <sstream>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <time.h>
  10. #include <unistd.h> // usleep
  11. #include <vector>
  12. // Does this copy the terminal?
  13. Render::Render(int fd, Terminal &term) : term(term) {
  14. this->fd = fd;
  15. reset();
  16. }
  17. void Render::reset(void) {
  18. speed = 0;
  19. effect = 0;
  20. overlimit = 0;
  21. image_data = nullptr; // FUTURE: vector
  22. image_size = 0; // FUTURE: vector
  23. }
  24. void Render::set_image(const char **lines, int size) {
  25. image_data = lines;
  26. image_size = size;
  27. }
  28. void Render::reset_image(void) {
  29. image_data = nullptr;
  30. image_size = 0;
  31. }
  32. void Render::sleep(void) {
  33. if (overlimit)
  34. return;
  35. if (speed) { // * 100 still too slow.
  36. ms_sleep(speed * 10);
  37. }
  38. }
  39. int Render::ms_sleep(unsigned int ms) {
  40. int result = 0;
  41. struct timespec ts = {ms / 1000, (ms % 1000) * 1000000L};
  42. do {
  43. struct timespec ts_sleep = ts;
  44. result = nanosleep(&ts_sleep, &ts);
  45. } while ((-1 == result));
  46. return result;
  47. }
  48. void Render::color(int color) {
  49. const int MYSTIC[] = {0, 4, 2, 6, 1, 5, 3, 7};
  50. std::ostringstream oss;
  51. switch (color) {
  52. case 0:
  53. case 1:
  54. case 2:
  55. case 3:
  56. case 4:
  57. case 5:
  58. case 6:
  59. case 7:
  60. oss << "\x1b[0;" << MYSTIC[color] + 30 << "m";
  61. break;
  62. case 8:
  63. case 9:
  64. case 10:
  65. case 11:
  66. case 12:
  67. case 13:
  68. case 14:
  69. case 15:
  70. oss << "\x1b[0;1;" << MYSTIC[color - 8] + 30 << "m";
  71. break;
  72. case 16:
  73. case 17:
  74. case 18:
  75. case 19:
  76. case 20:
  77. case 21:
  78. case 22:
  79. case 23:
  80. oss << "\x1b[" << MYSTIC[color - 16] + 40 << "m";
  81. break;
  82. case 24:
  83. case 25:
  84. case 26:
  85. case 27:
  86. case 28:
  87. case 29:
  88. case 30:
  89. case 31:
  90. oss << "\x1b[5;" << MYSTIC[color - 24] + 40 << "m";
  91. break;
  92. default:
  93. break;
  94. }
  95. std::string buffer = oss.str();
  96. ZF_LOGD("write_color( %d ): %s", color, repr(buffer.c_str()));
  97. write(fd, buffer.c_str(), buffer.size());
  98. }
  99. void Render::pos_goto(int x, int y) {
  100. std::ostringstream oss;
  101. oss << "\x1b[" << y << ";" << x << "H";
  102. std::string buffer = oss.str();
  103. write(fd, buffer.c_str(), buffer.size());
  104. };
  105. void Render::send(char ch) { // render_effect
  106. // int effect = effect;
  107. int l;
  108. char space = ' ';
  109. char bs = '\b';
  110. Terminal::termchar tc;
  111. tc = term.putchar(ch);
  112. if (tc.in_ansi) {
  113. // We are inside ANSI command, so
  114. write(fd, &ch, 1);
  115. return;
  116. }
  117. switch (effect) {
  118. case 1:
  119. // CHAR + SPC + BS
  120. render_sleep();
  121. write(fd, &ch, 1);
  122. render_sleep();
  123. write(fd, &space, 1);
  124. render_sleep();
  125. render_sleep();
  126. write(fd, &bs, 1);
  127. break;
  128. case 2:
  129. // CHAR + 8 spaces + 8 BS
  130. // This might be too much.
  131. #define MOVE 4
  132. render_sleep();
  133. write(fd, &ch, 1);
  134. for (l = 0; l < MOVE; l++) {
  135. render_sleep();
  136. write(fd, &space, 1);
  137. }
  138. for (l = 0; l < MOVE; l++) {
  139. render_sleep();
  140. write(fd, &bs, 1);
  141. }
  142. break;
  143. case 0:
  144. default:
  145. // NORMAL
  146. render_sleep();
  147. write(fd, &ch, 1);
  148. break;
  149. }
  150. }
  151. void Render::send(std::string &string_out) { // render
  152. time_t start = time(NULL);
  153. size_t pos = 0;
  154. int elapsed;
  155. size_t tpos;
  156. while ((tpos = string_out.find(TRIGGER, pos)) != std::string::npos) {
  157. while (pos != tpos) {
  158. elapsed = time(NULL) - start;
  159. if (elapsed > SLEEP_LIMIT) {
  160. overlimit = 1;
  161. speed = 0;
  162. }
  163. send(string_out[pos]);
  164. pos++;
  165. }
  166. pos += strlen(TRIGGER);
  167. process_trigger(string_out, pos);
  168. }
  169. while (pos < string_out.size()) {
  170. elapsed = time(NULL) - start;
  171. if (elapsed > SLEEP_LIMIT) {
  172. overlimit = 1;
  173. speed = 0;
  174. }
  175. send(string_out[pos]);
  176. pos++;
  177. }
  178. }
  179. int Render::digit(std::string str, size_t &pos, int digits) {
  180. int i = 0;
  181. while (digits > 0) {
  182. if (std::isdigit(str[pos])) {
  183. i *= 10;
  184. i += str[pos] - '0';
  185. pos++;
  186. } else {
  187. ZF_LOGE("digit fail");
  188. }
  189. digits--;
  190. };
  191. return i;
  192. }
  193. void Render::process_trigger(std::string str, size_t &pos) {
  194. char ch = str[pos];
  195. int i, x, y;
  196. pos++;
  197. switch (ch) {
  198. case 'D':
  199. i = digit(str, pos, 2);
  200. if ((i > 0) && (i < 80)) {
  201. ZF_LOGI("DEL %02d", i);
  202. for (x = 0; x < i; x++) {
  203. write(fd, "\b \b", 3);
  204. term.putstring("\b \b");
  205. }
  206. };
  207. break;
  208. case 'C': {
  209. i = 0;
  210. if (str[pos] == 'S') {
  211. pos++;
  212. color_history.push_back(term.color_restore());
  213. // console_history.push_back(console);
  214. ZF_LOGI("saved color [%s].", term.color_restore().c_str());
  215. break;
  216. }
  217. if (str[pos] == 'R') {
  218. pos++;
  219. if (color_history.empty()) {
  220. ZF_LOGE("Trying to Color Restore from empty vector!");
  221. break;
  222. }
  223. std::string restore = color_history.back();
  224. color_history.pop_back();
  225. ZF_LOGI("restored color [%s].", restore.c_str());
  226. write(fd, restore.c_str(), restore.size());
  227. break;
  228. }
  229. i = digit(str, pos, 2);
  230. write_color(fd, i);
  231. } break;
  232. // no longer takes a filename. :)
  233. case 'F':
  234. case 'f': {
  235. int UsePos = 0;
  236. if (ch == 'f') {
  237. UsePos = 1;
  238. x = digit(str, pos, 2);
  239. y = digit(str, pos, 2);
  240. ZF_LOGI("file at (%d, %d)", x, y);
  241. }
  242. ZF_LOGD("IMAGE (%d lines)", image_size);
  243. if (UsePos) {
  244. send_image(x, y);
  245. } else {
  246. send_image();
  247. };
  248. } break;
  249. case 'G': {
  250. x = digit(str, pos, 2);
  251. y = digit(str, pos, 2);
  252. char buffer[20]; // row ; column H
  253. int slen;
  254. ZF_LOGD("GOTO (%d,%d)", x, y);
  255. slen = snprintf(buffer, sizeof(buffer), "\x1b[%d;%dH", y, x);
  256. if (slen >= (int)sizeof(buffer)) {
  257. ZF_LOGE("snprintf %d > size %d", slen, (int)sizeof(buffer));
  258. buffer[0] = 0;
  259. }
  260. write(fd, buffer, strlen(buffer));
  261. } break;
  262. case 'R': {
  263. i = digit(str, pos);
  264. if ((i >= 0) && (i < 10)) {
  265. ZF_LOGI("RENDER %d", i);
  266. effect = i;
  267. } else {
  268. effect = 0;
  269. }
  270. } break;
  271. case 'S': {
  272. i = digit(str, pos);
  273. if ((i >= 0) && (i < 10)) {
  274. ZF_LOGI("SPEED %d", i);
  275. speed = i;
  276. } else {
  277. speed = 0;
  278. }
  279. } break;
  280. case 'P': {
  281. i = digit(str, pos);
  282. if ((i >= 0) && (i < 10)) {
  283. ZF_LOGI("PAWS %d", i);
  284. // sleep(i);
  285. if (!overlimit) {
  286. // sleep(i);
  287. ms_sleep(i * 1000);
  288. };
  289. }
  290. } break;
  291. }
  292. }
  293. int Render::send_image(int x, int y) {
  294. int i;
  295. const char **lines = image_data;
  296. if (lines == nullptr) {
  297. ZF_LOGE("No image data for send_image(%d,%d)", x, y);
  298. return 0;
  299. }
  300. for (i = 0; i < image_size; i++) {
  301. send_goto(fd, x, y);
  302. y++;
  303. write(fd, lines[i], strlen(lines[i]));
  304. }
  305. // success
  306. reset_image();
  307. return 1;
  308. }
  309. int Render::send_image(void) {
  310. int i;
  311. const char **lines = image_data;
  312. if (lines == nullptr) {
  313. ZF_LOGE("No image data for send_image.");
  314. return 0;
  315. }
  316. for (i = 0; i < image_size; i++) {
  317. std::string line(lines[i]);
  318. line.append("\r\n");
  319. // rendering the ^BAT^ was a bad idea. (uses ^ chars).
  320. // render(fd, line);
  321. write(fd, lines[i], strlen(lines[i]));
  322. write(fd, "\r\n", 2);
  323. }
  324. // success
  325. reset_image();
  326. return 1;
  327. }
  328. extern const char *strnstr(const char *source, int len, const char *needle);
  329. extern struct console_details console;
  330. struct render current_render;
  331. int render_overlimit = 0;
  332. void reset_render(void) {
  333. current_render.speed = 0;
  334. current_render.effect = 0;
  335. render_overlimit = 0;
  336. }
  337. // or possibly a vector, and pop the image pointer off
  338. // allowing for multiple images.
  339. const char **image_data = NULL;
  340. int image_size = 0;
  341. void render_image(const char **lines, int size) {
  342. image_data = lines;
  343. image_size = size;
  344. }
  345. void reset_image(void) {
  346. image_data = NULL;
  347. image_size = 0;
  348. }
  349. int ms_sleep(unsigned int ms) {
  350. int result = 0;
  351. struct timespec ts = {ms / 1000, (ms % 1000) * 1000000L};
  352. do {
  353. struct timespec ts_sleep = ts;
  354. result = nanosleep(&ts_sleep, &ts);
  355. } while ((-1 == result));
  356. return result;
  357. }
  358. void render_sleep(void) {
  359. if (render_overlimit)
  360. return;
  361. if (current_render.speed) { // * 100 still too slow.
  362. ms_sleep(current_render.speed * 10);
  363. }
  364. }
  365. /*
  366. Well SNAP! Mystic numbers don't remotely match ANSI color codes.
  367. 00 : Sets the current foreground to Black 0;30
  368. 01 : Sets the current foreground to Dark Blue 0;34
  369. 02 : Sets the current foreground to Dark Green 0;32
  370. 03 : Sets the current foreground to Dark Cyan 0;36
  371. 04 : Sets the current foreground to Dark Red 0;31
  372. 05 : Sets the current foreground to Dark Magenta 0;35
  373. 06 : Sets the current foreground to Brown 0;33
  374. 07 : Sets the current foreground to Grey 0;37
  375. 08 : Sets the current foreground to Dark Grey 1;30
  376. 09 : Sets the current foreground to Light Blue 1;34
  377. 10 : Sets the current foreground to Light Green 1;32
  378. 11 : Sets the current foreground to Light Cyan 1;36
  379. 12 : Sets the current foreground to Light Red 1;31
  380. 13 : Sets the current foreground to Light Magenta 1;35
  381. 14 : Sets the current foreground to Yellow 1;33
  382. 15 : Sets the current foreground to White 1;37
  383. 16 : Sets the current background to Black 40
  384. 17 : Sets the current background to Blue 44
  385. 18 : Sets the current background to Green 42
  386. 19 : Sets the current background to Cyan 46
  387. 20 : Sets the current background to Red 41
  388. 21 : Sets the current background to Magenta 45
  389. 22 : Sets the current background to Brown 43
  390. 23 : Sets the current background to Grey 47
  391. 24 : Sets the current background to black with blinking foreground 5;40
  392. 25 : Sets the current background to blue with blinking foreground 5;44
  393. 26 : Sets the current background to green with blinking foreground 5;42
  394. 27 : Sets the current background to cyan with blinking foreground 5;46
  395. 28 : Sets the current background to red with blinking foreground 5;41
  396. 29 : Sets the current background to magenta with blinking foreground 5;45
  397. 30 : Sets the current background to brown with blinking foreground 5;43
  398. 31 : Sets the current background to grey with blinking foreground 5;47
  399. Other things that Mystic does ...
  400. [A## - Move the cursor up ## lines
  401. [B## - Move the cursor down ## lines
  402. [C## - Move the cursor forward (to the right) ## columns
  403. [D## - Move the cursor backwards (to the left) ## columns
  404. [K - Clear from the current cursor position to the end of the line
  405. [L - Move cursor and erase data backwards from current column to column ##
  406. [X## - Move cursor to X coordinate ##
  407. [Y## - Move cursor to Y coordinate ##
  408. BS - Sends 1 destructive backspace sequence (ASCII 8-32-8)
  409. CL - Clears the screen (ANSI 1,1 locate and [2J or ASCII 12)
  410. CR - Send a carrage return and line feed (move to next line)
  411. RA - Restore the saved text attribute color
  412. RS - Restore the saved user's terminal screen
  413. SA - Save the current text attribute color
  414. SS - Save the entire user's terminal screen
  415. */
  416. // Covert MYSTIC color to (Proper) ANSI COLOR.
  417. const int MYSTIC[] = {0, 4, 2, 6, 1, 5, 3, 7};
  418. // ANSI_color = MYSTIC[ odd_mystic_color % 8 ]
  419. void write_color(int fd, int color) {
  420. char buffer[12];
  421. int slen;
  422. switch (color) {
  423. case 0:
  424. case 1:
  425. case 2:
  426. case 3:
  427. case 4:
  428. case 5:
  429. case 6:
  430. case 7:
  431. slen = snprintf(buffer, sizeof(buffer), "\x1b[0;3%dm", MYSTIC[color]);
  432. if (slen >= (int)sizeof(buffer)) {
  433. ZF_LOGE("snprintf %d > size %d", slen, (int)sizeof(buffer));
  434. buffer[0] = 0;
  435. }
  436. break;
  437. case 8:
  438. case 9:
  439. case 10:
  440. case 11:
  441. case 12:
  442. case 13:
  443. case 14:
  444. case 15:
  445. slen = snprintf(buffer, sizeof(buffer), "\x1b[0;1;3%dm", MYSTIC[color - 8]);
  446. if (slen >= (int)sizeof(buffer)) {
  447. ZF_LOGE("snprintf %d > size %d", slen, (int)sizeof(buffer));
  448. buffer[0] = 0;
  449. }
  450. break;
  451. case 16:
  452. case 17:
  453. case 18:
  454. case 19:
  455. case 20:
  456. case 21:
  457. case 22:
  458. case 23:
  459. slen = snprintf(buffer, sizeof(buffer), "\x1b[4%dm", MYSTIC[color - 16]);
  460. if (slen >= (int)sizeof(buffer)) {
  461. ZF_LOGE("snprintf %d > size %d", slen, (int)sizeof(buffer));
  462. buffer[0] = 0;
  463. }
  464. break;
  465. case 24:
  466. case 25:
  467. case 26:
  468. case 27:
  469. case 28:
  470. case 29:
  471. case 30:
  472. case 31:
  473. slen = snprintf(buffer, sizeof(buffer), "\x1b[5;4%dm", MYSTIC[color - 24]);
  474. if (slen >= (int)sizeof(buffer)) {
  475. ZF_LOGE("snprintf %d > size %d", slen, (int)sizeof(buffer));
  476. buffer[0] = 0;
  477. }
  478. break;
  479. default:
  480. buffer[0] = 0;
  481. break;
  482. }
  483. ZF_LOGD("write_color( %d ): %s", color, repr(buffer));
  484. write(fd, buffer, strlen(buffer));
  485. }
  486. void send_goto(int fd, int x, int y) {
  487. char gbuffer[16];
  488. int slen;
  489. slen = snprintf(gbuffer, sizeof(gbuffer), "\x1b[%d;%dH", y, x);
  490. if (slen >= (int)sizeof(gbuffer)) {
  491. ZF_LOGE("snprintf %d > size %d", slen, (int)sizeof(gbuffer));
  492. gbuffer[0] = 0;
  493. }
  494. write(fd, gbuffer, strlen(gbuffer));
  495. }
  496. int send_image(int fd) {
  497. int i;
  498. const char **lines = image_data;
  499. if (lines == NULL) {
  500. ZF_LOGE("No image data for send_image.");
  501. return 0;
  502. }
  503. for (i = 0; i < image_size; i++) {
  504. std::string line(lines[i]);
  505. line.append("\r\n");
  506. // rendering the ^BAT^ was a bad idea. (uses ^ chars).
  507. // render(fd, line);
  508. write(fd, lines[i], strlen(lines[i]));
  509. write(fd, "\r\n", 2);
  510. }
  511. // success
  512. reset_image();
  513. return 1;
  514. }
  515. int send_image(int fd, int x, int y) {
  516. int i;
  517. const char **lines = image_data;
  518. if (lines == NULL) {
  519. ZF_LOGE("No image data for send_image(%d,%d)", x, y);
  520. return 0;
  521. }
  522. for (i = 0; i < image_size; i++) {
  523. send_goto(fd, x, y);
  524. y++;
  525. write(fd, lines[i], strlen(lines[i]));
  526. }
  527. // success
  528. reset_image();
  529. return 1;
  530. }
  531. int digit(std::string str, size_t &pos, int digits = 1) {
  532. int i = 0;
  533. while (digits > 0) {
  534. if (std::isdigit(str[pos])) {
  535. i *= 10;
  536. i += str[pos] - '0';
  537. pos++;
  538. } else {
  539. ZF_LOGE("digit fail");
  540. }
  541. digits--;
  542. };
  543. return i;
  544. }
  545. static std::vector<console_details> console_history;
  546. /**
  547. * process_trigger( fd, str, &pos )
  548. *
  549. * This process a command trigger.
  550. * It has seen TRIGGER, and now it is
  551. * processing whatever comes after it.
  552. * It will perform the process, and
  553. * update pos to whatever is next.
  554. */
  555. void process_trigger(int fd, std::string str, size_t &pos) {
  556. char ch = str[pos];
  557. int i, x, y;
  558. pos++;
  559. switch (ch) {
  560. case 'D':
  561. i = digit(str, pos, 2);
  562. if ((i > 0) && (i < 80)) {
  563. ZF_LOGI("DEL %02d", i);
  564. for (x = 0; x < i; x++) {
  565. write(fd, "\b \b", 3);
  566. console_receive(&console, "\b \b");
  567. }
  568. };
  569. break;
  570. case 'C': {
  571. i = 0;
  572. if (str[pos] == 'S') {
  573. pos++;
  574. console_history.push_back(console);
  575. ZF_LOGI("saved color [%d/%d/%d].", console.fgcolor, console.bgcolor, console.status);
  576. break;
  577. }
  578. if (str[pos] == 'R') {
  579. pos++;
  580. if (console_history.empty()) {
  581. ZF_LOGE("Trying to Color Restore from empty vector!");
  582. break;
  583. }
  584. console_details old_color = console_history.back();
  585. console_history.pop_back();
  586. const char *restore = color_restore(&old_color);
  587. ZF_LOGI("restore color [%d/%d/%d] %s", old_color.fgcolor, old_color.bgcolor, old_color.status, repr(restore));
  588. write(fd, restore, strlen(restore));
  589. break;
  590. }
  591. i = digit(str, pos, 2);
  592. write_color(fd, i);
  593. } break;
  594. // no longer takes a filename. :)
  595. case 'F':
  596. case 'f': {
  597. int UsePos = 0;
  598. if (ch == 'f') {
  599. UsePos = 1;
  600. x = digit(str, pos, 2);
  601. y = digit(str, pos, 2);
  602. ZF_LOGI("file at (%d, %d)", x, y);
  603. }
  604. ZF_LOGD("IMAGE (%d lines)", image_size);
  605. if (UsePos) {
  606. send_image(fd, x, y);
  607. } else {
  608. send_image(fd);
  609. };
  610. } break;
  611. case 'G': {
  612. x = digit(str, pos, 2);
  613. y = digit(str, pos, 2);
  614. char buffer[20]; // row ; column H
  615. int slen;
  616. ZF_LOGD("GOTO (%d,%d)", x, y);
  617. slen = snprintf(buffer, sizeof(buffer), "\x1b[%d;%dH", y, x);
  618. if (slen >= (int)sizeof(buffer)) {
  619. ZF_LOGE("snprintf %d > size %d", slen, (int)sizeof(buffer));
  620. buffer[0] = 0;
  621. }
  622. write(fd, buffer, strlen(buffer));
  623. } break;
  624. case 'R': {
  625. i = digit(str, pos);
  626. if ((i > 0) && (i < 10)) {
  627. ZF_LOGI("RENDER %d", i);
  628. current_render.effect = i;
  629. } else {
  630. current_render.effect = 0;
  631. }
  632. } break;
  633. case 'S': {
  634. i = digit(str, pos);
  635. if ((i > 0) && (i < 10)) {
  636. ZF_LOGI("SPEED %d", i);
  637. current_render.speed = i;
  638. } else {
  639. current_render.speed = 0;
  640. }
  641. } break;
  642. case 'P': {
  643. i = digit(str, pos);
  644. if ((i > 0) && (i < 10)) {
  645. ZF_LOGI("PAWS %d", i);
  646. // sleep(i);
  647. if (!render_overlimit) {
  648. sleep(i);
  649. };
  650. }
  651. } break;
  652. }
  653. }
  654. /**
  655. * render_effect( fd, ch )
  656. *
  657. * Displays the given character with whatever
  658. * rendering effect is currently active.
  659. * (If any).
  660. */
  661. void render_effect(int fd, char ch) {
  662. int effect = current_render.effect;
  663. int l;
  664. char space = ' ';
  665. char bs = '\b';
  666. termchar tc;
  667. tc = console_char(&console, ch);
  668. if (tc.in_ansi) {
  669. // We are inside ANSI command, so
  670. write(fd, &ch, 1);
  671. return;
  672. }
  673. switch (effect) {
  674. case 1:
  675. // CHAR + SPC + BS
  676. render_sleep();
  677. write(fd, &ch, 1);
  678. render_sleep();
  679. write(fd, &space, 1);
  680. render_sleep();
  681. render_sleep();
  682. write(fd, &bs, 1);
  683. break;
  684. case 2:
  685. // CHAR + 8 spaces + 8 BS
  686. // This might be too much.
  687. #define MOVE 4
  688. render_sleep();
  689. write(fd, &ch, 1);
  690. for (l = 0; l < MOVE; l++) {
  691. render_sleep();
  692. write(fd, &space, 1);
  693. }
  694. for (l = 0; l < MOVE; l++) {
  695. render_sleep();
  696. write(fd, &bs, 1);
  697. }
  698. break;
  699. case 0:
  700. default:
  701. // NORMAL
  702. render_sleep();
  703. write(fd, &ch, 1);
  704. break;
  705. }
  706. }
  707. /**
  708. * render( fd, string_out )
  709. *
  710. * Render an entire string.
  711. * Handles TRIGGER.
  712. * Renders with effects.
  713. */
  714. void render(int fd, std::string &string_out) {
  715. // reset_render();
  716. time_t start = time(NULL);
  717. size_t pos = 0;
  718. int elapsed;
  719. size_t tpos;
  720. while ((tpos = string_out.find(TRIGGER, pos)) != std::string::npos) {
  721. while (pos != tpos) {
  722. elapsed = time(NULL) - start;
  723. if (elapsed > SLEEP_LIMIT) {
  724. render_overlimit = 1;
  725. current_render.speed = 0;
  726. }
  727. render_effect(fd, string_out[pos]);
  728. pos++;
  729. }
  730. pos += strlen(TRIGGER);
  731. process_trigger(fd, string_out, pos);
  732. }
  733. while (pos < string_out.size()) {
  734. elapsed = time(NULL) - start;
  735. if (elapsed > SLEEP_LIMIT) {
  736. render_overlimit = 1;
  737. current_render.speed = 0;
  738. }
  739. render_effect(fd, string_out[pos]);
  740. pos++;
  741. }
  742. }