consoleui.cpp
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:6k
源码类别:

外挂编程

开发平台:

Windows_Unix

  1. #ifdef __APPLE__
  2. /* MacOS X has a kernel bug: poll() blocks when used on
  3.  * stdin, even when timeout is set to 0! So we use
  4.  * select() instead.
  5.  */
  6. #define USE_SELECT
  7. #endif
  8. #include <stdio.h>
  9. #include <readline/readline.h>
  10. #include <readline/history.h>
  11. #include <stdlib.h>
  12. #ifdef USE_SELECT
  13. #include <sys/select.h>
  14. #else
  15. #include <sys/poll.h>
  16. #endif
  17. #include <unistd.h>
  18. #include <string.h>
  19. #include <assert.h>
  20. #include "consoleui.h"
  21. // Hack: work around some memory corruption issues in readline
  22. // by setting this variable to NULL before a rl_redisplay().
  23. // It is unclear now to solve this problem correctly.
  24. extern char *rl_display_prompt;
  25. static pthread_mutex_t singletonLock = PTHREAD_MUTEX_INITIALIZER;
  26. /**
  27.  * This class delegates callback functions back to the ConsoleUI instance.
  28.  */
  29. class ConsoleUICallbacks {
  30. public:
  31. static void *threadMain(void *arg) {
  32. return ConsoleUI::getInstance()->threadMain(arg);
  33. }
  34. static void lineRead(char *line) {
  35. ConsoleUI::getInstance()->lineRead(line);
  36. }
  37. };
  38. ConsoleUI *ConsoleUI::instance = NULL;
  39. ConsoleUI::ConsoleUI() {
  40. thread = 0;
  41. pthread_mutex_init(&inputLock, NULL);
  42. pthread_mutex_init(&outputLock, NULL);
  43. pthread_cond_init(&outputCond, NULL);
  44. }
  45. ConsoleUI::~ConsoleUI() {
  46. stop();
  47. while (!input.empty()) {
  48. free(input.front());
  49. input.pop();
  50. }
  51. while (!output.empty()) {
  52. free(output.front());
  53. output.pop();
  54. }
  55. pthread_mutex_destroy(&inputLock);
  56. pthread_mutex_destroy(&outputLock);
  57. pthread_cond_destroy(&outputCond);
  58. }
  59. void
  60. ConsoleUI::lineRead(char *line) {
  61. if (line == NULL) {
  62. pthread_mutex_lock(&inputLock);
  63. input.push(strdup(""));
  64. pthread_mutex_unlock(&inputLock);
  65. quit = true;
  66. } else if (*line != '') {
  67. pthread_mutex_lock(&inputLock);
  68. input.push(line);
  69. pthread_mutex_unlock(&inputLock);
  70. add_history(line);
  71. }
  72. lineProcessed = true;
  73. }
  74. bool
  75. ConsoleUI::canRead() {
  76. #ifdef USE_SELECT
  77. fd_set f;
  78. struct timeval t;
  79. t.tv_sec = 0;
  80. t.tv_usec = 0;
  81. FD_ZERO(&f);
  82. FD_SET(STDIN_FILENO, &f);
  83. return select(STDIN_FILENO + 1, &f, NULL, NULL, &t) == 1;
  84. #else
  85. struct pollfd ufds;
  86. ufds.fd = STDIN_FILENO;
  87. ufds.events = POLLIN;
  88. return poll(&ufds, 1, 0) == 1;
  89. #endif
  90. }
  91. void *
  92. ConsoleUI::threadMain(void *arg) {
  93. rl_callback_handler_install("", ConsoleUICallbacks::lineRead);
  94. while (!quit) {
  95. while (canRead()) {
  96. lineProcessed = false;
  97. rl_callback_read_char();
  98. if (lineProcessed && rl_prompt != NULL && rl_prompt[0] != '') {
  99. // If a line has been processed, reset the prompt
  100. // so we don't see it again after an Enter.
  101. rl_set_prompt("");
  102. rl_display_prompt = NULL;
  103. rl_redisplay();
  104. }
  105. }
  106. pthread_mutex_lock(&outputLock);
  107. if (!output.empty()) {
  108. processOutput();
  109. pthread_cond_broadcast(&outputCond);
  110. }
  111. pthread_mutex_unlock(&outputLock);
  112. usleep(10000);
  113. }
  114. rl_callback_handler_remove();
  115. return NULL;
  116. }
  117. void
  118. ConsoleUI::processOutput() {
  119. FILE *stream = (rl_outstream == NULL) ? stdout : rl_outstream;
  120. int point, mark;
  121. char *buffer = NULL;
  122. char *prompt = NULL;
  123. // Save readline's state.
  124. point = rl_point;
  125. mark = rl_mark;
  126. if (rl_line_buffer != NULL) {
  127. buffer = strdup(rl_line_buffer);
  128. }
  129. if (rl_prompt != NULL) {
  130. prompt = strdup(rl_prompt);
  131. }
  132. rl_replace_line("", 0);
  133. rl_point = rl_mark = 0;
  134. rl_set_prompt("");
  135. rl_display_prompt = NULL;
  136. rl_redisplay();
  137. // If there was already a prompt (previous printed message didn't
  138. // contain a newline), then print it to the screen and clear the
  139. // prompt.
  140. if (prompt != NULL) {
  141. if (prompt[0] != '') {
  142. fputs(prompt, stream);
  143. }
  144. free(prompt);
  145. prompt = NULL;
  146. }
  147. // Make sure the prompt color will be set to default.
  148. prompt = strdup("e[0m");
  149. while (!output.empty()) {
  150. char *msg = output.front();
  151. size_t len;
  152. len = strlen(msg);
  153. if (output.size() == 1 && len > 0 && msg[len - 1] != 'n') {
  154. // This is the last message and it doesn't end with a newline.
  155. // Use this message as prompt.
  156. char buf[1024 * 32];
  157. // Reset the prompt color.
  158. snprintf(buf, sizeof(buf) - 1, "%se[0m", msg);
  159. rl_set_prompt(buf);
  160. // Prevent prompt from being set to an empty string.
  161. if (prompt != NULL) {
  162. free(prompt);
  163. prompt = NULL;
  164. }
  165. } else {
  166. fputs(msg, stream);
  167. }
  168. free(msg);
  169. output.pop();
  170. }
  171. // Restore readline's state.
  172. if (prompt != NULL) {
  173. rl_set_prompt(prompt);
  174. free(prompt);
  175. }
  176. if (buffer != NULL) {
  177. rl_insert_text(buffer);
  178. free(buffer);
  179. }
  180. rl_point = point;
  181. rl_mark = mark;
  182. rl_on_new_line();
  183. rl_display_prompt = NULL;
  184. rl_redisplay();
  185. fflush(stream);
  186. }
  187. ConsoleUI *
  188. ConsoleUI::getInstance() {
  189. pthread_mutex_lock(&singletonLock);
  190. if (instance == NULL) {
  191. instance = new ConsoleUI();
  192. atexit(cleanup);
  193. }
  194. pthread_mutex_unlock(&singletonLock);
  195. return instance;
  196. }
  197. void
  198. ConsoleUI::start() {
  199. quit = false;
  200. rl_initialize();
  201. pthread_create(&thread, NULL, ConsoleUICallbacks::threadMain, NULL);
  202. }
  203. void
  204. ConsoleUI::stop() {
  205. if (thread != 0) {
  206. waitUntilPrinted();
  207. quit = true;
  208. pthread_join(thread, NULL);
  209. thread = 0;
  210. }
  211. }
  212. void
  213. ConsoleUI::print(const char *msg) {
  214. assert(msg != NULL);
  215. pthread_mutex_lock(&outputLock);
  216. output.push(strdup(msg));
  217. pthread_cond_broadcast(&outputCond);
  218. pthread_mutex_unlock(&outputLock);
  219. }
  220. void
  221. ConsoleUI::waitUntilPrinted() {
  222. pthread_mutex_lock(&outputLock);
  223. while (!output.empty()) {
  224. pthread_cond_wait(&outputCond, &outputLock);
  225. }
  226. pthread_mutex_unlock(&outputLock);
  227. }
  228. char *
  229. ConsoleUI::getInput() {
  230. char *result = NULL;
  231. pthread_mutex_lock(&inputLock);
  232. if (!input.empty()) {
  233. result = input.front();
  234. input.pop();
  235. }
  236. pthread_mutex_unlock(&inputLock);
  237. return result;
  238. }
  239. void
  240. ConsoleUI::cleanup() {
  241. if (instance != NULL) {
  242. delete instance;
  243. instance = NULL;
  244. }
  245. }