curses.c 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. #include <curses.h>
  2. #include <malloc.h>
  3. #include <stddef.h>
  4. #include <vsprintf.h>
  5. #include <string.h>
  6. /** @file
  7. *
  8. * MuCurses: lightweight xcurses implementation for PXE ROMs
  9. *
  10. */
  11. #define WRAP 0
  12. #define NOWRAP 1
  13. unsigned short _COLS;
  14. unsigned short _LINES;
  15. unsigned short _COLOURS;
  16. unsigned int *_COLOUR_PAIRS; /* basically this is an array, but as its
  17. length is determined only when initscr
  18. is run, I can only think to make it a
  19. pointer and malloc the array into being
  20. ... */
  21. struct cursor_pos {
  22. unsigned int y, x;
  23. };
  24. struct _softlabel {
  25. /* Format of soft label
  26. 0: left justify
  27. 1: centre justify
  28. 2: right justify
  29. */
  30. int fmt;
  31. // label string
  32. char *label;
  33. };
  34. struct _softlabelkeys {
  35. struct _softlabel fkeys[12];
  36. attr_t attrs;
  37. unsigned int fmt;
  38. unsigned int maxlablen;
  39. };
  40. struct _softlabelkeys *slks;
  41. WINDOW _stdscr = {
  42. .attrs = A_DEFAULT,
  43. .ori_y = 0,
  44. .ori_x = 0,
  45. .curs_y = 0,
  46. .curs_x = 0,
  47. .scr = curscr,
  48. };
  49. /*
  50. * Primitives
  51. */
  52. /**
  53. * Write a single character rendition to a window
  54. *
  55. * @v *win window in which to write
  56. * @v ch character rendition to write
  57. * @v wrap wrap "switch"
  58. */
  59. static void _wputch ( WINDOW *win, chtype ch, int wrap ) {
  60. /* make sure we set the screen cursor to the right position
  61. first! */
  62. win->scr->movetoyx( win->scr, win->ori_y + win->curs_y,
  63. win->ori_x + win->curs_x );
  64. win->scr->putc(win->scr, ch);
  65. if ( ++(win->curs_x) == win->width ) {
  66. if ( wrap == WRAP ) {
  67. win->curs_x = 0;
  68. /* specification says we should really scroll,
  69. but we have no buffer to scroll with, so we
  70. can only overwrite back at the beginning of
  71. the window */
  72. if ( ++(win->curs_y) == win->height )
  73. win->curs_y = 0;
  74. } else {
  75. (win->curs_x)--;
  76. }
  77. }
  78. }
  79. /**
  80. * Write a chtype string to a window
  81. *
  82. * @v *win window in which to write
  83. * @v *chstr chtype string
  84. * @v wrap wrap "switch"
  85. * @v n write at most n chtypes
  86. */
  87. static void _wputchstr ( WINDOW *win, const chtype *chstr, int wrap, int n ) {
  88. for ( ; *chstr && n-- ; chstr++ ) {
  89. _wputch(win,*chstr,wrap);
  90. }
  91. }
  92. /**
  93. * Write a standard c-style string to a window
  94. *
  95. * @v *win window in which to write
  96. * @v *str string
  97. * @v wrap wrap "switch"
  98. * @v n write at most n chars from *str
  99. */
  100. static void _wputstr ( WINDOW *win, const char *str, int wrap, int n ) {
  101. for ( ; *str && n-- ; str++ ) {
  102. _wputch( win, *str | win->attrs, wrap );
  103. }
  104. }
  105. /**
  106. * Restore cursor position from encoded backup variable
  107. *
  108. * @v *win window on which to operate
  109. * @v *pos pointer to struct in which original cursor position is stored
  110. */
  111. static void _restore_curs_pos ( WINDOW *win, struct cursor_pos *pos ){
  112. win->curs_y = pos->y;
  113. win->curs_x = pos->x;
  114. win->scr->movetoyx ( win->scr, win->curs_y, win->curs_x );
  115. }
  116. /**
  117. * Store cursor position for later restoration
  118. *
  119. * @v *win window on which to operate
  120. * @v *pos pointer to struct in which to store cursor position
  121. */
  122. static void _store_curs_pos ( WINDOW *win, struct cursor_pos *pos ) {
  123. pos->y = win->curs_y;
  124. pos->x = win->curs_x;
  125. }
  126. /**
  127. * Move a window's cursor to the specified position
  128. *
  129. * @v *win window to be operated on
  130. * @v y Y position
  131. * @v x X position
  132. * @ret rc return status code
  133. */
  134. int wmove ( WINDOW *win, int y, int x ) {
  135. /* chech for out-of-bounds errors */
  136. if ( ( ( (unsigned)x - win->ori_x ) > win->width ) ||
  137. ( ( (unsigned)y - win->ori_y ) > win->height ) ) {
  138. return ERR;
  139. }
  140. win->curs_y = y;
  141. win->curs_x = x;
  142. win->scr->movetoyx( win->scr, win->ori_y + win->curs_y,
  143. win->ori_x + win->curs_x );
  144. return OK;
  145. }
  146. /**
  147. * get terminal baud rate
  148. *
  149. * @ret bps return baud rate in bits per second
  150. */
  151. int baudrate ( void ) {
  152. return OK;
  153. }
  154. /**
  155. * Audible (or visual) signal
  156. *
  157. * @ret rc return status code
  158. */
  159. int beep ( void ) {
  160. printf("\a");
  161. return OK;
  162. }
  163. /**
  164. * Draw borders from single-byte characters and renditions around a
  165. * window
  166. *
  167. * @v *win window to be bordered
  168. * @v verch vertical chtype
  169. * @v horch horizontal chtype
  170. * @ret rc return status code
  171. */
  172. int box ( WINDOW *win, chtype verch, chtype horch ) {
  173. int corner = '+' | win->attrs; /* default corner character */
  174. return wborder( win, verch, verch, horch, horch,
  175. corner, corner, corner, corner );
  176. }
  177. /**
  178. * Indicates whether the underlying terminal device is capable of
  179. * having colours redefined
  180. *
  181. * @ret bool returns boolean
  182. */
  183. bool can_change_colour ( void ) {
  184. return (bool)TRUE;
  185. }
  186. /**
  187. * Identify the RGB components of a given colour value
  188. *
  189. * @v colour colour value
  190. * @v *red address to store red component
  191. * @v *green address to store green component
  192. * @v *blue address to store blue component
  193. * @ret rc return status code
  194. */
  195. int colour_content ( short colour, short *red, short *green, short *blue ) {
  196. /* we do not have a particularly large range of colours (3
  197. primary, 3 secondary and black), so let's just put in a
  198. basic switch... */
  199. switch(colour) {
  200. case COLOUR_BLACK:
  201. *red = 0; *green = 0; *blue = 0;
  202. break;
  203. case COLOUR_BLUE:
  204. *red = 0; *green = 0; *blue = 1000;
  205. break;
  206. case COLOUR_GREEN:
  207. *red = 0; *green = 1000; *blue = 0;
  208. break;
  209. case COLOUR_CYAN:
  210. *red = 0; *green = 1000; *blue = 1000;
  211. break;
  212. case COLOUR_RED:
  213. *red = 1000; *green = 0; *blue = 0;
  214. break;
  215. case COLOUR_MAGENTA:
  216. *red = 1000; *green = 0; *blue = 1000;
  217. break;
  218. case COLOUR_YELLOW:
  219. *red = 1000; *green = 1000; *blue = 0;
  220. break;
  221. }
  222. return OK;
  223. }
  224. /**
  225. * Delete a window
  226. *
  227. * @v *win pointer to window being deleted
  228. * @ret rc return status code
  229. */
  230. int delwin ( WINDOW *win ) {
  231. if ( win == NULL )
  232. goto err;
  233. /* must free descendants first, but I haven't implemented descendants yet
  234. ... */
  235. free(win);
  236. return OK;
  237. err:
  238. return ERR;
  239. }
  240. /**
  241. * Get the background rendition attributes for a window
  242. *
  243. * @v *win subject window
  244. * @ret ch chtype rendition representation
  245. */
  246. inline chtype getbkgd ( WINDOW *win ) {
  247. return win->attrs;
  248. }
  249. /**
  250. * Initialise console environment
  251. *
  252. * @ret *win return pointer to stdscr
  253. */
  254. WINDOW *initscr ( void ) {
  255. /* determine console size */
  256. /* initialise screen */
  257. stdscr->width = 80;
  258. stdscr->height = 25;
  259. /* set previously unknown window attributes */
  260. /* refresh screen */
  261. return stdscr;
  262. }
  263. /**
  264. * Create new WINDOW
  265. *
  266. * @v nlines number of lines
  267. * @v ncols number of columns
  268. * @v begin_y column origin
  269. * @v begin_x line origin
  270. * @ret *win return pointer to new window
  271. */
  272. WINDOW *newwin ( int nlines, int ncols, int begin_y, int begin_x ) {
  273. WINDOW *win = calloc( 1, sizeof(WINDOW) );
  274. win->ori_y = begin_y;
  275. win->ori_x = begin_x;
  276. win->height = nlines;
  277. win->width = ncols;
  278. win->scr = stdscr->scr;
  279. win->parent = NULL;
  280. win->child = NULL;
  281. return win;
  282. }
  283. /**
  284. * Return the attribute used for the soft function keys
  285. *
  286. * @ret attrs the current attributes of the soft function keys
  287. */
  288. attr_t slk_attr ( void ) {
  289. return ( slks == NULL ? 0 : slks->attrs );
  290. }
  291. /**
  292. * Turn off soft function key attributes
  293. *
  294. * @v attrs attribute bit mask
  295. * @ret rc return status code
  296. */
  297. int slk_attroff ( const chtype attrs ) {
  298. if ( slks == NULL )
  299. return ERR;
  300. slks->attrs &= ~( attrs & A_ATTRIBUTES );
  301. return OK;
  302. }
  303. /**
  304. * Turn on soft function key attributes
  305. *
  306. * @v attrs attribute bit mask
  307. * @ret rc return status code
  308. */
  309. int slk_attron ( const chtype attrs ) {
  310. if ( slks == NULL )
  311. return ERR;
  312. slks->attrs |= ( attrs & A_ATTRIBUTES );
  313. return OK;
  314. }
  315. /**
  316. * Set soft function key attributes
  317. *
  318. * @v attrs attribute bit mask
  319. * @ret rc return status code
  320. */
  321. int slk_attrset ( const chtype attrs ) {
  322. if ( slks == NULL )
  323. return ERR;
  324. slks->attrs = ( attrs & A_ATTRIBUTES );
  325. return OK;
  326. }
  327. /**
  328. * Turn off soft function key attributes
  329. *
  330. * @v attrs attribute bit mask
  331. * @v *opts undefined (for future implementation)
  332. * @ret rc return status code
  333. */
  334. int slk_attr_off ( const attr_t attrs, void *opts __unused ) {
  335. return slk_attroff( attrs );
  336. }
  337. /**
  338. * Turn on soft function key attributes
  339. *
  340. * @v attrs attribute bit mask
  341. * @v *opts undefined (for future implementation)
  342. * @ret rc return status code
  343. */
  344. int slk_attr_on ( attr_t attrs, void *opts __unused ) {
  345. return slk_attron( attrs );
  346. }
  347. /**
  348. * Set soft function key attributes
  349. *
  350. * @v attrs attribute bit mask
  351. * @v colour_pair_number colour pair integer
  352. * @v *opts undefined (for future implementation)
  353. * @ret rc return status code
  354. */
  355. int slk_attr_set ( const attr_t attrs, short colour_pair_number,
  356. void *opts __unused ) {
  357. if ( slks == NULL )
  358. return ERR;
  359. if ( ( unsigned short )colour_pair_number > COLORS )
  360. return ERR;
  361. slks->attrs = ( (unsigned short)colour_pair_number << CPAIR_SHIFT ) |
  362. ( attrs & A_ATTRIBUTES );
  363. return OK;
  364. }
  365. /**
  366. * Clear the soft function key labels from the screen
  367. *
  368. * @ret rc return status code
  369. */
  370. int slk_clear ( void ) {
  371. if ( slks == NULL )
  372. return ERR;
  373. wmove(stdscr,stdscr->height-1,0);
  374. wclrtoeol(stdscr);
  375. return 0;
  376. }
  377. /**
  378. * Initialise the soft function keys
  379. *
  380. * @v fmt format of keys
  381. * @ret rc return status code
  382. */
  383. int slk_init ( int fmt ) {
  384. if ( (unsigned)fmt > 3 ) {
  385. return ERR;
  386. }
  387. slks = malloc(sizeof(struct _softlabelkeys));
  388. slks->attrs = A_DEFAULT;
  389. slks->fmt = fmt;
  390. slks->maxlablen = 5;
  391. return OK;
  392. }
  393. /**
  394. * Return the label for the specified soft key
  395. *
  396. * @v labnum soft key identifier
  397. * @ret label return label
  398. */
  399. char* slk_label ( int labnum ) {
  400. if ( slks == NULL )
  401. return NULL;
  402. return slks->fkeys[labnum].label;
  403. }
  404. /**
  405. * Restore soft function key labels to the screen
  406. *
  407. * @ret rc return status code
  408. */
  409. int slk_restore ( void ) {
  410. if ( slks == NULL )
  411. return ERR;
  412. return OK;
  413. }
  414. /**
  415. * Configure specified soft key
  416. *
  417. * @v labnum soft label position to configure
  418. * @v *label string to use as soft key label
  419. * @v fmt justification format of label
  420. * @ret rc return status code
  421. */
  422. int slk_set ( int labnum, const char *label, int fmt ) {
  423. if ( slks == NULL )
  424. return ERR;
  425. if ( labnum == 0 || (unsigned)labnum > 12 )
  426. return ERR;
  427. if ( (unsigned)fmt >= 3 )
  428. return ERR;
  429. if ( strlen(label) > slks->maxlablen )
  430. return ERR;
  431. strcpy( slks->fkeys[labnum].label, label );
  432. slks->fkeys[labnum].fmt = fmt;
  433. return OK;
  434. }
  435. struct printw_context {
  436. struct printf_context ctx;
  437. WINDOW *win;
  438. };
  439. static void _printw_handler ( struct printf_context *ctx, unsigned int c ) {
  440. struct printw_context *wctx =
  441. container_of ( ctx, struct printw_context, ctx );
  442. _wputch( wctx->win, c | wctx->win->attrs, WRAP );
  443. }
  444. /**
  445. * Print formatted output in a window
  446. *
  447. * @v *win subject window
  448. * @v *fmt formatted string
  449. * @v varglist argument list
  450. * @ret rc return status code
  451. */
  452. int vw_printw ( WINDOW *win, const char *fmt, va_list varglist ) {
  453. struct printw_context wctx = {
  454. .win = win,
  455. .ctx = { .handler = _printw_handler, },
  456. };
  457. vcprintf ( &(wctx.ctx), fmt, varglist );
  458. return OK;
  459. }
  460. /**
  461. * Add a single-byte character and rendition to a window and advance
  462. * the cursor
  463. *
  464. * @v *win window to be rendered in
  465. * @v ch character to be added at cursor
  466. * @ret rc return status code
  467. */
  468. int waddch ( WINDOW *win, const chtype ch ) {
  469. _wputch( win, ch, WRAP );
  470. return OK;
  471. }
  472. /**
  473. * Add string of single-byte characters and renditions to a window
  474. *
  475. * @v *win window to be rendered in
  476. * @v *chstr pointer to first chtype in "string"
  477. * @v n max number of chars from chstr to render
  478. * @ret rc return status code
  479. */
  480. int waddchnstr ( WINDOW *win, const chtype *chstr, int n ) {
  481. struct cursor_pos pos;
  482. _store_curs_pos( win, &pos );
  483. _wputchstr( win, chstr, NOWRAP, n );
  484. _restore_curs_pos( win, &pos );
  485. return OK;
  486. }
  487. /**
  488. * Add string of single-byte characters to a window
  489. *
  490. * @v *win window to be rendered in
  491. * @v *str standard c-style string
  492. * @v n max number of chars from string to render
  493. * @ret rc return status code
  494. */
  495. int waddnstr ( WINDOW *win, const char *str, int n ) {
  496. _wputstr( win, str, WRAP, n );
  497. return OK;
  498. }
  499. /**
  500. * Turn off attributes in a window
  501. *
  502. * @v win subject window
  503. * @v attrs attributes to enable
  504. * @ret rc return status code
  505. */
  506. int wattroff ( WINDOW *win, int attrs ) {
  507. win->attrs &= ~attrs;
  508. return OK;
  509. }
  510. /**
  511. * Turn on attributes in a window
  512. *
  513. * @v win subject window
  514. * @v attrs attributes to enable
  515. * @ret rc return status code
  516. */
  517. int wattron ( WINDOW *win, int attrs ) {
  518. win->attrs |= attrs;
  519. return OK;
  520. }
  521. /**
  522. * Set attributes in a window
  523. *
  524. * @v win subject window
  525. * @v attrs attributes to enable
  526. * @ret rc return status code
  527. */
  528. int wattrset ( WINDOW *win, int attrs ) {
  529. win->attrs = ( attrs | ( win->attrs & A_COLOR ) );
  530. return OK;
  531. }
  532. /**
  533. * Get attributes and colour pair information
  534. *
  535. * @v *win window to obtain information from
  536. * @v *attrs address in which to store attributes
  537. * @v *pair address in which to store colour pair
  538. * @v *opts undefined (for future implementation)
  539. * @ret rc return status cude
  540. */
  541. int wattr_get ( WINDOW *win, attr_t *attrs, short *pair,
  542. void *opts __unused ) {
  543. *attrs = win->attrs & A_ATTRIBUTES;
  544. *pair = (short)(( win->attrs & A_COLOR ) >> CPAIR_SHIFT);
  545. return OK;
  546. }
  547. /**
  548. * Turn off attributes in a window
  549. *
  550. * @v *win subject window
  551. * @v attrs attributes to toggle
  552. * @v *opts undefined (for future implementation)
  553. * @ret rc return status code
  554. */
  555. int wattr_off ( WINDOW *win, attr_t attrs,
  556. void *opts __unused ) {
  557. wattroff( win, attrs );
  558. return OK;
  559. }
  560. /**
  561. * Turn on attributes in a window
  562. *
  563. * @v *win subject window
  564. * @v attrs attributes to toggle
  565. * @v *opts undefined (for future implementation)
  566. * @ret rc return status code
  567. */
  568. int wattr_on ( WINDOW *win, attr_t attrs,
  569. void *opts __unused ) {
  570. wattron( win, attrs );
  571. return OK;
  572. }
  573. /**
  574. * Set attributes and colour pair information in a window
  575. *
  576. * @v *win subject window
  577. * @v attrs attributes to set
  578. * @v cpair colour pair to set
  579. * @v *opts undefined (for future implementation)
  580. * @ret rc return status code
  581. */
  582. int wattr_set ( WINDOW *win, attr_t attrs, short cpair,
  583. void *opts __unused ) {
  584. wattrset( win, attrs | ( ( (unsigned short)cpair ) << CPAIR_SHIFT ) );
  585. return OK;
  586. }
  587. /**
  588. * Draw borders from single-byte characters and renditions around a
  589. * window
  590. *
  591. * @v *win window to be bordered
  592. * @v ls left side
  593. * @v rs right side
  594. * @v ts top
  595. * @v bs bottom
  596. * @v tl top left corner
  597. * @v tr top right corner
  598. * @v bl bottom left corner
  599. * @v br bottom right corner
  600. * @ret rc return status code
  601. */
  602. int wborder ( WINDOW *win, chtype ls, chtype rs,
  603. chtype ts, chtype bs, chtype tl,
  604. chtype tr, chtype bl, chtype br ) {
  605. wmove(win,0,0);
  606. _wputch(win,tl,WRAP);
  607. while ( ( win->width - 1 ) - win->curs_x ) {
  608. _wputch(win,ts,WRAP);
  609. }
  610. _wputch(win,tr,WRAP);
  611. while ( ( win->height - 1 ) - win->curs_y ) {
  612. _wputch(win,ls,WRAP);
  613. wmove(win,win->curs_y,(win->width)-1);
  614. _wputch(win,rs,WRAP);
  615. }
  616. _wputch(win,bl,WRAP);
  617. while ( ( win->width -1 ) - win->curs_x ) {
  618. _wputch(win,bs,WRAP);
  619. }
  620. _wputch(win,br,NOWRAP); /* do not wrap last char to leave
  621. cursor in last position */
  622. return OK;
  623. }
  624. /**
  625. * Clear a window to the bottom
  626. *
  627. * @v *win subject window
  628. * @ret rc return status code
  629. */
  630. int wclrtobot ( WINDOW *win ) {
  631. struct cursor_pos pos;
  632. _store_curs_pos( win, &pos );
  633. do {
  634. _wputch( win, (unsigned)' ', WRAP );
  635. } while ( win->curs_y + win->curs_x );
  636. _restore_curs_pos( win, &pos );
  637. return OK;
  638. }
  639. /**
  640. * Clear a window to the end of the current line
  641. *
  642. * @v *win subject window
  643. * @ret rc return status code
  644. */
  645. int wclrtoeol ( WINDOW *win ) {
  646. struct cursor_pos pos;
  647. _store_curs_pos( win, &pos );
  648. while ( ( win->curs_y - pos.y ) == 0 ) {
  649. _wputch( win, (unsigned)' ', WRAP );
  650. }
  651. _restore_curs_pos( win, &pos );
  652. return OK;
  653. }
  654. /**
  655. * Set colour pair for a window
  656. *
  657. * @v *win subject window
  658. * @v colour_pair_number colour pair integer
  659. * @v *opts undefined (for future implementation)
  660. * @ret rc return status code
  661. */
  662. int wcolour_set ( WINDOW *win, short colour_pair_number,
  663. void *opts __unused ) {
  664. if ( ( unsigned short )colour_pair_number > COLORS )
  665. return ERR;
  666. win->attrs = ( (unsigned short)colour_pair_number << CPAIR_SHIFT ) |
  667. ( win->attrs & A_ATTRIBUTES );
  668. return OK;
  669. }
  670. /**
  671. * Delete character under the cursor in a window
  672. *
  673. * @v *win subject window
  674. * @ret rc return status code
  675. */
  676. int wdelch ( WINDOW *win ) {
  677. struct cursor_pos pos;
  678. _store_curs_pos( win, &pos );
  679. _wputch( win, (unsigned)' ', NOWRAP );
  680. _restore_curs_pos( win, &pos );
  681. return OK;
  682. }
  683. /**
  684. * Delete line under a window's cursor
  685. *
  686. * @v *win subject window
  687. * @ret rc return status code
  688. */
  689. int wdeleteln ( WINDOW *win ) {
  690. /* let's just set the cursor to the beginning of the line and
  691. let wclrtoeol do the work :) */
  692. wmove( win, win->curs_y, 0 );
  693. wclrtoeol( win );
  694. return OK;
  695. }
  696. /**
  697. * Create a horizontal line in a window
  698. *
  699. * @v *win subject window
  700. * @v ch rendition and character
  701. * @v n max number of chars (wide) to render
  702. * @ret rc return status code
  703. */
  704. int whline ( WINDOW *win, chtype ch, int n ) {
  705. struct cursor_pos pos;
  706. _store_curs_pos ( win, &pos );
  707. while ( ( win->curs_x - win->width ) && n-- ) {
  708. _wputch ( win, ch, NOWRAP );
  709. }
  710. _restore_curs_pos ( win, &pos );
  711. return OK;
  712. }
  713. /**
  714. * Print formatted output to a window
  715. *
  716. * @v *win subject window
  717. * @v *fmt formatted string
  718. * @v ... string arguments
  719. * @ret rc return status code
  720. */
  721. int wprintw ( WINDOW *win, const char *fmt, ... ) {
  722. va_list args;
  723. int i;
  724. va_start ( args, fmt );
  725. i = vw_printw ( win, fmt, args );
  726. va_end ( args );
  727. return i;
  728. }
  729. /**
  730. * Create a vertical line in a window
  731. *
  732. * @v *win subject window
  733. * @v ch rendition and character
  734. * @v n max number of lines to render
  735. * @ret rc return status code
  736. */
  737. int wvline ( WINDOW *win, chtype ch, int n ) {
  738. struct cursor_pos pos;
  739. _store_curs_pos ( win, &pos );
  740. while ( ( win->curs_y - win->height ) && n-- ) {
  741. _wputch ( win, ch, NOWRAP );
  742. wmove( win, ++(win->curs_y), pos.x);
  743. }
  744. _restore_curs_pos ( win, &pos );
  745. return OK;
  746. }