Drop -Werror
[pmc.git] / screen.c
blobd6a684f212a29fcd9d3a25a88a426ee3e3c07e9b
1 #include <ncurses.h>
2 #include <malloc.h>
3 #include <string.h>
4 #include <cbuf.h>
5 #include <color.h>
6 #include <screen.h>
7 #include <ansi.h>
9 #include <list.h>
11 #include <debug.h>
13 #define MS_MAGIC 0x131948dd
15 #define HIST_SIZE 30
17 struct hist_node {
18 list_head();
19 char *hist;
22 struct mcl_screen {
23 int magic;
24 int pad;
25 int xsize, ysize;
26 WINDOW *background;
27 WINDOW *output;
28 WINDOW *bar_top;
29 WINDOW *bar_bot;
30 WINDOW *input;
31 char *buffer;
32 char *ibuf;
33 char *scrollback;
34 struct hist_node *hist_list;
35 struct hist_node *hist_curr;
36 int hp;
37 int mhp;
38 int en;
39 int men;
40 int mv;
41 int mmv;
45 void
46 add_hist(struct hist_node **head, const char *val)
48 char *vd;
49 struct hist_node *c, *f = NULL;
50 int len;
52 if (val[0] == 0 || val[0] == '\n')
53 return;
55 list_for(head, c, len) {
56 if (len >= HIST_SIZE) {
57 list_remove(head, c);
58 free(c->hist);
59 free(c);
60 break;
63 if (!strcmp(c->hist, val)) {
64 list_remove(head, c);
65 f = c;
66 break;
70 if (f) {
71 list_prepend(head, f);
72 return;
75 vd = strdup(val);
76 if (!vd)
77 return;
78 len = strlen(vd);
79 if (vd[len] == '\n')
80 vd[len] = 0;
81 f = malloc(sizeof(*f));
82 if (!f) {
83 free(vd);
84 return;
87 f->hist = vd;
88 list_prepend(head, f);
92 int
93 pmc_buffer(void *s, const char *data, size_t len)
95 struct mcl_screen *scr = (struct mcl_screen *)s;
96 if (scr->magic != MS_MAGIC)
97 return -1;
99 cb_append(scr->buffer, data, len);
100 return 0;
104 char *
105 pmc_get_scrollback(void *s)
107 struct mcl_screen *scr = (struct mcl_screen *)s;
108 if (scr->magic != MS_MAGIC)
109 return NULL;
111 return scr->scrollback;
115 /* Zaps the contents of a bar */
116 void
117 pmc_write_bar(void *sp, int bar, const char *str)
119 struct mcl_screen *scr = (struct mcl_screen *)sp;
120 WINDOW *w;
121 char *s;
122 int x, wx, wy, len;
124 if (scr->magic != MS_MAGIC)
125 return;
127 /* only go until first newline */
128 s = strchr(str, '\n');
129 if (!s) {
130 len = strlen(str);
131 } else {
132 len = s - str;
135 //debug_print("Writing %d bytes to window\n", len);
136 /* XXX TODO internal function below here */
138 if (bar == BAR_TOP)
139 w = scr->bar_top;
140 else
141 w = scr->bar_bot;
143 /* zero out the rest */
145 getmaxyx(w, wy, wx);
146 mvwaddnstr(w, 0, 0, str, len);
148 for (x = len; x < wx; x++)
149 mvwaddch(w, 0, x, ' ');
151 wnoutrefresh(w);
156 pmc_copyout(void *s, char *circbuf)
158 struct mcl_screen *scr = (struct mcl_screen *)s;
159 if (scr->magic != MS_MAGIC)
160 return -1;
162 cb_append(circbuf, scr->ibuf, cb_length(scr->ibuf));
163 cb_reset(scr->ibuf);
164 return 0;
168 static int
169 check_triggers(struct mcl_screen *scr, char *line)
171 char *c;
173 //debug_print("Line: %s", line);
175 if (!strcmp(line,"+=--------------------------------------------------------------------------=+\n")) {
176 for (c = line - 3; c >= scr->scrollback; c--) {
177 if (*c == '|')
178 break;
179 if (*c == '\n') {
180 while (*c == '\n' || *c == '\r' || *c == ' ' || *c == '\t')
181 c++;
183 pmc_write_bar(scr, BAR_TOP, c);
184 return 0;
189 return 0;
194 pmc_update(void *s)
196 struct mcl_screen *scr = (struct mcl_screen *)s;
197 size_t len, olen, slen;
198 int x, newline = 1;
199 int y, data = 0;
200 char *line;
202 if (scr->magic != MS_MAGIC)
203 return -1;
205 while ((len = cb_length(scr->buffer))) {
207 newline = 0;
209 for (x = 0; x < len; x++) {
210 if (scr->buffer[x] == '\n') {
211 newline = 1;
212 break;
216 if (!newline)
217 break;
219 olen = x + 1;
220 slen = ansi_strip(scr->scrollback, scr->buffer, olen);
221 line = &scr->scrollback[cb_length(scr->scrollback) - slen];
222 check_triggers(scr, line);
223 olen = ansi_waddnstr(scr->output, scr->buffer, olen);
224 cb_discard(scr->buffer, olen);
225 ++data;
228 /* add trailing non-line */
229 len = cb_length(scr->buffer);
230 if (len) {
231 ++data;
232 olen = ansi_waddnstr(scr->output, scr->buffer, len);
233 cb_discard(scr->buffer, olen);
236 if (data)
237 wnoutrefresh(scr->output);
238 wnoutrefresh(scr->bar_bot);
239 wnoutrefresh(scr->bar_top);
241 /* Hack to keep the cursor in the input box */
242 getyx(scr->input, y, x);
243 mvwaddch(scr->input, y, x,' ');
244 wmove(scr->input, y, x);
245 wnoutrefresh(scr->input);
247 return 0;
251 void
252 pmc_resize(void *s)
254 struct mcl_screen *scr = (struct mcl_screen *)s;
255 int x;
257 if (scr->magic != MS_MAGIC)
258 return;
260 endwin();
261 refresh();
263 getmaxyx(scr->background, scr->ysize, scr->xsize);
265 wresize(scr->bar_top, 1, scr->xsize);
266 mvwin(scr->bar_top, 0, 0);
267 for (x = 0; x < scr->xsize; x++)
268 mvwaddch(scr->bar_top, 0, x, ' ');
270 wresize(scr->output, scr->ysize - 3, scr->xsize);
271 mvwin(scr->output, 1, 0);
273 wresize(scr->bar_bot, 1, scr->xsize);
274 mvwin(scr->bar_bot, scr->ysize - 2, 0);
275 for (x = 0; x < scr->xsize; x++)
276 mvwaddch(scr->bar_bot, 0, x, ' ');
278 wresize(scr->input, 1, scr->xsize);
279 mvwin(scr->input, scr->ysize - 1, 0);
281 refresh();
285 void *
286 pmc_init(void)
288 struct mcl_screen *s;
289 attr_t attr;
290 short pair;
291 int x;
293 s = malloc(sizeof(*s));
294 memset(s, 0, sizeof(*s));
296 s->magic = MS_MAGIC;
298 s->background = initscr();
299 clearok(s->background, FALSE);
301 start_color();
302 pmc_init_color();
303 noecho();
305 getmaxyx(s->background, s->ysize, s->xsize);
306 s->bar_top = newwin(1, s->xsize, 0, 0);
307 idlok(s->bar_top, TRUE);
309 wattr_get(s->bar_top, &attr, &pair, NULL);
310 attr &= ~(A_UNDERLINE | A_BLINK);
311 pair = BG(C_BLUE)|C_WHITE;
312 wattr_set(s->bar_top, attr, pair, NULL);
314 for (x = 0; x < s->xsize; x++)
315 mvwaddch(s->bar_top, 0, x, ' ');
317 s->output = newwin(s->ysize - 3, s->xsize, 1, 0);
318 scrollok(s->output, TRUE);
319 idlok(s->output, TRUE);
321 s->bar_bot = newwin(1, s->xsize, s->ysize-2, 0);
323 wattr_get(s->bar_bot, &attr, &pair, NULL);
325 attr &= ~(A_UNDERLINE | A_BLINK);
326 pair = BG(C_BLUE)|C_WHITE;
327 wattr_set(s->bar_bot, attr, pair, NULL);
329 for (x = 0; x < s->xsize; x++)
330 mvwaddch(s->bar_bot, 0, x, ' ');
332 s->input = newwin(1, s->xsize, s->ysize-1, 0);
333 leaveok(s->input, FALSE);
334 keypad(s->input, TRUE);
336 s->buffer = malloc(4096);
337 s->buffer = cb_init(s->buffer, 4096, NULL);
338 s->scrollback = malloc(16384);
339 s->scrollback = cb_init(s->scrollback, 16384, NULL);
341 s->ibuf = malloc(1024);
342 s->ibuf = cb_init(s->ibuf, 1024, NULL);
344 refresh();
346 return s;
350 static void
351 _erase_word(char *buff)
353 int x, y;
355 x = cb_length(buff);
356 y = x;
357 x--;
359 while (x >= 0 && (buff[x] == ' ' || buff[x] == '\t'))
360 x--;
361 while (x >= 0 && (buff[x] != ' ' && buff[x] != '\t'))
362 x--;
364 if (x < 0)
365 cb_reset(buff);
366 else
367 cb_delete(buff, &buff[x+1], y-x);
371 /* This prevents a full screen refresh */
372 static void
373 zap_line(WINDOW *w, int line)
375 wmove(w, line, 0);
376 wclrtoeol(w);
377 wmove(w, line, 0);
381 /* Wait for keyboard input */
383 pmc_listen(void *s)
385 int keystroke;
386 struct mcl_screen *scr = (struct mcl_screen *)s;
387 char key = '\n';
388 int x,y, ret = 0;
390 if (scr->magic != MS_MAGIC)
391 return -1;
393 keystroke = wgetch(scr->input);
394 key = (char)(keystroke & 0x0ff);
396 switch(keystroke) {
397 case KEY_ENTER:
398 case '\n':
399 /* reset this */
400 scr->hist_curr = NULL;
402 /* ^/ = local command; don't send */
403 zap_line(scr->input, 0);
405 /* add or move history to LRU */
406 add_hist(&scr->hist_list, scr->ibuf);
408 cb_append(scr->ibuf, &key, 1);
409 if (*scr->buffer != '/')
410 cb_append(scr->buffer, &key, 1);
411 ret = 1;
412 break;
414 case '\x10':
415 case KEY_UP:
416 if (scr->hist_curr) {
417 scr->hist_curr = (void *)(le(scr->hist_curr)->le_next);
418 } else {
419 if (scr->hist_list) {
420 scr->hist_curr = scr->hist_list;
421 } else {
422 break;
426 cb_reset(scr->ibuf);
427 cb_strcat(scr->ibuf, scr->hist_curr->hist);
428 zap_line(scr->input, 0);
429 mvwaddstr(scr->input, 0, 0, scr->ibuf);
431 break;
433 case '\x0e':
434 case KEY_DOWN:
435 if (scr->hist_curr) {
436 scr->hist_curr = (void *)(le(scr->hist_curr)->le_prev);
437 } else {
438 if (scr->hist_list) {
439 scr->hist_curr = (void *)(le(scr->hist_list)->le_prev);
440 } else {
441 break;
445 cb_reset(scr->ibuf);
446 cb_strcat(scr->ibuf, scr->hist_curr->hist);
447 zap_line(scr->input, 0);
448 mvwaddstr(scr->input, 0, 0, scr->ibuf);
450 break;
452 case KEY_BACKSPACE:
453 case '\x7f':
454 cb_backspace(scr->ibuf, 1);
455 /* optimization- draw a space over previous char */
456 getyx(scr->input, y, x);
457 mvwaddch(scr->input, y, x-1, ' ');
458 wmove(scr->input, y, x-1);
459 break;
461 case '\x17':
462 /* Erase to last space */
463 _erase_word(scr->ibuf);
464 zap_line(scr->input, 0);
465 mvwaddstr(scr->input, 0, 0, scr->ibuf);
466 break;
468 case '\x15':
469 cb_reset(scr->ibuf);
470 zap_line(scr->input, 0);
471 break;
473 default:
474 key = (char) keystroke;
475 if (key == '\x3') {
476 return 2;
478 cb_append(scr->ibuf, &key, 1);
479 waddch(scr->input, key);
481 wnoutrefresh(scr->input);
483 return ret;