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' extensions.
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[MAX_WINDOWS][SCREEN_Y];
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 include/curses.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) { /* TODO */ return 0; }
206 // WINDOW *getwin (FILE *) {}
207 bool has_colors (void) { /* TODO */ return(*(bool *)0); }
208 // bool has_ic (void) {}
209 // bool has_il (void) {}
210 // void idcok (WINDOW *, bool) {}
211 // int idlok (WINDOW *, bool) {}
212 void immedok(WINDOW *win, bool flag) { win->_immed = flag; }
213 /** Note: Must _not_ be called twice! */
214 WINDOW *initscr(void)
218 // newterm(name, stdout, stdin);
221 if (curses_flags & F_ENABLE_SERIAL) {
225 if (curses_flags & F_ENABLE_CONSOLE) {
226 /* Clear the screen and kill the cursor */
228 video_console_clear();
229 video_console_cursor_enable(0);
234 stdscr = newwin(SCREEN_Y, SCREEN_X + 1, 0, 0);
235 // TODO: curscr, newscr?
237 for (y = 0; y < stdscr->_maxy; y++) {
238 for (x = 0; x < stdscr->_maxx; x++) {
239 stdscr->_line[y].text[x].chars[0] = ' ';
240 stdscr->_line[y].text[x].attr = A_NORMAL;
246 // int intrflush (WINDOW *,bool) {}
247 /* D */ bool isendwin(void) { return ((SP == NULL) ? FALSE : SP->_endwin); }
248 // bool is_linetouched (WINDOW *,int) {}
249 // bool is_wintouched (WINDOW *) {}
250 // NCURSES_CONST char * keyname (int) {}
251 int keypad (WINDOW *win, bool flag) { /* TODO */ return 0; }
252 // char killchar (void) {}
253 /* D */ int leaveok(WINDOW *win, bool flag) { win->_leaveok = flag; return OK; }
254 // char *longname (void) {}
255 // int meta (WINDOW *,bool) {}
256 // int mvcur (int,int,int,int) {}
257 // int mvderwin (WINDOW *, int, int) {}
258 int mvprintw(int y, int x, const char *fmt, ...)
263 if (move(y, x) == ERR)
267 code = vwprintw(stdscr, fmt, argp);
272 // int mvscanw (int,int, NCURSES_CONST char *,...) {}
273 // int mvwin (WINDOW *,int,int) {}
274 int mvwprintw(WINDOW *win, int y, int x, const char *fmt, ...)
279 if (wmove(win, y, x) == ERR)
283 code = vwprintw(win, fmt, argp);
288 // int mvwscanw (WINDOW *,int,int, NCURSES_CONST char *,...) {}
289 // int napms (int) {}
290 // WINDOW *newpad (int,int) {}
291 // SCREEN *newterm (NCURSES_CONST char *,FILE *,FILE *) {}
292 WINDOW *newwin(int num_lines, int num_columns, int begy, int begx)
296 /* Use next statically allocated window. */
297 // TODO: Error handling.
299 WINDOW *win = &window_list[window_count++];
301 // bool is_pad = (flags & _ISPAD);
307 win->_maxy = num_lines - 1;
308 win->_maxx = num_columns - 1;
311 // win->_yoffset = SP->_topstolen;
313 win->_line = ldat_list[ldat_count++];
315 /* FIXME: Is this right? Should the window attributes be normal? */
316 win->_color = PAIR_NUMBER(0);
317 win->_attrs = A_NORMAL;
319 for (i = 0; i < num_lines; i++)
321 (NCURSES_CH_T *)&linebuf_list[linebuf_count++];
325 /* D */ int nl(void) { SP->_nl = TRUE; return OK; }
326 /* D */ int noecho(void) { SP->_echo = FALSE; return OK; }
327 /* D */ int nonl(void) { SP->_nl = FALSE; return OK; }
328 // void noqiflush (void) {}
329 // int noraw (void) {}
330 /* D */ int notimeout (WINDOW *win, bool f) { win->_notimeout = f; return OK; }
331 // int overlay (const WINDOW*,WINDOW *) {}
332 // int overwrite (const WINDOW*,WINDOW *) {}
333 // int pair_content (short,short*,short*) {}
334 // int pechochar (WINDOW *, const chtype) {}
335 // int pnoutrefresh (WINDOW*,int,int,int,int,int,int) {}
336 // int prefresh (WINDOW *,int,int,int,int,int,int) {}
337 int printw(const char *fmt, ...)
343 code = vwprintw(stdscr, fmt, argp);
348 // int putwin (WINDOW *, FILE *) {}
349 // void qiflush (void) {}
351 // int resetty (void) {}
352 // int reset_prog_mode (void) {}
353 // int reset_shell_mode (void) {}
354 // int ripoffline (int, int (*)(WINDOW *, int)) {}
355 // int savetty (void) {}
356 // int scanw (NCURSES_CONST char *,...) {}
357 // int scr_dump (const char *) {}
358 // int scr_init (const char *) {}
359 /* D */ int scrollok(WINDOW *win, bool flag) { win->_scroll = flag; return OK; }
360 // int scr_restore (const char *) {}
361 // int scr_set (const char *) {}
362 // SCREEN *set_term (SCREEN *) {}
363 // int slk_attroff (const chtype) {}
364 // int slk_attron (const chtype) {}
365 // int slk_attrset (const chtype) {}
366 // attr_t slk_attr (void) {}
367 // int slk_attr_set (const attr_t,short,void*) {}
368 // int slk_clear (void) {}
369 // int slk_color (short) {}
370 // int slk_init (int) {}
371 /* D */ char *slk_label(int n)
374 // if (SP == NULL || SP->_slk == NULL || n < 1 || n > SP->_slk->labcnt)
376 return SP->_slk->ent[n - 1].ent_text;
378 // int slk_noutrefresh (void) {}
379 // int slk_refresh (void) {}
380 // int slk_restore (void) {}
381 // int slk_set (int,const char *,int) {}
382 // int slk_touch (void) {}
384 // WINDOW *subpad (WINDOW *, int, int, int, int) {}
385 WINDOW *subwin(WINDOW *w, int l, int c, int y, int x)
387 return derwin(w, l, c, y - w->_begy, x - w->_begx);
389 // int syncok (WINDOW *, bool) {}
390 // chtype termattrs (void) {}
391 // char *termname (void) {}
392 // int typeahead (int) {}
393 int ungetch(int ch) { /* TODO */ return ERR; }
394 // void use_env (bool) {}
395 // int vidattr (chtype) {}
396 // int vidputs (chtype, int (*)(int)) {}
397 int vwprintw(WINDOW *win, const char *fmt, va_list argp)
399 vsprintf((char *)&sprintf_tmp, fmt, argp);
401 /* TODO: Error handling? */
402 return waddstr(win, (char *)&sprintf_tmp);
404 // int vwscanw (WINDOW *, NCURSES_CONST char *,va_list) {}
405 // int waddch (WINDOW *, const chtype) {}
406 int waddch(WINDOW *win, const chtype ch)
410 // SetChar2(wch, ch);
412 win->_line[win->_cury].text[win->_curx].chars[0] = ch;
414 /* Use the window attributes - perhaps we also pull attributes from
415 the ch itself, I don't know */
417 win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win);
418 win->_curx++; // FIXME
420 // if (win && (waddch_nosync(win, wch) != ERR)) {
421 // _nc_synchook(win);
427 // int waddchnstr (WINDOW *,const chtype *,int) {}
428 int waddnstr(WINDOW *win, const char *astr, int n)
431 const char *str = astr;
439 while ((n-- > 0) && (*str != '\0')) {
440 // while (*str != '\0') {
441 win->_line[win->_cury].text[win->_curx].chars[0] = *str++;
442 win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win)
444 win->_curx++; // FIXME
447 // SetChar(ch, UChar(*str++), A_NORMAL);
448 // if (_nc_waddch_nosync(win, ch) == ERR) {
455 int wattr_on(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
458 win->_color = PAIR_NUMBER(at);
459 // toggle_attr_on(WINDOW_ATTRS(win), at);
462 int wattr_off(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
466 // toggle_attr_off(WINDOW_ATTRS(win), at);
469 // int wbkgd (WINDOW *, chtype) {}
470 void wbkgdset(WINDOW *win, chtype ch) { /* TODO */ }
472 int wborder(WINDOW *win, chtype ls, chtype rs, chtype ts, chtype bs,
473 chtype tl, chtype tr, chtype bl, chtype br)
477 for(y = 0; y <= win->_maxy; y++) {
480 mvwaddch(win, y, 0, tl);
482 for(x = 1; x < win->_maxx; x++)
483 mvwaddch(win, y, x, ts);
485 mvwaddch(win, y, win->_maxx, tr);
487 else if (y == win->_maxy) {
488 mvwaddch(win, y, 0, bl);
490 for(x = 1; x < win->_maxx; x++)
491 mvwaddch(win, y, x, bs);
493 mvwaddch(win, y, win->_maxx, br);
496 mvwaddch(win, y, 0, ls);
497 mvwaddch(win, y, win->_maxx, rs);
504 // int wchgat (WINDOW *, int, attr_t, short, const void *) {}
505 /* D */ int wclear(WINDOW *win)
507 if (werase(win) == ERR)
512 // int wclrtobot (WINDOW *) {}
513 int wclrtoeol(WINDOW *win) { /* TODO */ return(*(int *)0); }
514 int wcolor_set(WINDOW *win, short color_pair_number, void *opts)
516 if (!opts && (color_pair_number >= 0)
517 && (color_pair_number < COLOR_PAIRS)) {
518 SET_WINDOW_PAIR(win, color_pair_number);
519 if_EXT_COLORS(win->_color = color_pair_number);
524 // void wcursyncup (WINDOW *) {}
525 // int wdelch (WINDOW *) {}
526 // int wechochar (WINDOW *, const chtype) {}
527 int werase(WINDOW *win)
530 for (y = 0; y <= win->_maxy; y++) {
531 for (x = 0; x <= win->_maxx; x++) {
532 win->_line[y].text[x].chars[0] = ' ';
533 win->_line[y].text[x].attr = WINDOW_ATTRS(win);
538 // int wgetnstr (WINDOW *,char *,int) {}
539 int whline(WINDOW *win, chtype ch, int n)
541 NCURSES_SIZE_T start, end;
542 struct ldat *line = &(win->_line[win->_cury]);
547 if (end > win->_maxx)
550 CHANGED_RANGE(line, start, end);
554 //// SetChar2(wch, ACS_HLINE);
556 //// SetChar2(wch, ch);
558 wch.chars[0] = ((ch) & (chtype)A_CHARTEXT);
559 wch.attr = ((ch) & (chtype)A_ATTRIBUTES);
560 wch = _nc_render(win, wch);
562 while (end >= start) {
563 line->text[end] = wch;
567 //// _nc_synchook(win);
571 /* D */ chtype winch(WINDOW *win)
574 // return (CharOf(win->_line[win->_cury].text[win->_curx]) |
575 // AttrOf(win->_line[win->_cury].text[win->_curx]));
578 // int winchnstr (WINDOW *, chtype *, int) {}
579 // int winnstr (WINDOW *, char *, int) {}
580 // int winsch (WINDOW *, chtype) {}
581 // int winsdelln (WINDOW *,int) {}
582 // int winsnstr (WINDOW *, const char *,int) {}
583 /* D */ int wmove(WINDOW *win, int y, int x)
585 if (!LEGALYX(win, y, x))
587 win->_curx = (NCURSES_SIZE_T) x;
588 win->_cury = (NCURSES_SIZE_T) y;
589 win->_flags &= ~_WRAPPED;
590 win->_flags |= _HASMOVED;
594 int wnoutrefresh(WINDOW *win)
597 int serial_is_bold = 0;
603 for (y = 0; y <= win->_maxy; y++) {
605 /* Position the serial cursor */
607 if (curses_flags & F_ENABLE_SERIAL)
608 serial_set_cursor(win->_begy + y, win->_begx);
610 for (x = 0; x <= win->_maxx; x++) {
611 attr_t attr = win->_line[y].text[x].attr;
614 ((int)color_pairs[PAIR_NUMBER(attr)]) << 8;
616 if (curses_flags & F_ENABLE_SERIAL) {
619 if (!serial_is_bold) {
625 if (serial_is_bold) {
631 serial_putchar(win->_line[y].text[x].chars[0]);
634 if (curses_flags & F_ENABLE_CONSOLE) {
636 /* Handle some of the attributes. */
641 if (attr & A_REVERSE) {
642 unsigned char tmp = (c >> 8) & 0xf;
643 c = (c >> 4) & 0xf00;
648 * FIXME: Somewhere along the line, the
649 * character value is getting sign-extented.
650 * For now grab just the 8 bit character,
651 * but this will break wide characters!
653 c |= (chtype) (win->_line[y].text[x].chars[0] & 0xff);
654 video_console_putc(win->_begy + y, win->_begx + x, c);
661 int wprintw(WINDOW *win, const char *fmt, ...)
667 code = vwprintw(win, fmt, argp);
672 // int wredrawln (WINDOW *,int,int) {}
673 int wrefresh(WINDOW *win)
676 return wnoutrefresh(win);
682 curscr->_clear = TRUE;
683 // code = doupdate();
684 } else if ((code = wnoutrefresh(win)) == OK) {
686 newscr->_clear = TRUE;
687 // code = doupdate();
689 * Reset the clearok() flag in case it was set for the special
690 * case in hardscroll.c (if we don't reset it here, we'll get 2
691 * refreshes because the flag is copied from stdscr to newscr).
692 * Resetting the flag shouldn't do any harm, anyway.
699 // int wscanw (WINDOW *, NCURSES_CONST char *,...) {}
700 int wscrl(WINDOW *win, int n)
706 // _nc_scroll_window(win, n, win->_regtop, win->_regbottom, win->_nc_bkgd);
707 // _nc_synchook(win);
711 int wsetscrreg(WINDOW *win, int top, int bottom)
713 if (top >= 0 && top <= win->_maxy && bottom >= 0 &&
714 bottom <= win->_maxy && bottom > top) {
715 win->_regtop = (NCURSES_SIZE_T) top;
716 win->_regbottom = (NCURSES_SIZE_T) bottom;
721 // void wsyncdown (WINDOW *) {}
722 // void wsyncup (WINDOW *) {}
723 /* D */ void wtimeout(WINDOW *win, int delay) { win->_delay = delay; }
724 /* D */ int wtouchln(WINDOW *win, int y, int n, int changed)
728 // if ((n < 0) || (y < 0) || (y > win->_maxy))
731 for (i = y; i < y + n; i++) {
734 win->_line[i].firstchar = changed ? 0 : _NOCHANGE;
735 win->_line[i].lastchar = changed ? win->_maxx : _NOCHANGE;
739 // int wvline (WINDOW *,chtype,int) {}
740 // int tigetflag (NCURSES_CONST char *) {}
741 // int tigetnum (NCURSES_CONST char *) {}
742 // char *tigetstr (NCURSES_CONST char *) {}
743 // int putp (const char *) {}
744 // #if NCURSES_TPARM_VARARGS
745 // char *tparm (NCURSES_CONST char *, ...) {}
747 // char *tparm (NCURSES_CONST char *, long,long,long,long,long,long,long,long,long) {}
748 // char *tparm_varargs (NCURSES_CONST char *, ...) {}