2 * This file is part of the libpayload project.
4 * Copyright (C) 2007 Uwe Hermann <uwe@hermann-uwe.de>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * This is a tiny implementation of the (n)curses library intended to be
32 * used in embedded/firmware/BIOS code where no libc or operating system
33 * environment is available and code size is very important.
36 * - Small object code.
38 * - Doesn't require a libc (no glibc/uclibc/dietlibc/klibc/newlib).
39 * - Works without any other external libraries or header files.
40 * - Works without an underlying operating system.
41 * - Doesn't use files, signals, syscalls, ttys, library calls, etc.
42 * - Doesn't do any dynamic memory allocation (no malloc() and friends).
43 * - All data structures are statically allocated.
44 * - Supports standard VGA console (80x25) and serial port console.
45 * - This includes character output and keyboard input over serial.
46 * - Supports beep() through a minimal PC speaker driver.
49 * - Only implements a small subset of the (n)curses functions.
50 * - Only implements very few sanity checks (for smaller code).
51 * - Thus: Don't do obviously stupid things in your code.
52 * - Doesn't implement the 'form', 'panel', and 'menu' extentions.
53 * - Only implements C bindings (no C++, Ada95, or others).
54 * - Doesn't include wide character support.
59 #undef _XOPEN_SOURCE_EXTENDED
60 #define _XOPEN_SOURCE_EXTENDED 1
64 /* Statically allocate all structures (no malloc())! */
65 static WINDOW window_list[MAX_WINDOWS];
66 static int window_count = 1;
69 static struct ldat ldat_list[3];
70 static int ldat_count = 0;
72 /* One item bigger than SCREEN_X to reverse place for a NUL byte. */
73 static NCURSES_CH_T linebuf_list[SCREEN_Y * MAX_WINDOWS][SCREEN_X + 1];
74 static int linebuf_count = 0;
77 int COLORS; /* Currently unused? */
91 // FIXME: Ugly (and insecure!) hack!
92 char sprintf_tmp[1024];
95 int curses_flags = (F_ENABLE_CONSOLE | F_ENABLE_SERIAL);
97 /* Return bit mask for clearing color pair number if given ch has color */
98 #define COLOR_MASK(ch) (~(attr_t)((ch) & A_COLOR ? A_COLOR : 0))
100 /* Compute a rendition of the given char correct for the current context. */
101 static inline NCURSES_CH_T render_char(WINDOW *win, NCURSES_CH_T ch)
107 /* Make render_char() visible while still allowing us to inline it below. */
108 NCURSES_CH_T _nc_render(WINDOW *win, NCURSES_CH_T ch)
110 return render_char(win, ch);
114 * Implementations of most functions marked 'implemented' in tinycurses.h:
117 // int baudrate(void) {}
120 /* TODO: Flash the screen if beeping fails? */
121 speaker_tone(1760, 500); /* 1760 == note A6 */
124 // bool can_change_color(void) {}
125 int cbreak(void) { /* TODO */ return 0; }
126 /* D */ int clearok(WINDOW *win, bool flag) { win->_clear = flag; return OK; }
127 // int color_content(short color, short *r, short *g, short *b) {}
128 // int curs_set(int) {}
129 // int def_prog_mode(void) {}
130 // int def_shell_mode(void) {}
131 // int delay_output(int) {}
132 // void delscreen(SCREEN *) {}
133 int delwin(WINDOW *win)
135 /* TODO: Don't try to delete stdscr. */
136 /* TODO: Don't delete parent windows before subwindows. */
138 // if (win->_flags & _SUBWIN)
139 // touchwin(win->_parent);
140 // else if (curscr != 0)
143 // return _nc_freewin(win);
146 WINDOW *derwin(WINDOW *orig, int num_lines, int num_columns, int begy, int begx)
152 /* Make sure window fits inside the original one. */
153 if (begy < 0 || begx < 0 || orig == 0 || num_lines < 0
157 if (begy + num_lines > orig->_maxy + 1
158 || begx + num_columns > orig->_maxx + 1)
162 num_lines = orig->_maxy + 1 - begy;
164 if (num_columns == 0)
165 num_columns = orig->_maxx + 1 - begx;
167 if (orig->_flags & _ISPAD)
171 //// if ((win = _nc_makenew(num_lines, num_columns, orig->_begy + begy,
172 //// orig->_begx + begx, flags)) == 0)
177 WINDOW_ATTRS(win) = WINDOW_ATTRS(orig);
178 win->_nc_bkgd = orig->_nc_bkgd;
180 for (i = 0; i < num_lines; i++)
181 win->_line[i].text = &orig->_line[begy++].text[begx];
187 int doupdate(void) { /* TODO */ return(*(int *)0); }
188 // WINDOW * dupwin (WINDOW *) {}
189 /* D */ int echo(void) { SP->_echo = TRUE; return OK; }
197 // _nc_screen_wrap();
198 // _nc_mvcur_wrap(); /* wrap up cursor addressing */
199 // return reset_shell_mode();
202 // char erasechar (void) {}
203 // void filter (void) {}
204 // int flash(void) {}
205 // int flushinp (void) {}
206 // WINDOW *getwin (FILE *) {}
208 bool has_colors (void) { /* TODO */ return(*(bool *)0); }
209 // bool has_ic (void) {}
210 // bool has_il (void) {}
211 // void idcok (WINDOW *, bool) {}
212 // int idlok (WINDOW *, bool) {}
213 void immedok(WINDOW *win, bool flag) { win->_immed = flag; }
214 /** Note: Must _not_ be called twice! */
215 WINDOW *initscr(void)
219 // newterm(name, stdout, stdin);
222 if (curses_flags & F_ENABLE_CONSOLE) {
223 /* Clear the screen and kill the cursor. */
225 vga_cursor_enable(0);
230 stdscr = newwin(SCREEN_Y, SCREEN_X + 1, 0, 0);
231 // TODO: curscr, newscr?
233 for (y = 0; y < stdscr->_maxy; y++) {
234 for (x = 0; x < stdscr->_maxx; x++) {
235 stdscr->_line[y].text[x].chars[0] = ' ';
236 stdscr->_line[y].text[x].attr = A_NORMAL;
243 // int intrflush (WINDOW *,bool) {}
244 /* D */ bool isendwin(void) { return ((SP == NULL) ? FALSE : SP->_endwin); }
245 // bool is_linetouched (WINDOW *,int) {}
246 // bool is_wintouched (WINDOW *) {}
247 // NCURSES_CONST char * keyname (int) {}
248 int keypad (WINDOW *win, bool flag) { /* TODO */ return 0; }
249 // char killchar (void) {}
250 /* D */ int leaveok(WINDOW *win, bool flag) { win->_leaveok = flag; return OK; }
251 // char *longname (void) {}
252 // int meta (WINDOW *,bool) {}
253 // int mvcur (int,int,int,int) {}
254 // int mvderwin (WINDOW *, int, int) {}
255 int mvprintw(int y, int x, const char *fmt, ...)
260 if (move(y, x) == ERR)
264 code = vwprintw(stdscr, fmt, argp);
269 // int mvscanw (int,int, NCURSES_CONST char *,...) {}
270 // int mvwin (WINDOW *,int,int) {}
271 int mvwprintw(WINDOW *win, int y, int x, const char *fmt, ...)
276 if (wmove(win, y, x) == ERR)
280 code = vwprintw(win, fmt, argp);
285 // int mvwscanw (WINDOW *,int,int, NCURSES_CONST char *,...) {}
286 // int napms (int) {}
287 // WINDOW *newpad (int,int) {}
288 // SCREEN *newterm (NCURSES_CONST char *,FILE *,FILE *) {}
289 WINDOW *newwin(int num_lines, int num_columns, int begy, int begx)
293 /* Use next statically allocated window. */
294 // TODO: Error handling.
296 WINDOW *win = &window_list[window_count++];
298 // bool is_pad = (flags & _ISPAD);
304 win->_maxy = num_lines - 1;
305 win->_maxx = num_columns - 1;
308 // win->_yoffset = SP->_topstolen;
310 win->_line = &ldat_list[ldat_count++];
312 /* FIXME: Is this right? Should the window attributes be normal? */
313 win->_color = PAIR_NUMBER(0);
314 win->_attrs = A_NORMAL;
316 for (i = 0; i < num_lines; i++)
318 (NCURSES_CH_T *)&linebuf_list[linebuf_count++];
322 /* D */ int nl(void) { SP->_nl = TRUE; return OK; }
323 int nocbreak(void) { /* TODO */ return(*(int *)0); }
325 /* D */ int noecho(void) { SP->_echo = FALSE; return OK; }
326 /* D */ int nonl(void) { SP->_nl = FALSE; return OK; }
327 // void noqiflush (void) {}
328 // int noraw (void) {}
329 // int notimeout (WINDOW *,bool) {}
330 // int overlay (const WINDOW*,WINDOW *) {}
331 // int overwrite (const WINDOW*,WINDOW *) {}
332 // int pair_content (short,short*,short*) {}
333 // int pechochar (WINDOW *, const chtype) {}
334 // int pnoutrefresh (WINDOW*,int,int,int,int,int,int) {}
335 // int prefresh (WINDOW *,int,int,int,int,int,int) {}
336 int printw(const char *fmt, ...)
342 code = vwprintw(stdscr, fmt, argp);
347 // int putwin (WINDOW *, FILE *) {}
348 // void qiflush (void) {}
350 // int resetty (void) {}
351 // int reset_prog_mode (void) {}
352 // int reset_shell_mode (void) {}
353 // int ripoffline (int, int (*)(WINDOW *, int)) {}
354 // int savetty (void) {}
355 // int scanw (NCURSES_CONST char *,...) {}
356 // int scr_dump (const char *) {}
357 // int scr_init (const char *) {}
358 /* D */ int scrollok(WINDOW *win, bool flag) { win->_scroll = flag; return OK; }
359 // int scr_restore (const char *) {}
360 // int scr_set (const char *) {}
361 // SCREEN *set_term (SCREEN *) {}
362 // int slk_attroff (const chtype) {}
363 // int slk_attron (const chtype) {}
364 // int slk_attrset (const chtype) {}
365 // attr_t slk_attr (void) {}
366 // int slk_attr_set (const attr_t,short,void*) {}
367 // int slk_clear (void) {}
368 // int slk_color (short) {}
369 // int slk_init (int) {}
370 /* D */ char *slk_label(int n)
373 // if (SP == NULL || SP->_slk == NULL || n < 1 || n > SP->_slk->labcnt)
375 return SP->_slk->ent[n - 1].ent_text;
377 // int slk_noutrefresh (void) {}
378 // int slk_refresh (void) {}
379 // int slk_restore (void) {}
380 // int slk_set (int,const char *,int) {}
381 // int slk_touch (void) {}
383 // WINDOW *subpad (WINDOW *, int, int, int, int) {}
384 WINDOW *subwin(WINDOW *w, int l, int c, int y, int x)
386 return derwin(w, l, c, y - w->_begy, x - w->_begx);
388 // int syncok (WINDOW *, bool) {}
389 // chtype termattrs (void) {}
390 // char *termname (void) {}
391 // int typeahead (int) {}
392 int ungetch(int ch) { /* TODO */ return ERR; }
393 // void use_env (bool) {}
394 // int vidattr (chtype) {}
395 // int vidputs (chtype, int (*)(int)) {}
396 int vwprintw(WINDOW *win, const char *fmt, va_list argp)
398 vsprintf((char *)&sprintf_tmp, fmt, argp);
400 /* TODO: Error handling? */
401 return waddstr(win, (char *)&sprintf_tmp);
403 // int vwscanw (WINDOW *, NCURSES_CONST char *,va_list) {}
404 // int waddch (WINDOW *, const chtype) {}
405 int waddch(WINDOW *win, const chtype ch)
409 // SetChar2(wch, ch);
411 win->_line[win->_cury].text[win->_curx].chars[0] = ch;
413 /* Use the window attributes - perhaps we also pull attributes from
414 the ch itself, I don't know */
416 win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win);
417 win->_curx++; // FIXME
419 // if (win && (waddch_nosync(win, wch) != ERR)) {
420 // _nc_synchook(win);
426 // int waddchnstr (WINDOW *,const chtype *,int) {}
427 int waddnstr(WINDOW *win, const char *astr, int n)
430 const char *str = astr;
438 while ((n-- > 0) && (*str != '\0')) {
439 // while (*str != '\0') {
440 win->_line[win->_cury].text[win->_curx].chars[0] = *str++;
441 win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win)
443 win->_curx++; // FIXME
446 // SetChar(ch, UChar(*str++), A_NORMAL);
447 // if (_nc_waddch_nosync(win, ch) == ERR) {
454 int wattr_on(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
457 win->_color = PAIR_NUMBER(at);
458 // toggle_attr_on(WINDOW_ATTRS(win), at);
461 int wattr_off(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
465 // toggle_attr_off(WINDOW_ATTRS(win), at);
468 // int wbkgd (WINDOW *, chtype) {}
469 void wbkgdset(WINDOW *win, chtype ch) { /* TODO */ }
470 // int wborder (WINDOW *,chtype,chtype,chtype,chtype,chtype,chtype,chtype,chtype) {}
471 // int wchgat (WINDOW *, int, attr_t, short, const void *) {}
472 /* D */ int wclear(WINDOW *win)
474 if (werase(win) == ERR)
479 // int wclrtobot (WINDOW *) {}
480 int wclrtoeol(WINDOW *win) { /* TODO */ return(*(int *)0); }
481 int wcolor_set(WINDOW *win, short color_pair_number, void *opts)
483 if (!opts && (color_pair_number >= 0)
484 && (color_pair_number < COLOR_PAIRS)) {
485 SET_WINDOW_PAIR(win, color_pair_number);
486 if_EXT_COLORS(win->_color = color_pair_number);
491 // void wcursyncup (WINDOW *) {}
492 // int wdelch (WINDOW *) {}
493 // int wechochar (WINDOW *, const chtype) {}
494 int werase(WINDOW *win)
497 for (y = 0; y < win->_maxy; y++) {
498 for (x = 0; x < win->_maxx; x++) {
499 win->_line[y].text[x].chars[0] = ' ';
500 win->_line[y].text[x].attr = WINDOW_ATTRS(win);
506 // int wgetnstr (WINDOW *,char *,int) {}
507 int whline(WINDOW *win, chtype ch, int n)
509 NCURSES_SIZE_T start, end;
510 struct ldat *line = &(win->_line[win->_cury]);
515 if (end > win->_maxx)
518 CHANGED_RANGE(line, start, end);
522 //// SetChar2(wch, ACS_HLINE);
524 //// SetChar2(wch, ch);
526 wch.chars[0] = ((ch) & (chtype)A_CHARTEXT);
527 wch.attr = ((ch) & (chtype)A_ATTRIBUTES);
528 wch = _nc_render(win, wch);
530 while (end >= start) {
531 line->text[end] = wch;
535 //// _nc_synchook(win);
539 /* D */ chtype winch(WINDOW *win)
542 // return (CharOf(win->_line[win->_cury].text[win->_curx]) |
543 // AttrOf(win->_line[win->_cury].text[win->_curx]));
546 // int winchnstr (WINDOW *, chtype *, int) {}
547 // int winnstr (WINDOW *, char *, int) {}
548 // int winsch (WINDOW *, chtype) {}
549 // int winsdelln (WINDOW *,int) {}
550 // int winsnstr (WINDOW *, const char *,int) {}
551 /* D */ int wmove(WINDOW *win, int y, int x)
553 if (!LEGALYX(win, y, x))
555 win->_curx = (NCURSES_SIZE_T) x;
556 win->_cury = (NCURSES_SIZE_T) y;
557 win->_flags &= ~_WRAPPED;
558 win->_flags |= _HASMOVED;
563 int wnoutrefresh(WINDOW *win)
568 for (y = 0; y < win->_maxy; y++) {
569 for (x = 0; x < win->_maxx; x++) {
570 if (curses_flags & F_ENABLE_SERIAL)
571 serial_putchar(win->_line[y].text[x].chars[0]);
573 if (curses_flags & F_ENABLE_CONSOLE) {
574 attr_t attr = win->_line[y].text[x].attr;
576 ((int)color_pairs[PAIR_NUMBER(attr)]) << 8;
578 /* Handle some of the attributes. */
583 if (attr & A_REVERSE) {
584 unsigned char tmp = (c >> 8) & 0xf;
585 c = (c >> 4) & 0xf00;
589 c |= win->_line[y].text[x].chars[0];
598 int wprintw(WINDOW *win, const char *fmt, ...)
604 code = vwprintw(win, fmt, argp);
609 // int wredrawln (WINDOW *,int,int) {}
610 int wrefresh(WINDOW *win)
613 return wnoutrefresh(win);
619 curscr->_clear = TRUE;
620 // code = doupdate();
621 } else if ((code = wnoutrefresh(win)) == OK) {
623 newscr->_clear = TRUE;
624 // code = doupdate();
626 * Reset the clearok() flag in case it was set for the special
627 * case in hardscroll.c (if we don't reset it here, we'll get 2
628 * refreshes because the flag is copied from stdscr to newscr).
629 * Resetting the flag shouldn't do any harm, anyway.
636 // int wscanw (WINDOW *, NCURSES_CONST char *,...) {}
637 int wscrl(WINDOW *win, int n)
643 // _nc_scroll_window(win, n, win->_regtop, win->_regbottom, win->_nc_bkgd);
644 // _nc_synchook(win);
648 int wsetscrreg(WINDOW *win, int top, int bottom)
650 if (top >= 0 && top <= win->_maxy && bottom >= 0 &&
651 bottom <= win->_maxy && bottom > top) {
652 win->_regtop = (NCURSES_SIZE_T) top;
653 win->_regbottom = (NCURSES_SIZE_T) bottom;
658 // void wsyncdown (WINDOW *) {}
659 // void wsyncup (WINDOW *) {}
660 // void wtimeout (WINDOW *,int) {}
661 /* D */ int wtouchln(WINDOW *win, int y, int n, int changed)
665 // if ((n < 0) || (y < 0) || (y > win->_maxy))
668 for (i = y; i < y + n; i++) {
671 win->_line[i].firstchar = changed ? 0 : _NOCHANGE;
672 win->_line[i].lastchar = changed ? win->_maxx : _NOCHANGE;
676 // int wvline (WINDOW *,chtype,int) {}
677 // int tigetflag (NCURSES_CONST char *) {}
678 // int tigetnum (NCURSES_CONST char *) {}
679 // char *tigetstr (NCURSES_CONST char *) {}
680 // int putp (const char *) {}
681 // #if NCURSES_TPARM_VARARGS
682 // char *tparm (NCURSES_CONST char *, ...) {}
684 // char *tparm (NCURSES_CONST char *, long,long,long,long,long,long,long,long,long) {}
685 // char *tparm_varargs (NCURSES_CONST char *, ...) {}