! Fixed the root Makefile
[lightOS.git] / lib / curses / curses.c
blob553c1f6ba947aca33a2a9806fe438f664ddefba5
1 /*
2 lightOS libunix
3 Copyright (C) 2007-2009 Jörg Pfähler
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdio.h>
20 #include <assert.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <curses.h>
24 #include <libOS/LIBUNIX_glue.h>
25 #include <libOS/LIBC_glue.h>
27 // TODO
28 #include <libserver/console.h>
29 #include <libOS/lightOS/internal/curses.h>
31 // TODO: curses mode can be paused through endwin() and started again through a refresh
33 #define MAKE_COLOR_PAIR(foreground, background) (((background) << 4) | (foreground))
35 // Define the SCREEN modes
36 #define SCREEN_MODE_ECHO 0x01
37 #define SCREEN_MODE_CBREAK 0x02
38 #define SCREEN_MODE_KEYPAD 0x04
39 #define SCREEN_MODE_NEWLINE_TRANSLATION 0x08
41 // Define the WINDOW modes
42 #define WINDOW_MODE_NO_DELAY 0x01
44 struct _LIBUNIX_WINDOW
46 size_t x;
47 size_t y;
48 size_t width;
49 size_t height;
50 size_t cursor;
51 size_t color;
52 size_t mode;
53 _LIBOS_WINDOW osdep;
54 struct _LIBUNIX_WINDOW *parent;
55 struct _LIBUNIX_SCREEN *screen;
58 struct _LIBUNIX_SCREEN
60 size_t width;
61 size_t height;
62 FILE *infile;
63 FILE *outfile;
64 WINDOW *curscr;
65 WINDOW *stdscr;
66 size_t mode;
69 // Global variables
70 int COLS = 0;
71 int LINES = 0;
72 WINDOW *curscr = NULL;
73 WINDOW *stdscr = NULL;
75 // File-local variables
76 static SCREEN *_LIBUNIX_cur_screen = NULL;
80 // File-local functions
83 static int _LIBUNIX_move_cursor(int x, int y)
85 assert(_LIBUNIX_cur_screen != NULL);
87 // Set the 'hardware' cursor
88 _LIBSERVER_CONSOLE_SET_CURSOR(_LIBUNIX_cur_screen->outfile, x, y);
89 return OK;
94 // Initialization functions
97 SCREEN *newterm(char *type,
98 FILE *outfile,
99 FILE *infile)
101 // NOTE: type is ignored
102 assert(outfile != NULL);
103 assert(infile != NULL);
105 // Allocate memory for the SCREEN
106 SCREEN *Screen = malloc(sizeof(SCREEN));
107 if (Screen == NULL)
108 return NULL;
110 // Initialize the SCREEN
111 Screen->width = 80;
112 Screen->height = 25;
113 Screen->infile = infile;
114 Screen->outfile = outfile;
115 Screen->mode = SCREEN_MODE_ECHO | SCREEN_MODE_NEWLINE_TRANSLATION;
117 // Allocate memory for stdscr
118 Screen->stdscr = malloc(sizeof(WINDOW));
119 if (Screen->stdscr == NULL)
120 goto error_stdscr;
121 if (_LIBOS_init_window(&Screen->stdscr->osdep,
122 Screen->width,
123 Screen->height,
124 FALSE) == FALSE)
125 goto error_stdscr_init;
127 // Initialize the stdscr
128 Screen->stdscr->x = 0;
129 Screen->stdscr->y = 0;
130 Screen->stdscr->width = Screen->width;
131 Screen->stdscr->height = Screen->height;
132 Screen->stdscr->cursor = 0;
133 Screen->stdscr->color = MAKE_COLOR_PAIR(COLOR_WHITE, COLOR_BLACK);
134 Screen->stdscr->mode = 0;
135 Screen->stdscr->parent = NULL;
136 Screen->stdscr->screen = Screen;
138 // Allocate memory for curscr
139 Screen->curscr = malloc(sizeof(WINDOW));
140 if (Screen->curscr == NULL)goto error_curscr;
141 if (_LIBOS_init_window(&Screen->curscr->osdep,
142 Screen->width,
143 Screen->height,
144 TRUE) == FALSE)
145 goto error_curscr_init;
147 // Initialize the curscr
148 Screen->curscr->x = 0;
149 Screen->curscr->y = 0;
150 Screen->curscr->width = Screen->width;
151 Screen->curscr->height = Screen->height;
152 Screen->curscr->cursor = 0;
153 Screen->curscr->color = MAKE_COLOR_PAIR(COLOR_WHITE, COLOR_BLACK);
154 Screen->curscr->mode = 0;
155 Screen->curscr->parent = NULL;
156 Screen->curscr->screen = Screen;
158 // Disable 'hardware' echoing
159 // TODO: libOS
160 _LIBSERVER_CONSOLE_HW_ECHO(Screen->outfile, false);
162 // Clear the screen
163 // TODO: libOS
164 _LIBSERVER_CONSOLE_CLEAR(Screen->outfile);
166 // Set current SCREEN, stdscr & curscr
167 if (_LIBUNIX_cur_screen == NULL)
168 set_term(Screen);
170 return Screen;
172 error_curscr_init:
173 free(Screen->curscr);
174 error_curscr:
175 _LIBOS_deinit_window(&Screen->stdscr->osdep);
176 error_stdscr_init:
177 free(Screen->stdscr);
178 error_stdscr:
179 free(Screen);
180 return NULL;
183 SCREEN *set_term(SCREEN *newterm)
185 curscr = newterm->curscr;
186 stdscr = newterm->stdscr;
187 COLS = newterm->width;
188 LINES = newterm->height;
190 SCREEN *tmp = _LIBUNIX_cur_screen;
191 _LIBUNIX_cur_screen = newterm;
192 return tmp;
195 WINDOW *initscr()
197 if (newterm(NULL, stdout, stdin) == NULL)
199 // TODO: What should we do here?
200 _LIBOS_WARNING("libunix", "failed");
201 abort();
203 return stdscr;
206 void _LIBUNIX_getyx(const WINDOW *win, int *y, int *x)
208 *y = (win->cursor / 2) / win->width;
209 *x = (win->cursor / 2) % win->width;
212 void _LIBUNIX_getbegyx(const WINDOW *win, int *y, int *x)
214 *y = win->y;
215 *x = win->x;
218 void _LIBUNIX_getmaxyx(const WINDOW *win, int *y, int *x)
220 *y = win->height;
221 *x = win->width;
226 // Control the modes
229 // TODO: libOS?
230 int echo()
232 assert(_LIBUNIX_cur_screen != NULL);
233 _LIBUNIX_cur_screen->mode |= SCREEN_MODE_ECHO;
234 return OK;
237 int noecho()
239 assert(_LIBUNIX_cur_screen != NULL);
240 _LIBUNIX_cur_screen->mode &= ~SCREEN_MODE_ECHO;
241 return OK;
244 int cbreak()
246 assert(_LIBUNIX_cur_screen != NULL);
247 _LIBUNIX_cur_screen->mode |= SCREEN_MODE_CBREAK;
248 fflush(_LIBUNIX_cur_screen->outfile);
249 fprintf(_LIBUNIX_cur_screen->outfile, "\x1B]B");
250 fflush(_LIBUNIX_cur_screen->outfile);
251 return OK;
254 int nocbreak()
256 assert(_LIBUNIX_cur_screen != NULL);
257 _LIBUNIX_cur_screen->mode &= ~SCREEN_MODE_CBREAK;
258 fflush(_LIBUNIX_cur_screen->outfile);
259 fprintf(_LIBUNIX_cur_screen->outfile, "\x1B[B");
260 fflush(_LIBUNIX_cur_screen->outfile);
261 return OK;
264 int raw()
266 _LIBOS_WARNING("libunix", "not implemented");
267 // TODO
270 int noraw()
272 _LIBOS_WARNING("libunix", "not implemented");
273 // TODO
276 int nl()
278 assert(_LIBUNIX_cur_screen != NULL);
279 _LIBUNIX_cur_screen->mode |= SCREEN_MODE_NEWLINE_TRANSLATION;
280 return OK;
283 int nonl()
285 assert(_LIBUNIX_cur_screen != NULL);
286 _LIBUNIX_cur_screen->mode &= ~SCREEN_MODE_NEWLINE_TRANSLATION;
287 return OK;
290 int keypad(WINDOW *win, bool bf)
292 assert(win != NULL);
293 if (bf == true)win->mode |= SCREEN_MODE_KEYPAD;
294 else win->mode &= ~SCREEN_MODE_KEYPAD;
295 return OK;
298 int nodelay(WINDOW *win, bool bf)
300 assert(win != NULL);
302 if (bf != FALSE)
303 win->mode |= WINDOW_MODE_NO_DELAY;
304 else
305 win->mode &= ~WINDOW_MODE_NO_DELAY;
307 return OK;
312 // Control the cursor modes
315 int curs_set(int visibility)
317 assert(_LIBUNIX_cur_screen != NULL);
319 fflush(_LIBUNIX_cur_screen->outfile);
320 const char *string = NULL;
321 if (visibility == 0)
322 string = "\x1B[V0";
323 else
324 string = "\x1B[V1";
325 fprintf(_LIBUNIX_cur_screen->outfile, string);
326 fflush(_LIBUNIX_cur_screen->outfile);
327 return OK;
332 // Window management
335 WINDOW *newwin(int nlines, int ncols, int begin_y, int begin_x)
337 assert(_LIBUNIX_cur_screen != NULL);
339 if (ncols == 0)
340 ncols = COLS - begin_x;
341 if (nlines == 0)
342 nlines = LINES - begin_y;
344 // Allocate memory for the window
345 WINDOW *window = malloc(sizeof(WINDOW));
346 if (window == NULL)
347 return NULL;
348 if (_LIBOS_init_window(&window->osdep, nlines, ncols, FALSE) == FALSE)
350 free(window);
351 return NULL;
354 // Initialize the window
355 window->x = begin_x;
356 window->y = begin_y;
357 window->width = ncols;
358 window->height = nlines;
359 window->cursor = 0;
360 window->color = MAKE_COLOR_PAIR(COLOR_WHITE, COLOR_BLACK);
361 window->mode = 0;
362 window->parent = stdscr;
363 window->screen = _LIBUNIX_cur_screen;
365 return window;
368 int endwin()
370 assert(_LIBUNIX_cur_screen != NULL);
372 // Restore the cursor
373 if (curs_set(1) == ERR)return ERR;
375 // Enable 'hardware' echoing
376 // TODO: libOS
377 fflush(_LIBUNIX_cur_screen->outfile);
378 fprintf(_LIBUNIX_cur_screen->outfile, "\x1B[E");
379 fflush(_LIBUNIX_cur_screen->outfile);
381 // Clear the screen
382 // TODO: libOS
383 fprintf(_LIBUNIX_cur_screen->outfile, "\x1B[C");
384 fflush(_LIBUNIX_cur_screen->outfile);
386 // Deallocate memory for the SCREEN, curscr & stdscr
387 // TODO: delscreen()
388 // free(_cur_screen->stdscr);
389 // free(_cur_screen->curscr);
390 // free(_cur_screen);
392 // Reset current SCREEN, stdscr & curscr
393 // _cur_screen = NULL;
394 // stdscr = NULL;
395 // curscr = NULL;
396 // COLS = 0;
397 // LINES = 0;
399 return OK;
402 int wclear(WINDOW *win)
404 assert(win != NULL);
406 // Clear the screen
407 win->cursor = 0;
408 memset(_LIBOS_window_data(&win->osdep),
410 win->width * win->height * 2);
412 return OK;
415 int werase(WINDOW *win)
417 return wclear(win);
420 int wmove(WINDOW *win, int y, int x)
422 assert(win != NULL);
423 assert(x < win->width);
424 assert(y < win->height);
426 win->cursor = (win->width * y + x) * 2;
427 return OK;
430 int waddch(WINDOW *win, const chtype ch)
432 assert(win != NULL);
434 // Get a pointer to the memory
435 char *Data = _LIBOS_window_data(&win->osdep);
437 // Write the character to the memory
438 if (ch == '\n')
440 // NOTE: to static terminal size
441 win->cursor -= win->cursor % 160;
442 win->cursor += 160;
444 else
446 Data[win->cursor] = (char)ch;
447 Data[win->cursor + 1] = win->color;
450 // Move the cursor
451 win->cursor += 2;
453 // TODO: replace spaces with the background character (should be \0)
454 // TODO: Attributes
455 // TODO: Wrapping
456 // TODO: Special character processing
457 return OK;
460 int mvwaddch(WINDOW *win, int y, int x, const chtype ch)
462 assert(win != NULL);
464 // Move the cursor
465 if (wmove(win, y, x) != OK)return ERR;
467 // Add the character
468 return waddch(win, ch);
471 int waddstr(WINDOW *win, const char *str)
473 return waddnstr(win, str, -1);
476 int waddnstr(WINDOW *win, const char *str, int n)
478 assert(win != NULL);
480 if (n == -1)n = strlen(str);
482 for (int i = 0;i < n;i++)
484 if (str[i] == '\0')break;
485 waddch(win, str[i]);
488 return OK;
491 int mvwaddstr(WINDOW *win, int y, int x, const char *str)
493 return mvwaddnstr(win, y, x, str, -1);
496 int mvwaddnstr(WINDOW *win, int y, int x, const char *str, int n)
498 assert(win != NULL);
500 // Move the cursor
501 if (wmove(win, y, x) != OK)return ERR;
503 // Add the string
504 return waddnstr(win, str, n);
507 static int var_wprintw(WINDOW *win, const char *fmt, va_list args)
509 va_list argcopy;
510 va_copy(argcopy, args);
511 int result = vsnprintf(0, 0, fmt, argcopy);
512 va_end(argcopy);
513 if (result < 0)return ERR;
514 char *array = malloc(result + 1);
515 result = vsnprintf(array, result + 1, fmt, args);
516 if (result < 0)
518 free(array);
519 return ERR;
521 waddstr(win, array);
522 free(array);
523 return result;
526 int printw(const char *fmt, ...)
528 va_list args;
529 va_start(args, fmt);
530 int result = var_wprintw(stdscr, fmt, args);
531 va_end(args);
532 return result;
535 int wprintw(WINDOW *win, const char *fmt, ...)
537 va_list args;
538 va_start(args, fmt);
539 int result = var_wprintw(win, fmt, args);
540 va_end(args);
541 return result;
544 static int var_mvwprintw(WINDOW *win, int y, int x, const char *fmt, va_list args)
546 va_list argcopy;
547 va_copy(argcopy, args);
548 int result = vsnprintf(0, 0, fmt, argcopy);
549 va_end(argcopy);
550 if (result < 0)return ERR;
551 char *array = malloc(result + 1);
552 result = vsnprintf(array, result + 1, fmt, args);
553 if (result < 0)
555 free(array);
556 return ERR;
558 mvwaddstr(win, y, x, array);
559 free(array);
560 return result;
563 int mvprintw(int y, int x, const char *fmt, ...)
565 va_list args;
566 va_start(args, fmt);
567 int result = var_mvwprintw(stdscr, y, x, fmt, args);
568 va_end(args);
569 return result;
572 int mvwprintw(WINDOW *win, int y, int x, const char *fmt, ...)
574 va_list args;
575 va_start(args, fmt);
576 int result = var_mvwprintw(win, y, x, fmt, args);
577 va_end(args);
578 return result;
585 int wattroff(WINDOW *win, int attrs)
587 assert(win != NULL);
589 if ((attrs & A_REVERSE) != 0)
591 win->color = MAKE_COLOR_PAIR(COLOR_WHITE, COLOR_BLACK);
594 if ((attrs & (~(A_REVERSE))) != 0)
596 _LIBOS_WARNING("libunix", "unimplemented attribute");
597 abort();
600 return OK;
602 int wattron(WINDOW *win, int attrs)
604 assert(win != NULL);
606 if ((attrs & A_REVERSE) != 0)
608 win->color = MAKE_COLOR_PAIR(COLOR_BLACK, COLOR_WHITE);
611 if ((attrs & (~(A_REVERSE))) != 0)
613 _LIBOS_WARNING("libunix", "unimplemented attribute");
614 abort();
617 return OK;
621 int mvwgetch(WINDOW *win, int y, int x)
623 assert(win != NULL);
625 // Move the cursor
626 if (wmove(win, y, x) != OK)return ERR;
628 return wgetch(win);
630 int wgetch(WINDOW *win)
632 assert(win != NULL);
634 // TODO: Is window a Pad?
635 wrefresh(win);
637 // TODO FIXME HACK
638 if ((win->mode & WINDOW_MODE_NO_DELAY) != 0)
639 return ERR;
641 _LIBSERVER_key_t Key;
642 int result;
643 char tmp[10];
644 size_t length = 0;
647 int character = fgetc(win->screen->infile);
648 if (character == EOF)
649 return ERR;
651 tmp[length++] = (char)character;
653 if ((win->mode & SCREEN_MODE_KEYPAD) == SCREEN_MODE_KEYPAD)
655 result = _LIBSERVER_convert_from_ecma48(tmp, length, &Key);
656 assert(result != _LIBSERVER_CONVERT_FAILED);
658 else
660 Key.character = tmp[0];
661 Key.code = _LIBSERVER_KEYCODE_NONE;
662 result = _LIBSERVER_CONVERT_OK;
665 if (result == _LIBSERVER_CONVERT_FAILED)
666 return ERR;
667 } while (result == _LIBSERVER_CONVERT_NEED_INPUT);
669 int retval = Key.character;
670 if (Key.character == L'\0')
671 retval = _LIBOS_KEYCODE_TO_LIBUNIX(Key.code);
673 // Newline translation disabled?
674 if ((win->mode & SCREEN_MODE_NEWLINE_TRANSLATION) == 0 && retval == '\n')
675 retval = KEY_ENTER;
677 // Print the character
678 if ((_LIBUNIX_cur_screen->mode & SCREEN_MODE_ECHO) != 0)
679 if (retval < 256)
680 if (waddch(win, (chtype)retval) == ERR)
681 return ERR;
683 return retval;
687 int wrefresh(WINDOW *win)
689 assert(win != NULL);
691 if (wnoutrefresh(win) == ERR)return ERR;
692 return doupdate();
695 int wnoutrefresh(WINDOW *win)
697 assert(win != NULL);
699 // Copy window data to curscr
700 size_t offsrc = 0;
701 size_t offdest = (win->y * curscr->width + win->x) * 2;
702 size_t cpywidth = win->width;
703 if ((win->width + win->x) > curscr->width)
704 cpywidth = curscr->width - win->x;
705 size_t cpyheight = win->height;
706 if ((win->height + win->y) > curscr->height)
707 cpyheight = curscr->height - win->y;
708 for (size_t i = 0;i < cpyheight;i++)
710 memcpy(_LIBOS_window_data(&curscr->osdep) + offdest,
711 _LIBOS_window_data(&win->osdep) + offsrc,
712 cpywidth * 2);
713 offdest += curscr->width * 2;
714 offsrc += win->width * 2;
717 size_t curx = ((win->cursor / 2) % win->width) + win->x;
718 size_t cury = ((win->cursor / 2) / win->width) + win->y;
719 curscr->cursor = ((cury * curscr->width) + curx) * 2;
721 return OK;
724 int doupdate()
726 _LIBOS_screen_update(&curscr->osdep, _LIBUNIX_cur_screen->outfile);
728 // Set the cursor
729 _LIBUNIX_move_cursor((curscr->cursor / 2) % curscr->width,
730 (curscr->cursor / 2) / curscr->width);
731 return OK;
734 int beep()
736 _LIBOS_WARNING("libunix", "not implemented");
737 abort();
738 return 0;
740 int delwin(WINDOW *win)
742 _LIBOS_WARNING("libunix", "not implemented");
743 abort();
744 return 0;
746 int scrollok(WINDOW *win, bool bf)
748 _LIBOS_WARNING("libunix", "not implemented");
749 abort();
750 return 0;
752 int wscrl(WINDOW *win, int n)
754 _LIBOS_WARNING("libunix", "not implemented");
755 abort();
756 return 0;
758 bool isendwin(void)
760 _LIBOS_WARNING("libunix", "not implemented");
761 //abort();
762 return FALSE;