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 video_console_clear();
225 video_console_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;
242 // int intrflush (WINDOW *,bool) {}
243 /* D */ bool isendwin(void) { return ((SP == NULL) ? FALSE : SP->_endwin); }
244 // bool is_linetouched (WINDOW *,int) {}
245 // bool is_wintouched (WINDOW *) {}
246 // NCURSES_CONST char * keyname (int) {}
247 int keypad (WINDOW *win, bool flag) { /* TODO */ return 0; }
248 // char killchar (void) {}
249 /* D */ int leaveok(WINDOW *win, bool flag) { win->_leaveok = flag; return OK; }
250 // char *longname (void) {}
251 // int meta (WINDOW *,bool) {}
252 // int mvcur (int,int,int,int) {}
253 // int mvderwin (WINDOW *, int, int) {}
254 int mvprintw(int y, int x, const char *fmt, ...)
259 if (move(y, x) == ERR)
263 code = vwprintw(stdscr, fmt, argp);
268 // int mvscanw (int,int, NCURSES_CONST char *,...) {}
269 // int mvwin (WINDOW *,int,int) {}
270 int mvwprintw(WINDOW *win, int y, int x, const char *fmt, ...)
275 if (wmove(win, y, x) == ERR)
279 code = vwprintw(win, fmt, argp);
284 // int mvwscanw (WINDOW *,int,int, NCURSES_CONST char *,...) {}
285 // int napms (int) {}
286 // WINDOW *newpad (int,int) {}
287 // SCREEN *newterm (NCURSES_CONST char *,FILE *,FILE *) {}
288 WINDOW *newwin(int num_lines, int num_columns, int begy, int begx)
292 /* Use next statically allocated window. */
293 // TODO: Error handling.
295 WINDOW *win = &window_list[window_count++];
297 // bool is_pad = (flags & _ISPAD);
303 win->_maxy = num_lines - 1;
304 win->_maxx = num_columns - 1;
307 // win->_yoffset = SP->_topstolen;
309 win->_line = &ldat_list[ldat_count++];
311 /* FIXME: Is this right? Should the window attributes be normal? */
312 win->_color = PAIR_NUMBER(0);
313 win->_attrs = A_NORMAL;
315 for (i = 0; i < num_lines; i++)
317 (NCURSES_CH_T *)&linebuf_list[linebuf_count++];
321 /* D */ int nl(void) { SP->_nl = TRUE; return OK; }
322 /* D */ int noecho(void) { SP->_echo = FALSE; return OK; }
323 /* D */ int nonl(void) { SP->_nl = FALSE; return OK; }
324 // void noqiflush (void) {}
325 // int noraw (void) {}
326 /* D */ int notimeout (WINDOW *win, bool f) { win->_notimeout = f; return OK; }
327 // int overlay (const WINDOW*,WINDOW *) {}
328 // int overwrite (const WINDOW*,WINDOW *) {}
329 // int pair_content (short,short*,short*) {}
330 // int pechochar (WINDOW *, const chtype) {}
331 // int pnoutrefresh (WINDOW*,int,int,int,int,int,int) {}
332 // int prefresh (WINDOW *,int,int,int,int,int,int) {}
333 int printw(const char *fmt, ...)
339 code = vwprintw(stdscr, fmt, argp);
344 // int putwin (WINDOW *, FILE *) {}
345 // void qiflush (void) {}
347 // int resetty (void) {}
348 // int reset_prog_mode (void) {}
349 // int reset_shell_mode (void) {}
350 // int ripoffline (int, int (*)(WINDOW *, int)) {}
351 // int savetty (void) {}
352 // int scanw (NCURSES_CONST char *,...) {}
353 // int scr_dump (const char *) {}
354 // int scr_init (const char *) {}
355 /* D */ int scrollok(WINDOW *win, bool flag) { win->_scroll = flag; return OK; }
356 // int scr_restore (const char *) {}
357 // int scr_set (const char *) {}
358 // SCREEN *set_term (SCREEN *) {}
359 // int slk_attroff (const chtype) {}
360 // int slk_attron (const chtype) {}
361 // int slk_attrset (const chtype) {}
362 // attr_t slk_attr (void) {}
363 // int slk_attr_set (const attr_t,short,void*) {}
364 // int slk_clear (void) {}
365 // int slk_color (short) {}
366 // int slk_init (int) {}
367 /* D */ char *slk_label(int n)
370 // if (SP == NULL || SP->_slk == NULL || n < 1 || n > SP->_slk->labcnt)
372 return SP->_slk->ent[n - 1].ent_text;
374 // int slk_noutrefresh (void) {}
375 // int slk_refresh (void) {}
376 // int slk_restore (void) {}
377 // int slk_set (int,const char *,int) {}
378 // int slk_touch (void) {}
380 // WINDOW *subpad (WINDOW *, int, int, int, int) {}
381 WINDOW *subwin(WINDOW *w, int l, int c, int y, int x)
383 return derwin(w, l, c, y - w->_begy, x - w->_begx);
385 // int syncok (WINDOW *, bool) {}
386 // chtype termattrs (void) {}
387 // char *termname (void) {}
388 // int typeahead (int) {}
389 int ungetch(int ch) { /* TODO */ return ERR; }
390 // void use_env (bool) {}
391 // int vidattr (chtype) {}
392 // int vidputs (chtype, int (*)(int)) {}
393 int vwprintw(WINDOW *win, const char *fmt, va_list argp)
395 vsprintf((char *)&sprintf_tmp, fmt, argp);
397 /* TODO: Error handling? */
398 return waddstr(win, (char *)&sprintf_tmp);
400 // int vwscanw (WINDOW *, NCURSES_CONST char *,va_list) {}
401 // int waddch (WINDOW *, const chtype) {}
402 int waddch(WINDOW *win, const chtype ch)
406 // SetChar2(wch, ch);
408 win->_line[win->_cury].text[win->_curx].chars[0] = ch;
410 /* Use the window attributes - perhaps we also pull attributes from
411 the ch itself, I don't know */
413 win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win);
414 win->_curx++; // FIXME
416 // if (win && (waddch_nosync(win, wch) != ERR)) {
417 // _nc_synchook(win);
423 // int waddchnstr (WINDOW *,const chtype *,int) {}
424 int waddnstr(WINDOW *win, const char *astr, int n)
427 const char *str = astr;
435 while ((n-- > 0) && (*str != '\0')) {
436 // while (*str != '\0') {
437 win->_line[win->_cury].text[win->_curx].chars[0] = *str++;
438 win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win)
440 win->_curx++; // FIXME
443 // SetChar(ch, UChar(*str++), A_NORMAL);
444 // if (_nc_waddch_nosync(win, ch) == ERR) {
451 int wattr_on(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
454 win->_color = PAIR_NUMBER(at);
455 // toggle_attr_on(WINDOW_ATTRS(win), at);
458 int wattr_off(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
462 // toggle_attr_off(WINDOW_ATTRS(win), at);
465 // int wbkgd (WINDOW *, chtype) {}
466 void wbkgdset(WINDOW *win, chtype ch) { /* TODO */ }
468 int wborder(WINDOW *win, chtype ls, chtype rs, chtype ts, chtype bs,
469 chtype tl, chtype tr, chtype bl, chtype br)
473 for(y = 0; y <= win->_maxy; y++) {
476 mvwaddch(win, y, 0, tl);
478 for(x = 1; x < win->_maxx; x++)
479 mvwaddch(win, y, x, ts);
481 mvwaddch(win, y, win->_maxx, tr);
483 else if (y == win->_maxy) {
484 mvwaddch(win, y, 0, bl);
486 for(x = 1; x < win->_maxx; x++)
487 mvwaddch(win, y, x, bs);
489 mvwaddch(win, y, win->_maxx, br);
492 mvwaddch(win, y, 0, ls);
493 mvwaddch(win, y, win->_maxx, rs);
500 // int wchgat (WINDOW *, int, attr_t, short, const void *) {}
501 /* D */ int wclear(WINDOW *win)
503 if (werase(win) == ERR)
508 // int wclrtobot (WINDOW *) {}
509 int wclrtoeol(WINDOW *win) { /* TODO */ return(*(int *)0); }
510 int wcolor_set(WINDOW *win, short color_pair_number, void *opts)
512 if (!opts && (color_pair_number >= 0)
513 && (color_pair_number < COLOR_PAIRS)) {
514 SET_WINDOW_PAIR(win, color_pair_number);
515 if_EXT_COLORS(win->_color = color_pair_number);
520 // void wcursyncup (WINDOW *) {}
521 // int wdelch (WINDOW *) {}
522 // int wechochar (WINDOW *, const chtype) {}
523 int werase(WINDOW *win)
526 for (y = 0; y < win->_maxy; y++) {
527 for (x = 0; x < win->_maxx; x++) {
528 win->_line[y].text[x].chars[0] = ' ';
529 win->_line[y].text[x].attr = WINDOW_ATTRS(win);
534 // int wgetnstr (WINDOW *,char *,int) {}
535 int whline(WINDOW *win, chtype ch, int n)
537 NCURSES_SIZE_T start, end;
538 struct ldat *line = &(win->_line[win->_cury]);
543 if (end > win->_maxx)
546 CHANGED_RANGE(line, start, end);
550 //// SetChar2(wch, ACS_HLINE);
552 //// SetChar2(wch, ch);
554 wch.chars[0] = ((ch) & (chtype)A_CHARTEXT);
555 wch.attr = ((ch) & (chtype)A_ATTRIBUTES);
556 wch = _nc_render(win, wch);
558 while (end >= start) {
559 line->text[end] = wch;
563 //// _nc_synchook(win);
567 /* D */ chtype winch(WINDOW *win)
570 // return (CharOf(win->_line[win->_cury].text[win->_curx]) |
571 // AttrOf(win->_line[win->_cury].text[win->_curx]));
574 // int winchnstr (WINDOW *, chtype *, int) {}
575 // int winnstr (WINDOW *, char *, int) {}
576 // int winsch (WINDOW *, chtype) {}
577 // int winsdelln (WINDOW *,int) {}
578 // int winsnstr (WINDOW *, const char *,int) {}
579 /* D */ int wmove(WINDOW *win, int y, int x)
581 if (!LEGALYX(win, y, x))
583 win->_curx = (NCURSES_SIZE_T) x;
584 win->_cury = (NCURSES_SIZE_T) y;
585 win->_flags &= ~_WRAPPED;
586 win->_flags |= _HASMOVED;
589 int wnoutrefresh(WINDOW *win)
594 for (y = 0; y < win->_maxy; y++) {
595 for (x = 0; x < win->_maxx; x++) {
596 if (curses_flags & F_ENABLE_SERIAL)
597 serial_putchar(win->_line[y].text[x].chars[0]);
599 if (curses_flags & F_ENABLE_CONSOLE) {
600 attr_t attr = win->_line[y].text[x].attr;
602 ((int)color_pairs[PAIR_NUMBER(attr)]) << 8;
604 /* Handle some of the attributes. */
609 if (attr & A_REVERSE) {
610 unsigned char tmp = (c >> 8) & 0xf;
611 c = (c >> 4) & 0xf00;
616 * FIXME: Somewhere along the line, the
617 * character value is getting sign-extented.
618 * For now grab just the 8 bit character,
619 * but this will break wide characters!
621 c |= (chtype) (win->_line[y].text[x].chars[0] & 0xff);
622 video_console_putc(y, x, c);
629 int wprintw(WINDOW *win, const char *fmt, ...)
635 code = vwprintw(win, fmt, argp);
640 // int wredrawln (WINDOW *,int,int) {}
641 int wrefresh(WINDOW *win)
644 return wnoutrefresh(win);
650 curscr->_clear = TRUE;
651 // code = doupdate();
652 } else if ((code = wnoutrefresh(win)) == OK) {
654 newscr->_clear = TRUE;
655 // code = doupdate();
657 * Reset the clearok() flag in case it was set for the special
658 * case in hardscroll.c (if we don't reset it here, we'll get 2
659 * refreshes because the flag is copied from stdscr to newscr).
660 * Resetting the flag shouldn't do any harm, anyway.
667 // int wscanw (WINDOW *, NCURSES_CONST char *,...) {}
668 int wscrl(WINDOW *win, int n)
674 // _nc_scroll_window(win, n, win->_regtop, win->_regbottom, win->_nc_bkgd);
675 // _nc_synchook(win);
679 int wsetscrreg(WINDOW *win, int top, int bottom)
681 if (top >= 0 && top <= win->_maxy && bottom >= 0 &&
682 bottom <= win->_maxy && bottom > top) {
683 win->_regtop = (NCURSES_SIZE_T) top;
684 win->_regbottom = (NCURSES_SIZE_T) bottom;
689 // void wsyncdown (WINDOW *) {}
690 // void wsyncup (WINDOW *) {}
691 /* D */ void wtimeout(WINDOW *win, int delay) { win->_delay = delay; }
692 /* D */ int wtouchln(WINDOW *win, int y, int n, int changed)
696 // if ((n < 0) || (y < 0) || (y > win->_maxy))
699 for (i = y; i < y + n; i++) {
702 win->_line[i].firstchar = changed ? 0 : _NOCHANGE;
703 win->_line[i].lastchar = changed ? win->_maxx : _NOCHANGE;
707 // int wvline (WINDOW *,chtype,int) {}
708 // int tigetflag (NCURSES_CONST char *) {}
709 // int tigetnum (NCURSES_CONST char *) {}
710 // char *tigetstr (NCURSES_CONST char *) {}
711 // int putp (const char *) {}
712 // #if NCURSES_TPARM_VARARGS
713 // char *tparm (NCURSES_CONST char *, ...) {}
715 // char *tparm (NCURSES_CONST char *, long,long,long,long,long,long,long,long,long) {}
716 // char *tparm_varargs (NCURSES_CONST char *, ...) {}