PageRenderTime 35ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/console.c

https://gitlab.com/fzwoch/fodquake
C | 739 lines | 565 code | 153 blank | 21 comment | 114 complexity | 19145a08b8763caf2be34023e4049c84 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. Copyright (C) 2010-2013 Mark Olsen
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #include <stdlib.h>
  16. #include <string.h>
  17. /* Fixme: Include less. */
  18. #include "quakedef.h"
  19. #include "strl.h"
  20. #include "utils.h"
  21. #include "console.h"
  22. static qboolean con_parsecolors_callback(cvar_t *, char *);
  23. static cvar_t con_notifylines = { "con_notifylines", "4" };
  24. static cvar_t con_notifytime = { "con_notifytime", "3" };
  25. static cvar_t con_parsecolors = { "con_parsecolors", "1", 0, con_parsecolors_callback };
  26. static unsigned char *conbuf;
  27. static unsigned int contail;
  28. static unsigned int consize;
  29. static unsigned int partiallinestart;
  30. static unsigned int *lines;
  31. static unsigned short *linestartcolours;
  32. static unsigned int maxlines; /* Must be a power of 2 */
  33. static unsigned int firstline;
  34. static unsigned int lastline;
  35. static unsigned int displayline;
  36. static unsigned int textcolumns;
  37. static char *scrollupmarker;
  38. static unsigned int editlinepos;
  39. static char *stitchbuffer; /* A buffer which contains a linear representation of the line that cross the end of the console buffer, if any */
  40. unsigned int stitchbufferlength;
  41. static const float con_cursorspeed = 4;
  42. static unsigned int suppressed;
  43. #define MAXNOTIFYLINES 16
  44. static unsigned long long notifytimes[MAXNOTIFYLINES];
  45. static unsigned int notifystart;
  46. /* Ugly :( */
  47. #define MAXCMDLINE 256
  48. extern char key_lines[32][MAXCMDLINE];
  49. extern int edit_line;
  50. extern int key_linepos;
  51. static void Con_CopyToBuffer(const void *buf, unsigned int size)
  52. {
  53. if (contail + size <= consize)
  54. {
  55. memcpy(conbuf + contail, buf, size);
  56. contail += size;
  57. if (contail == consize)
  58. contail = 0;
  59. }
  60. else
  61. {
  62. memcpy(conbuf + contail, buf, consize - contail);
  63. memcpy(conbuf, buf + (consize - contail), size - (consize - contail));
  64. contail = size - (consize - contail);
  65. }
  66. }
  67. static unsigned int Con_BufferStringLength(unsigned int offset)
  68. {
  69. unsigned int i;
  70. unsigned int len;
  71. i = offset;
  72. while(i < consize && conbuf[i] != 0)
  73. {
  74. i++;
  75. }
  76. len = i - offset;
  77. if (i == consize)
  78. {
  79. i = 0;
  80. while(i < offset && conbuf[i] != 0)
  81. {
  82. i++;
  83. }
  84. len += i;
  85. }
  86. return len;
  87. }
  88. static unsigned int Con_BufferColouredStringLength(unsigned int offset)
  89. {
  90. unsigned int len;
  91. len = Con_BufferStringLength(offset);
  92. if (offset + len > consize)
  93. {
  94. if (stitchbuffer)
  95. return Colored_String_Length(stitchbuffer + strlen(stitchbuffer) - len);
  96. return 0;
  97. }
  98. else
  99. {
  100. return Colored_String_Length(conbuf + offset);
  101. }
  102. }
  103. static unsigned int Con_BufferColouredStringLengthOffset(unsigned int offset, unsigned int maxlen, unsigned short *lastcolour)
  104. {
  105. unsigned int len;
  106. len = Con_BufferStringLength(offset);
  107. if (offset + len > consize)
  108. {
  109. if (stitchbuffer)
  110. return Colored_String_Offset(stitchbuffer + strlen(stitchbuffer) - len, maxlen, lastcolour);
  111. return len;
  112. }
  113. else
  114. {
  115. return Colored_String_Offset(conbuf + offset, maxlen, lastcolour);
  116. }
  117. }
  118. static unsigned int Con_BufferFindLinebreak(unsigned int offset, unsigned int max, unsigned short *lastcolour)
  119. {
  120. unsigned int i;
  121. if (con_parsecolors.value)
  122. {
  123. max = Con_BufferColouredStringLength(offset);
  124. if (max <= textcolumns)
  125. return Con_BufferStringLength(offset);
  126. i = Con_BufferColouredStringLengthOffset(offset, textcolumns, lastcolour);
  127. }
  128. else
  129. {
  130. if (max <= textcolumns)
  131. return max;
  132. i = textcolumns;
  133. *lastcolour = 0x0fff;
  134. }
  135. while(i > 0 && conbuf[(offset + i) % consize] != ' ' && conbuf[(offset + i) % consize] != (' '|0x80))
  136. i--;
  137. if (i == 0)
  138. return textcolumns;
  139. while(conbuf[(offset + i) % consize] == ' ' || conbuf[(offset + i) % consize] == (' '|0x80))
  140. i++;
  141. return i;
  142. }
  143. static int Con_ExpandMaxLines()
  144. {
  145. unsigned int *newlines;
  146. unsigned short *newlinestartcolours;
  147. unsigned int i;
  148. unsigned int j;
  149. newlines = malloc(maxlines*2*sizeof(*lines));
  150. if (newlines)
  151. {
  152. newlinestartcolours = malloc(maxlines*2*sizeof(*linestartcolours));
  153. if (newlinestartcolours)
  154. {
  155. i = 0;
  156. j = firstline;
  157. while (j != ((lastline + 1) % maxlines))
  158. {
  159. newlines[i] = lines[j];
  160. newlinestartcolours[i] = linestartcolours[j];
  161. i++;
  162. j++;
  163. j %= maxlines;
  164. }
  165. displayline = (displayline - firstline) % maxlines;
  166. lastline = (lastline - firstline) % maxlines;
  167. firstline = 0;
  168. free(lines);
  169. free(linestartcolours);
  170. lines = newlines;
  171. linestartcolours = newlinestartcolours;
  172. maxlines *= 2;
  173. return 1;
  174. }
  175. free(newlines);
  176. }
  177. return 0;
  178. }
  179. static void Con_LayoutLine(unsigned int offset)
  180. {
  181. unsigned int i;
  182. unsigned int j;
  183. unsigned short linestartcolour;
  184. unsigned short lastcolour;
  185. linestartcolour = 0x0fff;
  186. i = Con_BufferStringLength(offset);
  187. do
  188. {
  189. j = Con_BufferFindLinebreak(offset, i, &lastcolour);
  190. if ((lastline+2)%maxlines == firstline)
  191. {
  192. if (!Con_ExpandMaxLines())
  193. {
  194. firstline++;
  195. firstline = firstline % maxlines;
  196. }
  197. }
  198. if (displayline == lastline)
  199. {
  200. displayline++;
  201. displayline %= maxlines;
  202. }
  203. lastline++;
  204. lastline %= maxlines;
  205. lines[lastline] = offset;
  206. linestartcolours[lastline] = linestartcolour;
  207. notifytimes[notifystart] = Sys_IntTime();
  208. notifystart++;
  209. notifystart %= MAXNOTIFYLINES;
  210. offset += j;
  211. offset %= consize;
  212. i -= j;
  213. linestartcolour = lastcolour;
  214. } while(i);
  215. }
  216. static void Con_Relayout()
  217. {
  218. unsigned int i;
  219. if (firstline != ((lastline + 1) % maxlines))
  220. {
  221. i = lines[firstline];
  222. firstline = 0;
  223. lastline = maxlines - 1;
  224. displayline = lastline;
  225. while(i != contail)
  226. {
  227. Con_LayoutLine(i);
  228. i += Con_BufferStringLength(i) + 1;
  229. i %= consize;
  230. }
  231. }
  232. }
  233. static void Con_Clear()
  234. {
  235. contail = 0;
  236. partiallinestart = 0;
  237. firstline = 0;
  238. lastline = maxlines - 1;
  239. displayline = lastline;
  240. }
  241. void Con_Init(void)
  242. {
  243. consize = 1024*256;
  244. conbuf = malloc(consize);
  245. if (conbuf)
  246. {
  247. lines = malloc(sizeof(*lines)*512);
  248. if (lines)
  249. {
  250. linestartcolours = malloc(sizeof(*linestartcolours)*512);
  251. if (lines)
  252. {
  253. memset(lines, 0, sizeof(*lines)*512);
  254. memset(linestartcolours, 0, sizeof(*linestartcolours)*512);
  255. maxlines = 512;
  256. lastline = maxlines - 1;
  257. displayline = lastline;
  258. textcolumns = 65536;
  259. }
  260. }
  261. }
  262. }
  263. void Con_Shutdown(void)
  264. {
  265. free(conbuf);
  266. free(lines);
  267. free(scrollupmarker);
  268. conbuf = 0;
  269. lines = 0;
  270. scrollupmarker = 0;
  271. }
  272. void Con_CvarInit(void)
  273. {
  274. Cvar_SetCurrentGroup(CVAR_GROUP_CONSOLE);
  275. Cvar_Register(&con_notifylines);
  276. Cvar_Register(&con_notifytime);
  277. Cvar_Register(&con_parsecolors);
  278. Cvar_ResetCurrentGroup();
  279. Cmd_AddCommand("clear", Con_Clear);
  280. }
  281. static qboolean con_parsecolors_callback(cvar_t *cvar, char *value)
  282. {
  283. cvar->value = atof(value);
  284. Con_Relayout();
  285. return false;
  286. }
  287. void Con_CheckResize(unsigned int pixelwidth)
  288. {
  289. unsigned int newtextcolumns;
  290. unsigned int i;
  291. newtextcolumns = pixelwidth / 8;
  292. if (newtextcolumns > 2)
  293. newtextcolumns -= 2;
  294. else
  295. newtextcolumns = 1;
  296. if (newtextcolumns != textcolumns)
  297. {
  298. textcolumns = newtextcolumns;
  299. free(scrollupmarker);
  300. if (textcolumns)
  301. {
  302. scrollupmarker = malloc(textcolumns + 1);
  303. for(i=0;i<textcolumns;i++)
  304. scrollupmarker[i] = i%4==0?'^':' ';
  305. scrollupmarker[i] = 0;
  306. }
  307. else
  308. scrollupmarker = 0;
  309. Con_Relayout();
  310. }
  311. }
  312. static void Con_DrawTextLines(unsigned int y, unsigned int maxlinestodraw, unsigned int lastlinetodraw)
  313. {
  314. unsigned int i;
  315. unsigned int j;
  316. unsigned int nextline;
  317. unsigned int linelength;
  318. if (firstline == ((lastline + 1) % maxlines))
  319. return;
  320. if (maxlinestodraw == 0)
  321. return;
  322. if (!con_parsecolors.value)
  323. Draw_BeginTextRendering();
  324. y += maxlinestodraw * 8;
  325. j = lastlinetodraw;
  326. if (firstline > lastlinetodraw)
  327. j += maxlines;
  328. if (firstline + maxlinestodraw - 1 <= j)
  329. {
  330. i = j - maxlinestodraw + 1;
  331. }
  332. else
  333. {
  334. i = firstline;
  335. maxlinestodraw = j - firstline + 1;
  336. }
  337. i %= maxlines;
  338. y -= maxlinestodraw * 8;
  339. while(i != ((lastline + 1) % maxlines) && maxlinestodraw)
  340. {
  341. if (maxlinestodraw == 1 && i != lastline)
  342. {
  343. Draw_String(8, y, scrollupmarker);
  344. break;
  345. }
  346. nextline = (i + 1) % maxlines;
  347. linelength = Con_BufferStringLength(lines[i]);
  348. if (nextline != ((lastline + 1) % maxlines))
  349. {
  350. if (lines[nextline] < lines[i])
  351. j = consize - lines[i] + lines[nextline];
  352. else
  353. j = lines[nextline] - lines[i];
  354. if (j < linelength)
  355. linelength = j;
  356. }
  357. if (lines[i] + linelength > consize)
  358. {
  359. if (stitchbuffer)
  360. {
  361. if (con_parsecolors.value)
  362. Draw_ColoredString_Length(8, y, stitchbuffer, 0, linelength, linestartcolours[i]);
  363. else
  364. Draw_String_Length(8, y, stitchbuffer, linelength);
  365. }
  366. }
  367. else
  368. {
  369. if (con_parsecolors.value)
  370. Draw_ColoredString_Length(8, y, conbuf + lines[i], 0, linelength, linestartcolours[i]);
  371. else
  372. Draw_String_Length(8, y, conbuf + lines[i], linelength);
  373. }
  374. y += 8;
  375. i = nextline;
  376. maxlinestodraw--;
  377. }
  378. if (!con_parsecolors.value)
  379. Draw_EndTextRendering();
  380. }
  381. void Con_DrawConsole(int pixellines)
  382. {
  383. unsigned int linelength;
  384. unsigned char tmpline[2048];
  385. Draw_ConsoleBackground(pixellines);
  386. Con_DrawTextLines((pixellines+2)%8, (pixellines - 22) / 8, displayline);
  387. if (key_linepos && key_linepos - 1 < editlinepos)
  388. editlinepos = key_linepos - 1;
  389. else if (key_linepos >= editlinepos + textcolumns)
  390. editlinepos = key_linepos - textcolumns + 1;
  391. linelength = strlen(key_lines[edit_line] + editlinepos);
  392. if (linelength > textcolumns)
  393. linelength = textcolumns;
  394. if (linelength > sizeof(tmpline) - 1)
  395. linelength = sizeof(tmpline) - 1;
  396. strlcpy(tmpline, key_lines[edit_line] + editlinepos, linelength + 1);
  397. if ((int) (Sys_DoubleTime() * con_cursorspeed) & 1)
  398. {
  399. if (tmpline[key_linepos - editlinepos] == 0)
  400. linelength++;
  401. tmpline[key_linepos - editlinepos] = 11;
  402. }
  403. Draw_String_Length(8, pixellines - 22, tmpline, linelength);
  404. }
  405. unsigned int Con_DrawNotify(void)
  406. {
  407. unsigned int maxnotifylines;
  408. unsigned int notifytime;
  409. unsigned long long now;
  410. unsigned int i;
  411. now = Sys_IntTime();
  412. notifytime = ((double)con_notifytime.value)*1000000;
  413. maxnotifylines = con_notifylines.value;
  414. if (maxnotifylines > MAXNOTIFYLINES)
  415. maxnotifylines = MAXNOTIFYLINES;
  416. i = (notifystart + (MAXNOTIFYLINES - maxnotifylines)) % MAXNOTIFYLINES;
  417. while(maxnotifylines && notifytimes[i] + notifytime < now)
  418. {
  419. i++;
  420. i %= MAXNOTIFYLINES;
  421. maxnotifylines--;
  422. }
  423. Con_DrawTextLines(0, maxnotifylines, lastline);
  424. return maxnotifylines;
  425. }
  426. void Con_ClearNotify(void)
  427. {
  428. memset(notifytimes, 0, sizeof(notifytimes));
  429. }
  430. void Con_Suppress(void)
  431. {
  432. suppressed = 1;
  433. }
  434. void Con_Unsuppress(void)
  435. {
  436. suppressed = 0;
  437. }
  438. unsigned int Con_GetColumns()
  439. {
  440. return textcolumns;
  441. }
  442. static void Con_ClearBufferSpace(unsigned int size)
  443. {
  444. while(firstline != ((lastline + 1) % maxlines) && ((lines[firstline] >= contail && lines[firstline] < contail + size) || (contail + size >= consize && lines[firstline] < (((contail + size) % consize)))))
  445. {
  446. if (displayline == firstline)
  447. {
  448. displayline++;
  449. displayline %= maxlines;
  450. }
  451. lines[firstline++] = 0;
  452. firstline %= maxlines;
  453. }
  454. }
  455. void Con_Print(const char *txt)
  456. {
  457. unsigned int i;
  458. unsigned int j;
  459. unsigned int linebegin;
  460. const char *newline;
  461. char *tmp;
  462. char colourbuf[256];
  463. void *freethis;
  464. if (suppressed)
  465. return;
  466. if (lines == 0)
  467. {
  468. printf("%s\n", txt);
  469. return;
  470. }
  471. if (strlen(txt) >= consize)
  472. return;
  473. freethis = 0;
  474. if (*txt == 1 || *txt == 2)
  475. {
  476. /* OMGWTFBBQ */
  477. txt++;
  478. if (strlen(txt) + 1 < sizeof(colourbuf))
  479. {
  480. strcpy(colourbuf, txt);
  481. tmp = colourbuf;
  482. }
  483. else
  484. {
  485. freethis = malloc(strlen(txt) + 1);
  486. if (freethis == 0)
  487. {
  488. Con_Print("Out of memory\n");
  489. return;
  490. }
  491. strcpy(freethis, txt);
  492. tmp = freethis;
  493. }
  494. txt = tmp;
  495. tmp--;
  496. while(*++tmp)
  497. {
  498. if (*tmp != '\n')
  499. *tmp |= 128;
  500. }
  501. }
  502. while((newline = strchr(txt, '\n')))
  503. {
  504. if ((tmp = strchr(txt, '\r')) && tmp < newline)
  505. txt = tmp + 1;
  506. i = newline - txt + 1;
  507. if (i + partiallinestart < consize)
  508. {
  509. Con_ClearBufferSpace(i);
  510. if (partiallinestart)
  511. linebegin = partiallinestart;
  512. else
  513. linebegin = contail;
  514. Con_CopyToBuffer(txt, i);
  515. if (contail == 0)
  516. j = consize - 1;
  517. else
  518. j = contail - 1;
  519. conbuf[j] = 0;
  520. if (contail < linebegin)
  521. {
  522. j = consize - linebegin + contail;
  523. if (j > stitchbufferlength)
  524. {
  525. free(stitchbuffer);
  526. stitchbuffer = malloc(j);
  527. }
  528. if (stitchbuffer)
  529. {
  530. memcpy(stitchbuffer, conbuf + linebegin, consize - linebegin);
  531. memcpy(stitchbuffer + (consize - linebegin), conbuf, contail);
  532. }
  533. }
  534. Con_LayoutLine(linebegin);
  535. }
  536. partiallinestart = 0;
  537. txt += i;
  538. }
  539. if (*txt)
  540. {
  541. i = strlen(txt);
  542. if (i + partiallinestart < consize)
  543. {
  544. if (!partiallinestart)
  545. partiallinestart = contail;
  546. Con_ClearBufferSpace(i + 1);
  547. Con_CopyToBuffer(txt, i);
  548. conbuf[contail] = 0;
  549. }
  550. }
  551. free(freethis);
  552. }
  553. void Con_ScrollUp(unsigned int numlines)
  554. {
  555. int distance;
  556. distance = displayline - firstline;
  557. if (distance < 0)
  558. distance += maxlines;
  559. if (numlines > distance)
  560. numlines = distance;
  561. displayline -= numlines;
  562. displayline %= maxlines;
  563. }
  564. void Con_ScrollDown(unsigned int numlines)
  565. {
  566. int distance;
  567. distance = lastline - displayline;
  568. if (distance < 0)
  569. distance += maxlines;
  570. if (numlines > distance)
  571. numlines = distance;
  572. displayline += numlines;
  573. displayline %= maxlines;
  574. }
  575. void Con_Home(void)
  576. {
  577. displayline = firstline;
  578. }
  579. void Con_End(void)
  580. {
  581. displayline = lastline;
  582. }