home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 388_01 / curses / curses.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-24  |  8.6 KB  |  515 lines

  1. /*
  2.  * curses.c    
  3.  *
  4.  * Stdscr Curses for PC Class Machines.
  5.  *
  6.  * Copyright 1990, 1993 by Anthony Howe.  All rights reserved.  No warranty.
  7.  *
  8.  *
  9.  * DESCRIPTION:
  10.  * This is a quick and dirty curses.  It assumes that only stdscr is
  11.  * used and so writes directly to the screen via the bios rather than 
  12.  * wait for a refresh().
  13.  */
  14.  
  15. #include <dos.h>
  16. #include <ctype.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include "curses.h"
  20. #include "unctrl.h"
  21.  
  22. #define ISFUNCKEY(x)    (0x100 <= (x))
  23.  
  24. SCREEN _tty;
  25. WINDOW _stdscr;
  26. chtype A_NORMAL;
  27. chtype A_REVERSE;
  28.  
  29. WINDOW *
  30. initscr()
  31. {
  32.     int i;
  33.  
  34.     _tty.mode = GetVideoMode();
  35.     _tty.page = GetDisplayPage();
  36.     _stdscr.mcol = _tty.width = GetScreenWidth();
  37.     
  38.     switch (_tty.mode) {
  39.     case 0:
  40.     case 1:
  41.     case 2:
  42.     case 3:
  43.         /* Common colour modes. */
  44.         _stdscr.mrow = _tty.height = SCREEN_HEIGHT;
  45.         _tty.seg = 0xb800;
  46.         break;
  47.     case 7:
  48.         /* Common monochrome mode. */
  49.         _stdscr.mrow = _tty.height = SCREEN_HEIGHT;
  50.         _tty.seg = 0xb000;
  51.         break;
  52.     default:
  53.         return (NULL);
  54.     }
  55.  
  56.     /* Fetch screen attributes from bottom-left corner. */
  57.     mvcur(-1, -1, _tty.height-1, 0);
  58.     A_NORMAL = GetChtype(_tty.page) & A_ATTRIBUTES;
  59.     A_REVERSE = ((A_NORMAL & 0x0700) << 4) | ((A_NORMAL & 0xf000) >> 4);
  60.  
  61.     _stdscr.attr = A_NORMAL;
  62.     _stdscr.back = A_NORMAL | ' ';
  63.     _stdscr.flags |=  _FULLWIN;
  64.     _stdscr.row = _stdscr.col = _stdscr.brow = _stdscr.bcol = 0;
  65.  
  66.     /* Create a dynamic array. */
  67.     _stdscr.display = (chtype far **) malloc
  68.         (_tty.height * sizeof (chtype far *)
  69.     );
  70.     if (_stdscr.display == NULL)
  71.         return (NULL);
  72.  
  73.     _stdscr.display[0] = MK_FP(_tty.seg, 0);
  74.     _stdscr.flags |= _MEMMAP;
  75.  
  76.     for (i = 1; i < LINES; ++i) 
  77.         _stdscr.display[i] = _stdscr.display[i-1] + _tty.width;
  78.  
  79.     clear();
  80.     echo();
  81.     nl();
  82.     scrollok(stdscr, FALSE);
  83.     return (&_stdscr);
  84. }
  85.  
  86. int
  87. addch(c)
  88. chtype c;
  89. {
  90.     int n;
  91.  
  92.     switch (c) {
  93.     case '\t':
  94.         n = 8-(_stdscr.col&7);
  95.         while (0 < n--)
  96.             addch(' ');
  97.         break;
  98.     case '\r':
  99.         _stdscr.col = 0;
  100.         break;
  101.     case '\n':
  102.         clrtoeol();
  103.         if (_tty._crlf)
  104.             _stdscr.col = 0;
  105.         ++_stdscr.row;
  106.         break;
  107.     case '\b':
  108.         if (0 < _stdscr.col)
  109.             --_stdscr.col;
  110.         else if (0 < _stdscr.row)
  111.             --_stdscr.row;
  112.         break;
  113.     default:
  114.         c |= _stdscr.attr;
  115.         if (_stdscr.display[_stdscr.row][_stdscr.col] != c) { 
  116.             _stdscr.display[_stdscr.row][_stdscr.col] = c;
  117.         }
  118.         ++_stdscr.col;
  119.     }
  120.     if (COLS <= _stdscr.col) {
  121.         _stdscr.col = 0;
  122.         ++_stdscr.row;
  123.     }
  124.     if (LINES <= _stdscr.row && (_stdscr.flags & _SCROLLOK)) {
  125.         /* Scroll up one line. */
  126.         ScrollUp(1, _stdscr.back, 0, 0, LINES, COLS);
  127.         move(LINES-1, 0);
  128.         clrtoeol();
  129.     }
  130.  
  131.     return (OK);
  132. }
  133.  
  134. int
  135. addnstr(s, n)
  136. char *s;
  137. int n;
  138. {
  139.     if (n < 0)
  140.         n = strlen(s);
  141.     while (0 < n-- && *s)
  142.         addch(*s++);
  143.     while (0 < n--)
  144.         addch(' ');
  145.     return (OK);
  146. }
  147.  
  148. #ifdef __STDC__
  149. int
  150. printw(char *fmt, ...)
  151. #else
  152. int
  153. printw(fmt)
  154. char *fmt;
  155. #endif /* __STDC__ */
  156. {
  157.     int i;
  158.     va_list args;
  159.     va_start(args, fmt);
  160.     i = vwprintw(stdscr, fmt, args);
  161.     va_end(args);
  162.     return (i);
  163. }
  164.  
  165. #ifdef __STDC__
  166. int
  167. mvprintw(int row, int col, char *fmt, ...)
  168. #else
  169. int
  170. mvprintw(row, col, fmt)
  171. int row, col;
  172. char *fmt;
  173. #endif /* __STDC__ */
  174. {
  175.     int i;
  176.     va_list args;
  177.     move(row, col);
  178.     va_start(args, fmt);
  179.     i = vwprintw(stdscr, fmt, args);
  180.     va_end(args);
  181.     return (i);
  182. }
  183.  
  184. int 
  185. vwprintw(w, fmt, args)
  186. WINDOW *w;
  187. char *fmt;
  188. va_list args;
  189. {
  190.     int i;
  191.     char buffer[BUFSIZ];
  192.     i = vsprintf(buffer, fmt, args);
  193.     addstr(buffer);
  194.     return (i);
  195. }
  196.  
  197. int
  198. beep()
  199. {
  200.     AddChar(_tty.page, 7);
  201.     mvcur(-1, -1, _stdscr.row, _stdscr.col);
  202.     return (OK);
  203. }
  204.  
  205. int
  206. endwin()
  207. {
  208.     chtype blank = ' ' | A_NORMAL;
  209.     mvcur(-1, -1, _tty.height-1, 0);
  210.     PutChtype(_tty.page, blank);
  211.     return (OK);
  212. }
  213.  
  214. int
  215. clrtobot()
  216. {
  217.     int row, col;
  218.  
  219.     if (LINES <= _stdscr.row)
  220.         return (ERR);
  221.     getyx(stdscr, row, col);
  222.     do {
  223.         if (clrtoeol() == ERR)
  224.             return (ERR);
  225.         _stdscr.col = 0;
  226.     } while (++_stdscr.row < LINES);
  227.     move(row, col);
  228.     return (OK);
  229. }
  230.  
  231. int
  232. clrtoeol()
  233. {
  234.     register int i;
  235.     register chtype far *ptr;
  236.  
  237.     if (COLS <= _stdscr.col)
  238.         return (ERR);
  239.     ptr = &_stdscr.display[_stdscr.row][_stdscr.col];
  240.     for (i = _stdscr.col; i < COLS; ++i, ++ptr) { 
  241.         if (*ptr != _stdscr.back) {
  242.             for (; i < COLS; ++i, ++ptr)
  243.                 *ptr = _stdscr.back;
  244.             break;
  245.         }
  246.     }
  247.     return (OK);
  248.  
  249. int
  250. refresh()
  251. {
  252.     if (!(_stdscr.flags & _LEAVEOK))
  253.         mvcur(-1, -1, _stdscr.row, _stdscr.col);
  254.     _stdscr.flags &= ~_CLEAROK;
  255.     return (OK);
  256. }
  257.  
  258. int
  259. clearok(w, bf)
  260. WINDOW *w;
  261. int bf;
  262. {
  263.     if (bf)
  264.         _stdscr.flags |= _CLEAROK;
  265.     else
  266.         _stdscr.flags &= ~_CLEAROK;
  267.     return (OK);
  268. }
  269.  
  270. int
  271. idlok(w, bf)
  272. WINDOW *w;
  273. int bf;
  274. {
  275.     if (bf)
  276.         _stdscr.flags |= _IDLOK;
  277.     else
  278.         _stdscr.flags &= ~_IDLOK;
  279.     return (OK);
  280. }
  281.  
  282. int
  283. scrollok(w, bf)
  284. WINDOW *w;
  285. int bf;
  286. {
  287.     if (bf)
  288.         _stdscr.flags |= _SCROLLOK;
  289.     else
  290.         _stdscr.flags &= ~_SCROLLOK;
  291.     return (OK);
  292. }
  293.  
  294. int
  295. keypad(w, bf)
  296. WINDOW *w;
  297. int bf;
  298. {
  299.     if (bf)
  300.         _stdscr.flags |= _KEYPAD;
  301.     else
  302.         _stdscr.flags &= ~_KEYPAD;
  303.     return (OK);
  304. }
  305.  
  306. int
  307. leaveok(w, bf)
  308. WINDOW *w;
  309. int bf;
  310. {
  311.     if (bf)
  312.         _stdscr.flags |= _LEAVEOK;
  313.     else
  314.         _stdscr.flags &= ~_LEAVEOK;
  315.     return (OK);
  316. }
  317.  
  318. int
  319. getch()
  320. {
  321.     KEY c;
  322.     refresh();
  323.     if (_stdscr.flags & _KEYPAD) {
  324.         c.val = GetKey();
  325.         if (c.key.ascii == 0) {
  326.             c.key.ascii = c.key.extended;
  327.             c.key.extended = 0x01;
  328.         } else {
  329.             c.key.extended = 0;
  330.             if (_tty._echo)
  331.                 addch(c.key.ascii);
  332.         }
  333.     } else {
  334.         static int scancode;
  335.         if (scancode != 0) {
  336.             /* Return previous saved scancode. */
  337.             c.val = scancode;
  338.             scancode = 0;
  339.         } else {
  340.             c.val = GetKey();
  341.             if (c.key.ascii == 0) {
  342.                 /* Remember scancode for next call 
  343.                  * of getch().  Return ^[ this call.
  344.                  */
  345.                 c.key.ascii = 0x1b;
  346.                 scancode = c.key.extended;
  347.             }
  348.             c.key.extended = 0;
  349.             if (_tty._echo)
  350.                 addch(c.key.ascii);
  351.         }
  352.     }
  353.     return (c.val);
  354. }
  355.  
  356. char *
  357. unctrl(ch)
  358. int ch;
  359. {
  360.     static char buf[5];
  361.     static char *ctrls[] = {
  362.         "^?",
  363.         "^@", "^A", "^B", "^C", "^D", "^E", "^F", "^G", 
  364.         "^H", "^I", "^J", "^K", "^L", "^M", "^N", "^O", 
  365.         "^P", "^Q", "^R", "^S", "^T", "^U", "^V", "^W", 
  366.         "^X", "^Y", "^Z", "^[", "^\\", "^]", "^^", "^_"
  367.     };
  368.     if (ch == 0x7f) {
  369.         return (ctrls[0]);
  370.     } else if (0x7f < ch) {
  371.         (void) sprintf(buf, "\\%03o", ch);
  372.     } else if (iscntrl(ch)) {
  373.         return (ctrls[ch+1]);
  374.     } else {
  375.         *buf = ch;
  376.         buf[1] = '\0';
  377.     } 
  378.     return (buf);
  379. }
  380.  
  381. typedef struct key_entry_t {
  382.     int code;
  383.     int (*func)(void);
  384. } key_entry_t;
  385.  
  386. static int fld_done(void);
  387. static int fld_erase(void);
  388. static int fld_kill(void);
  389. static int fld_left(void);
  390. static int fld_insert(void);
  391.  
  392. static key_entry_t table[] = {
  393.     { '\b', fld_erase },
  394.     { CTRL('x'), fld_kill },
  395.     { '\r', fld_done },
  396.     { '\n', fld_done },
  397.     { KEY_LEFT, fld_erase },
  398.     { KEY_BACKSPACE, fld_erase },    
  399.     { -1, fld_insert }
  400. };
  401.  
  402. static int fld_row;
  403. static int fld_col;
  404. static int fld_key;
  405. static int fld_echo;
  406. static int fld_index;
  407. static int fld_length;
  408. static char *fld_buffer;
  409.  
  410. int
  411. getnstr(buf, len)
  412. char *buf;
  413. int len;
  414. {
  415.     key_entry_t *k;
  416.  
  417.     fld_index = 0;
  418.     fld_buffer = buf;
  419.     fld_length = len < 0 ? COLS : len;
  420.     if (--fld_length < 1)
  421.         return (ERR);
  422.     getyx(stdscr, fld_row, fld_col);
  423.     fld_echo = _tty._echo;
  424.     noecho();
  425.  
  426.     for (;;) {
  427.         fld_key = getch();
  428.         for (k = table; k->code != -1 && k->code != fld_key; ++k)
  429.             ;
  430.         if (k->func != NULL && !(k->func)()) {
  431.             fld_buffer[fld_index] = '\0';
  432.             break;
  433.         }
  434.     }
  435.  
  436.     if (fld_echo)
  437.         echo();
  438.     return (OK);
  439. }
  440.     
  441. static int
  442. fld_done()
  443. {
  444.     return (FALSE);
  445. }
  446.  
  447. static int
  448. fld_left()
  449. {
  450.     int row, col, max_row, max_col;
  451.  
  452.     getyx(stdscr, row, col);
  453.     getmaxyx(stdscr, max_row, max_col);
  454.     if (0 < fld_index) {
  455.         --fld_index;
  456.         /* Assume that if 0 < fld_index then fld_row <= row 
  457.          * and fld_col < col.  So when fld_index == 0, then
  458.          * fld_row == row and fld_col == col. 
  459.          */
  460.         if (0 < col) {
  461.             --col;
  462.         } else if (0 < row) {
  463.             /* Handle reverse line wrap. */
  464.             --row;
  465.             col = max_col-1;
  466.         }
  467.         move(row, col);
  468.     }
  469.     return (TRUE);
  470. }
  471.  
  472. static int
  473. fld_erase()
  474. {
  475.     int row, col;
  476.  
  477.     if (0 < fld_index) {
  478.         fld_left();
  479.         getyx(stdscr, row, col);
  480.         addch(' ');
  481.         move(row, col);
  482.         fld_buffer[fld_index] = '\0';
  483.     }
  484.     return (TRUE);
  485. }
  486.  
  487. static int
  488. fld_kill()
  489. {
  490.     move(fld_row, fld_col);
  491.     while (0 < fld_index--)
  492.         addch(' ');
  493.     move(fld_row, fld_col);
  494.     fld_buffer[0] = '\0';
  495.     fld_index = 0;
  496.     return    (TRUE);
  497. }
  498.  
  499. static int
  500. fld_insert()
  501. {
  502.     if (fld_index < fld_length) {
  503.         if (!ISFUNCKEY(fld_key)) {
  504.             fld_buffer[fld_index++] = fld_key;
  505.             if (fld_echo)
  506.                 addch(fld_key);
  507.         } else {
  508.             beep();
  509.         }
  510.     }
  511.     return (fld_index < fld_length);
  512. }
  513.  
  514.