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[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 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_CONSOLE) {
222 /* Clear the screen and kill the cursor. */
224 vga_cursor_enable(0);
229 stdscr = newwin(SCREEN_Y, SCREEN_X + 1, 0, 0);
230 // TODO: curscr, newscr?
232 for (y = 0; y < stdscr->_maxy; y++) {
233 for (x = 0; x < stdscr->_maxx; x++) {
234 stdscr->_line[y].text[x].chars[0] = ' ';
235 stdscr->_line[y].text[x].attr = A_NORMAL;
241 // int intrflush (WINDOW *,bool) {}
242 /* D */ bool isendwin(void) { return ((SP == NULL) ? FALSE : SP->_endwin); }
243 // bool is_linetouched (WINDOW *,int) {}
244 // bool is_wintouched (WINDOW *) {}
245 // NCURSES_CONST char * keyname (int) {}
246 int keypad (WINDOW *win, bool flag) { /* TODO */ return 0; }
247 // char killchar (void) {}
248 /* D */ int leaveok(WINDOW *win, bool flag) { win->_leaveok = flag; return OK; }
249 // char *longname (void) {}
250 // int meta (WINDOW *,bool) {}
251 // int mvcur (int,int,int,int) {}
252 // int mvderwin (WINDOW *, int, int) {}
253 int mvprintw(int y, int x, const char *fmt, ...)
258 if (move(y, x) == ERR)
262 code = vwprintw(stdscr, fmt, argp);
267 // int mvscanw (int,int, NCURSES_CONST char *,...) {}
268 // int mvwin (WINDOW *,int,int) {}
269 int mvwprintw(WINDOW *win, int y, int x, const char *fmt, ...)
274 if (wmove(win, y, x) == ERR)
278 code = vwprintw(win, fmt, argp);
283 // int mvwscanw (WINDOW *,int,int, NCURSES_CONST char *,...) {}
284 // int napms (int) {}
285 // WINDOW *newpad (int,int) {}
286 // SCREEN *newterm (NCURSES_CONST char *,FILE *,FILE *) {}
287 WINDOW *newwin(int num_lines, int num_columns, int begy, int begx)
291 /* Use next statically allocated window. */
292 // TODO: Error handling.
294 WINDOW *win = &window_list[window_count++];
296 // bool is_pad = (flags & _ISPAD);
302 win->_maxy = num_lines - 1;
303 win->_maxx = num_columns - 1;
306 // win->_yoffset = SP->_topstolen;
308 win->_line = &ldat_list[ldat_count++];
310 /* FIXME: Is this right? Should the window attributes be normal? */
311 win->_color = PAIR_NUMBER(0);
312 win->_attrs = A_NORMAL;
314 for (i = 0; i < num_lines; i++)
316 (NCURSES_CH_T *)&linebuf_list[linebuf_count++];
320 /* D */ int nl(void) { SP->_nl = TRUE; return OK; }
321 /* D */ int noecho(void) { SP->_echo = FALSE; return OK; }
322 /* D */ int nonl(void) { SP->_nl = FALSE; return OK; }
323 // void noqiflush (void) {}
324 // int noraw (void) {}
325 /* D */ int notimeout (WINDOW *win, bool f) { win->_notimeout = f; return OK; }
326 // int overlay (const WINDOW*,WINDOW *) {}
327 // int overwrite (const WINDOW*,WINDOW *) {}
328 // int pair_content (short,short*,short*) {}
329 // int pechochar (WINDOW *, const chtype) {}
330 // int pnoutrefresh (WINDOW*,int,int,int,int,int,int) {}
331 // int prefresh (WINDOW *,int,int,int,int,int,int) {}
332 int printw(const char *fmt, ...)
338 code = vwprintw(stdscr, fmt, argp);
343 // int putwin (WINDOW *, FILE *) {}
344 // void qiflush (void) {}
346 // int resetty (void) {}
347 // int reset_prog_mode (void) {}
348 // int reset_shell_mode (void) {}
349 // int ripoffline (int, int (*)(WINDOW *, int)) {}
350 // int savetty (void) {}
351 // int scanw (NCURSES_CONST char *,...) {}
352 // int scr_dump (const char *) {}
353 // int scr_init (const char *) {}
354 /* D */ int scrollok(WINDOW *win, bool flag) { win->_scroll = flag; return OK; }
355 // int scr_restore (const char *) {}
356 // int scr_set (const char *) {}
357 // SCREEN *set_term (SCREEN *) {}
358 // int slk_attroff (const chtype) {}
359 // int slk_attron (const chtype) {}
360 // int slk_attrset (const chtype) {}
361 // attr_t slk_attr (void) {}
362 // int slk_attr_set (const attr_t,short,void*) {}
363 // int slk_clear (void) {}
364 // int slk_color (short) {}
365 // int slk_init (int) {}
366 /* D */ char *slk_label(int n)
369 // if (SP == NULL || SP->_slk == NULL || n < 1 || n > SP->_slk->labcnt)
371 return SP->_slk->ent[n - 1].ent_text;
373 // int slk_noutrefresh (void) {}
374 // int slk_refresh (void) {}
375 // int slk_restore (void) {}
376 // int slk_set (int,const char *,int) {}
377 // int slk_touch (void) {}
379 // WINDOW *subpad (WINDOW *, int, int, int, int) {}
380 WINDOW *subwin(WINDOW *w, int l, int c, int y, int x)
382 return derwin(w, l, c, y - w->_begy, x - w->_begx);
384 // int syncok (WINDOW *, bool) {}
385 // chtype termattrs (void) {}
386 // char *termname (void) {}
387 // int typeahead (int) {}
388 int ungetch(int ch) { /* TODO */ return ERR; }
389 // void use_env (bool) {}
390 // int vidattr (chtype) {}
391 // int vidputs (chtype, int (*)(int)) {}
392 int vwprintw(WINDOW *win, const char *fmt, va_list argp)
394 vsprintf((char *)&sprintf_tmp, fmt, argp);
396 /* TODO: Error handling? */
397 return waddstr(win, (char *)&sprintf_tmp);
399 // int vwscanw (WINDOW *, NCURSES_CONST char *,va_list) {}
400 // int waddch (WINDOW *, const chtype) {}
401 int waddch(WINDOW *win, const chtype ch)
405 // SetChar2(wch, ch);
407 win->_line[win->_cury].text[win->_curx].chars[0] = ch;
409 /* Use the window attributes - perhaps we also pull attributes from
410 the ch itself, I don't know */
412 win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win);
413 win->_curx++; // FIXME
415 // if (win && (waddch_nosync(win, wch) != ERR)) {
416 // _nc_synchook(win);
422 // int waddchnstr (WINDOW *,const chtype *,int) {}
423 int waddnstr(WINDOW *win, const char *astr, int n)
426 const char *str = astr;
434 while ((n-- > 0) && (*str != '\0')) {
435 // while (*str != '\0') {
436 win->_line[win->_cury].text[win->_curx].chars[0] = *str++;
437 win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win)
439 win->_curx++; // FIXME
442 // SetChar(ch, UChar(*str++), A_NORMAL);
443 // if (_nc_waddch_nosync(win, ch) == ERR) {
450 int wattr_on(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
453 win->_color = PAIR_NUMBER(at);
454 // toggle_attr_on(WINDOW_ATTRS(win), at);
457 int wattr_off(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
461 // toggle_attr_off(WINDOW_ATTRS(win), at);
464 // int wbkgd (WINDOW *, chtype) {}
465 void wbkgdset(WINDOW *win, chtype ch) { /* TODO */ }
466 // int wborder (WINDOW *,chtype,chtype,chtype,chtype,chtype,chtype,chtype,chtype) {}
467 // int wchgat (WINDOW *, int, attr_t, short, const void *) {}
468 /* D */ int wclear(WINDOW *win)
470 if (werase(win) == ERR)
475 // int wclrtobot (WINDOW *) {}
476 int wclrtoeol(WINDOW *win) { /* TODO */ return(*(int *)0); }
477 int wcolor_set(WINDOW *win, short color_pair_number, void *opts)
479 if (!opts && (color_pair_number >= 0)
480 && (color_pair_number < COLOR_PAIRS)) {
481 SET_WINDOW_PAIR(win, color_pair_number);
482 if_EXT_COLORS(win->_color = color_pair_number);
487 // void wcursyncup (WINDOW *) {}
488 // int wdelch (WINDOW *) {}
489 // int wechochar (WINDOW *, const chtype) {}
490 int werase(WINDOW *win)
493 for (y = 0; y < win->_maxy; y++) {
494 for (x = 0; x < win->_maxx; x++) {
495 win->_line[y].text[x].chars[0] = ' ';
496 win->_line[y].text[x].attr = WINDOW_ATTRS(win);
501 // int wgetnstr (WINDOW *,char *,int) {}
502 int whline(WINDOW *win, chtype ch, int n)
504 NCURSES_SIZE_T start, end;
505 struct ldat *line = &(win->_line[win->_cury]);
510 if (end > win->_maxx)
513 CHANGED_RANGE(line, start, end);
517 //// SetChar2(wch, ACS_HLINE);
519 //// SetChar2(wch, ch);
521 wch.chars[0] = ((ch) & (chtype)A_CHARTEXT);
522 wch.attr = ((ch) & (chtype)A_ATTRIBUTES);
523 wch = _nc_render(win, wch);
525 while (end >= start) {
526 line->text[end] = wch;
530 //// _nc_synchook(win);
534 /* D */ chtype winch(WINDOW *win)
537 // return (CharOf(win->_line[win->_cury].text[win->_curx]) |
538 // AttrOf(win->_line[win->_cury].text[win->_curx]));
541 // int winchnstr (WINDOW *, chtype *, int) {}
542 // int winnstr (WINDOW *, char *, int) {}
543 // int winsch (WINDOW *, chtype) {}
544 // int winsdelln (WINDOW *,int) {}
545 // int winsnstr (WINDOW *, const char *,int) {}
546 /* D */ int wmove(WINDOW *win, int y, int x)
548 if (!LEGALYX(win, y, x))
550 win->_curx = (NCURSES_SIZE_T) x;
551 win->_cury = (NCURSES_SIZE_T) y;
552 win->_flags &= ~_WRAPPED;
553 win->_flags |= _HASMOVED;
556 int wnoutrefresh(WINDOW *win)
561 for (y = 0; y < win->_maxy; y++) {
562 for (x = 0; x < win->_maxx; x++) {
563 if (curses_flags & F_ENABLE_SERIAL)
564 serial_putchar(win->_line[y].text[x].chars[0]);
566 if (curses_flags & F_ENABLE_CONSOLE) {
567 attr_t attr = win->_line[y].text[x].attr;
569 ((int)color_pairs[PAIR_NUMBER(attr)]) << 8;
571 /* Handle some of the attributes. */
576 if (attr & A_REVERSE) {
577 unsigned char tmp = (c >> 8) & 0xf;
578 c = (c >> 4) & 0xf00;
583 * FIXME: Somewhere along the line, the
584 * character value is getting sign-extented.
585 * For now grab just the 8 bit character,
586 * but this will break wide characters!
588 c |= (chtype) (win->_line[y].text[x].chars[0] & 0xff);
596 int wprintw(WINDOW *win, const char *fmt, ...)
602 code = vwprintw(win, fmt, argp);
607 // int wredrawln (WINDOW *,int,int) {}
608 int wrefresh(WINDOW *win)
611 return wnoutrefresh(win);
617 curscr->_clear = TRUE;
618 // code = doupdate();
619 } else if ((code = wnoutrefresh(win)) == OK) {
621 newscr->_clear = TRUE;
622 // code = doupdate();
624 * Reset the clearok() flag in case it was set for the special
625 * case in hardscroll.c (if we don't reset it here, we'll get 2
626 * refreshes because the flag is copied from stdscr to newscr).
627 * Resetting the flag shouldn't do any harm, anyway.
634 // int wscanw (WINDOW *, NCURSES_CONST char *,...) {}
635 int wscrl(WINDOW *win, int n)
641 // _nc_scroll_window(win, n, win->_regtop, win->_regbottom, win->_nc_bkgd);
642 // _nc_synchook(win);
646 int wsetscrreg(WINDOW *win, int top, int bottom)
648 if (top >= 0 && top <= win->_maxy && bottom >= 0 &&
649 bottom <= win->_maxy && bottom > top) {
650 win->_regtop = (NCURSES_SIZE_T) top;
651 win->_regbottom = (NCURSES_SIZE_T) bottom;
656 // void wsyncdown (WINDOW *) {}
657 // void wsyncup (WINDOW *) {}
658 /* D */ void wtimeout(WINDOW *win, int delay) { win->_delay = delay; }
659 /* D */ int wtouchln(WINDOW *win, int y, int n, int changed)
663 // if ((n < 0) || (y < 0) || (y > win->_maxy))
666 for (i = y; i < y + n; i++) {
669 win->_line[i].firstchar = changed ? 0 : _NOCHANGE;
670 win->_line[i].lastchar = changed ? win->_maxx : _NOCHANGE;
674 // int wvline (WINDOW *,chtype,int) {}
675 // int tigetflag (NCURSES_CONST char *) {}
676 // int tigetnum (NCURSES_CONST char *) {}
677 // char *tigetstr (NCURSES_CONST char *) {}
678 // int putp (const char *) {}
679 // #if NCURSES_TPARM_VARARGS
680 // char *tparm (NCURSES_CONST char *, ...) {}
682 // char *tparm (NCURSES_CONST char *, long,long,long,long,long,long,long,long,long) {}
683 // char *tparm_varargs (NCURSES_CONST char *, ...) {}