home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #18 / NN_1992_18.iso / spool / comp / lang / tcl / 1233 < prev    next >
Encoding:
Text File  |  1992-08-19  |  16.8 KB  |  645 lines

  1. Path: sparky!uunet!zaphod.mps.ohio-state.edu!wupost!waikato.ac.nz!comp.vuw.ac.nz!gnat
  2. Newsgroups: comp.lang.tcl
  3. Subject: tcl_curses.c New Version
  4. Message-ID: <GNAT.92Aug20182942@kauri.kauri.vuw.ac.nz>
  5. From: gnat@kauri.vuw.ac.nz (Nathan Torkington)
  6. Date: Thu, 20 Aug 1992 06:29:42 GMT
  7. Sender: news@comp.vuw.ac.nz (News Admin)
  8. Distribution: comp
  9. Organization: Contract to CSC, Victoria Uni, Wellington, New Zealand
  10. Nntp-Posting-Host: kauri.vuw.ac.nz
  11. Lines: 632
  12.  
  13. Here is both the README and the C source for tcl_curses.c, as
  14. originally written by Poul-Henning Kamp, phk@data.fls.dk, and
  15. subsequently hacked at by Nathan Torkington, gnat@kauri.vuw.ac.nz.
  16.  
  17. This is a way-cool idea, and if anyone wants to hack at it then
  18. I'd love to have more useful things added (a smarter getstr, etc).
  19. I'm planning on using it a lot in the future.  My comments in the
  20. readme are marked with a [N2].
  21.  
  22. --begin README
  23. Tcl_curses -- version 0.01 -- 19mar92 -- phk@data.fls.dk
  24.               version 0.02 -- 20Aug92 -- gnat@kauri.vuw.ac.nz [N2]
  25. =============================================================
  26.  
  27.  
  28. Introduction:
  29. -------------
  30. I needed a curses interface, so I made one, it's not so hard after all,
  31. but on the other hand it's not yet complete, most of the input it still 
  32. missing.
  33.  
  34. Some of the functions in curses has no reason to live in a Tcl interface, 
  35. printw() for instance, and scanw() would be a hell to implement too, so
  36. they will probably be better off if made using Tcl format &c &c.
  37.  
  38. Having added getstr, I find some problems.  Determination of string
  39. length is a problem.  Currently you must give a maximum length of the
  40. string, beforehand.  No enforcement of this is done, however. [N2]
  41.  
  42. How to use:
  43. -----------
  44.  
  45. call the 'C' function curses_init(interp) to initialize the curses interface.
  46.  
  47. This will define a Tcl function named 'curses' and a variable called
  48. 'curses_debug'.
  49.  
  50. Setting a non-zero value in curses_debug will send debugging output to stderr.
  51.  
  52. The curses function is for general operations, things like initscr, endwin
  53. and newwin.
  54.  
  55. Each window created (including stdscr by initscr) creates a function named
  56. after that window, which is used for all operations on that window
  57.  
  58. Example Tcl code:
  59. -----------------
  60.  
  61.     # initialize the curses(3) package, create stdscr function
  62.     curses initscr
  63.     curses mode noecho cbreak
  64.  
  65.     # move to line #1, pos#1, and addstr() a silly text
  66.     stdscr -m 0 0 -a so addstr "Outstanding attempt to print text !"
  67.  
  68.     # move to line #3, pos#2, and addstr() a silly text in bold
  69.     stdscr -m 2 1 -a bold addstr "Bold attempt to print text !"
  70.  
  71.     # move to line #4, pos#30, and addstr() a silly text in reverse
  72.     stdscr -m 3 29 -a rev addstr "Reverse attempt to print text !"
  73.  
  74.     # reset the attributes
  75.     stdscr -a ""
  76.  
  77.     # update the screen
  78.     stdscr refresh
  79.  
  80.     curses newwin zap 5 8 10 20
  81.  
  82.     zap -m 0 0 addstr "Any key"
  83.     zap -m 1 0 addstr "Pressed"
  84.     zap -m 2 0 addstr "will be"
  85.     zap -m 3 0 addstr "here->"
  86.     zap -m 4 0 addstr "q exits"
  87.  
  88.     set ch " "
  89.     while {$ch!="q"} {
  90.         zap -m 3 6 refresh
  91.         set ch [zap getch]
  92.         zap -m 3 6 addstr "$ch"
  93.         }
  94.  
  95.     # goodbye
  96.     curses endwin
  97.  
  98.  
  99. Extent of implementation:
  100. -------------------------
  101.         curses initscr
  102.         curses endwin
  103.         curses mode [[no]cbreak] [[no]echo] [[no]raw] [[no]nl]
  104.     curses info
  105.         curses newwin <win> <nlin> <ncol> <begin_y> <begin_x>
  106.         <win> [-m <lin> <pos>]
  107.         <win> [-a <{|so|ul|rev|blink|dim|bold}*> ]
  108.         <win> addstr <string>
  109.     <win> getstr <maxstrlen>
  110.         <win> clrtoeol
  111.         <win> clrtobot
  112.         <win> refresh
  113.         <win> erase
  114.         <win> clear
  115.         <win> getch
  116.     <win> box [on | off]
  117.  
  118.  
  119. Reference:
  120. ----------
  121.         curses initscr
  122. Must be called before any further calls.
  123.         curses endwin
  124. Should be called to reset the terminal mode at the very end of the
  125. program.
  126.         curses mode [[no]cbreak] [[no]echo] [[no]raw] [[no]nl]
  127. Set the terminal mode options.  All options are binary, so noraw is
  128. the opposite of raw.
  129.     curses info
  130. Returns a string consisting of the current terminal mode options.  This
  131. string can later be fed to "curses mode" to reset the terminal mode.
  132.         curses newwin <win> <nlin> <ncol> <begin_y> <begin_x>
  133. Create a new win, <nlin>x<ncol> with top-left at <begin_x>,<begin_y>.
  134.         <win> [-m <lin> <pos>]
  135. Move.  Can be used inside other commands (eg "win -m 3 5 addstr foo").
  136.         <win> [-a <{|so|ul|rev|blink|dim|bold}*> ]
  137. Change attributes of text to be displayed.
  138.         <win> addstr <string>
  139. Write <string> to current position.
  140.     <win> getstr <maxstrlen>
  141. Return a string of up to <maxstrlen> characters, obtained from the user
  142. at current cursor position, in <win>.
  143.         <win> clrtoeol
  144. Clear end of current line.
  145.         <win> clrtobot
  146. Clear to end of <win>.
  147.         <win> refresh
  148. Redraw <win>.  You must call this to make the changes to windows visible.
  149.         <win> erase
  150. Copy blanks to every position in <win>.
  151.         <win> clear
  152. erase *and* redraw from scratch next time refresh is called.
  153.         <win> getch
  154. Return a character obtained from the user in <win>.
  155.     <win> box [on | off]
  156. Turn a border box for <win> on or off.  New windows have no border.
  157. Adding a border moves everything down and to the right by one character,
  158. and draws a border around the window.  Turning the border off moves the
  159. text up and to the left by one character.
  160.  
  161. Platforms:
  162. ----------
  163. I'm on a IBM RS6000/520 with AIX 3.1.7, should work on most machines,
  164. I'm on a SGI Iris 4D and had no problems.  [N2]
  165.  
  166. I know that BSD curses and SYSV curses are somewhat different, do we need
  167. ifdefs ?
  168.  
  169. Attribute stuff won't work with BSD curses, so probably #ifdefs will be
  170. needed.  But I won't use BSD curses at all, so I won't write them :-) [N2]
  171.  
  172. Future:
  173. -------
  174. Send bugs, patches, bug-fixes and suggestions to the keeper of the
  175. relevant section of the code.
  176.  
  177. gnat@kauri.vuw.ac.nz worked on:
  178.     getstr
  179.     mode
  180.     info
  181.     box
  182.  
  183. phk@data.fls.dk worked on:
  184.     the rest
  185.  
  186. --
  187. phk@data.fls.dk          || Welcome to the '92 Open European Hell:
  188. Poul-Henning Kamp      ||   A british cook, a german lover, an italian
  189. FLS DATA A/S          ||   cop, a french bank, a belgian chauffeur,
  190. Phone: (+45) 36 18 12 35  ||   a spanish engineer, a greek manager... &c &c
  191. Fax:   (+45) 36 18 12 18  ||   -- and a danish victim.    (Poul-Henning Kamp)
  192. --end README
  193.  
  194. --begin tcl_curses.c
  195. /* curses.c
  196.  * CURSES interface for TcL
  197.  * 
  198.  * Poul-Henning Kamp, phk@data.fls.dk
  199.  * 920318 0.00
  200.  * 920319 0.01
  201.  * 920819 0.02 -- NJT
  202.  */
  203.  
  204. #include <curses.h>
  205. #include <tcl.h>
  206. #include <tclHash.h>
  207.  
  208. static char *TraceDebug();
  209. static int CursesProc();
  210. static int WinProc();
  211.  
  212. typedef struct
  213.     {
  214.     int        debug;
  215.     int
  216.       nl,
  217.       cbreak,
  218.       raw,
  219.       echo;
  220.     WINDOW    *stdscr;
  221.     } t_cldat;
  222.  
  223. typedef struct
  224.     {
  225.     t_cldat    *cd;
  226.     int         wbox;
  227.     WINDOW    *win;
  228.     WINDOW      *border;
  229.     } t_cldat2;
  230.  
  231. /****************************************************************************
  232.  *
  233.  * curses_init(interp)
  234.  * ===================
  235.  * 
  236.  * Initialize the curses interface.
  237.  *
  238.  ****************************************************************************/
  239.  
  240. void
  241. curses_init(interp)
  242.     Tcl_Interp    *interp;
  243.     {
  244.     t_cldat *cd;
  245.  
  246.     cd = (t_cldat *)ckalloc(sizeof *cd);
  247.     memset((void*)cd,0,sizeof *cd);
  248.     Tcl_CreateCommand(interp,"curses",CursesProc,cd,0);
  249.     Tcl_SetVar(interp,"curses_debug","0",0);
  250.     Tcl_TraceVar(interp,"curses_debug",
  251.     TCL_TRACE_WRITES|TCL_TRACE_UNSETS,TraceDebug,cd);
  252.     }
  253.  
  254. static int
  255. Error(interp,win,where)
  256.     Tcl_Interp  *interp;
  257.     char *win;
  258.     char *where;
  259.     {
  260.     Tcl_AddErrorInfo(interp,"curses ");
  261.     Tcl_AddErrorInfo(interp,win);
  262.     Tcl_AddErrorInfo(interp," ");
  263.     Tcl_AddErrorInfo(interp,where);
  264.     Tcl_AddErrorInfo(interp,": failed");
  265.     return TCL_ERROR;
  266.     }
  267.  
  268. static char*
  269. TraceDebug(cd,interp,name1,name2,flags)
  270.     t_cldat *cd;
  271.     Tcl_Interp    *interp;
  272.     char *name1;
  273.     char *name2;
  274.     int flags;
  275.     {
  276.     cd->debug=0;
  277.     if(flags & TCL_TRACE_WRITES) 
  278.     cd->debug = 
  279.         atoi(Tcl_GetVar(interp,"curses_debug",flags&TCL_GLOBAL_ONLY));
  280.     if(flags & TCL_TRACE_UNSETS) 
  281.     Tcl_SetVar(interp,"curses_debug","0",flags&TCL_GLOBAL_ONLY);
  282.     if(flags & TCL_TRACE_DESTROYED)
  283.     Tcl_TraceVar(interp,"curses_debug",
  284.         TCL_TRACE_WRITES|TCL_TRACE_UNSETS,TraceDebug,cd);
  285.     fprintf(stderr,"CURSES: debug is now %d\n",cd->debug);
  286.     return 0;
  287.     }
  288.     
  289. static int
  290. CursesProc(cd,interp,argc,argv)
  291.     t_cldat *cd;
  292.     Tcl_Interp  *interp;
  293.     int argc;
  294.     char **argv;
  295.     {
  296.     int i;
  297.     Tcl_HashEntry *he;
  298.     t_cldat2 *cd2;
  299.  
  300.     if(cd->debug)
  301.     {
  302.     fprintf(stderr,"CURSES: CursesProc %d ",argc);
  303.     for(i=0;i<argc;i++)
  304.         fprintf(stderr,"{%s} ",argv[i]);
  305.     fprintf(stderr,"\n");
  306.     }
  307.  
  308.     if(!cd->stdscr)     /* Not yet initscr */
  309.     {
  310. /*XX curses initscr */
  311.     if(argc == 2 && !strcmp(argv[1],"initscr"))
  312.         {
  313.           WINDOW *w;
  314.           w = initscr();
  315.           if (!w)
  316.         return Error(interp,"<none>",argv[1]);
  317.           cd2 = (t_cldat2 *)ckalloc(sizeof *cd2);
  318.           memset((void*)cd2,0,sizeof *cd2);
  319.           cd2->cd=cd;
  320.           cd2->win=w;
  321.           cd2->border=NULL;
  322.           cd2->wbox=0;
  323.           cd->stdscr = cd2->win;
  324.           cd->nl=1;
  325.           cd->cbreak=0;
  326.           cd->echo=1;
  327.           cd->raw=1;
  328.           Tcl_CreateCommand(interp,"stdscr",WinProc,cd2,0);
  329.           return TCL_OK;
  330.         }
  331.     else
  332.         {
  333.         Tcl_AddErrorInfo(interp,"curses ");
  334.         Tcl_AddErrorInfo(interp,argv[1]);
  335.         Tcl_AddErrorInfo(interp,": must start by calling initscr");
  336.         return TCL_ERROR;
  337.         }
  338.     }
  339.     if(argc == 2 && *argv[1]== 'e' && !strcmp(argv[1],"endwin"))
  340. /*XX curses endwin */
  341.     {
  342.     if(endwin() == OK) return TCL_OK;
  343.     return Error(interp,"<none>",argv[1]);
  344.     }
  345.  
  346.  
  347.     if(argc > 2 && *argv[1]== 'm' && !strcmp(argv[1],"mode")) {
  348. /*XX curses mode <[no]cbreak> <[no]nl> <[no]echo> <[no]raw> */
  349.       argc --; argv ++;
  350.       while (argc > 1) {
  351.     if(*argv[1]== 'c' && !strcmp(argv[1],"cbreak"))
  352.       {
  353.         if (cd->cbreak || cbreak() == OK)
  354.           cd->cbreak = 1;
  355.         else
  356.           return Error(interp,"<none>",argv[1]);
  357.     }
  358.     else
  359.     if(*argv[1]== 'n' && !strcmp(argv[1],"nocbreak"))
  360.     {
  361.       if (!cd->cbreak || nocbreak() == OK)
  362.         cd->cbreak = 0;
  363.       else
  364.         return Error(interp,"<none>",argv[1]);
  365.     }
  366.     else
  367.     if(*argv[1]== 'e' && !strcmp(argv[1],"echo"))
  368.       {
  369.         if (cd->echo || echo() == OK)
  370.           cd->echo=1;
  371.         else
  372.           return Error(interp,"<none>",argv[1]);
  373.       }
  374.     else
  375.     if(*argv[1]== 'n' && !strcmp(argv[1],"noecho"))
  376.     {
  377.       if (!cd->echo || noecho() == OK)
  378.         cd->echo=0;
  379.       else
  380.         return Error(interp,"<none>",argv[1]);
  381.     }
  382.     else
  383.     if(*argv[1]== 'r' && !strcmp(argv[1],"raw"))
  384.       {
  385.         if (cd->raw || raw() == OK)
  386.           cd->raw=1;
  387.         else
  388.           return Error(interp,"<none>",argv[1]);
  389.       }
  390.     else
  391.     if(*argv[1]== 'n' && !strcmp(argv[1],"noraw"))
  392.       {
  393.         if (!cd->raw || noraw() == OK)
  394.           cd->raw=0;
  395.         else
  396.           return Error(interp,"<none>",argv[1]);
  397.       }
  398.     else
  399.     if(*argv[1]== 'n' && !strcmp(argv[1],"nl"))
  400.       {
  401.         if (cd->nl || nl() == OK)
  402.           cd->nl=1;
  403.         else
  404.           return Error(interp,"<none>",argv[1]);
  405.       }
  406.     else
  407.     if(*argv[1]== 'n' && !strcmp(argv[1],"nonl"))
  408.       {
  409.         if (!cd->nl || nonl() == OK)
  410.           cd->nl=0;
  411.         else
  412.           return Error(interp,"<none>",argv[1]);
  413.       }
  414.     else {
  415. fprintf(stderr, "%s %d\n", argv[1], argc);
  416.       Tcl_AddErrorInfo(interp, "curses ");
  417.       Tcl_AddErrorInfo(interp, argv[1]);
  418.       Tcl_AddErrorInfo(interp, ": Huh ?");
  419.       return TCL_ERROR;
  420.     }
  421.     
  422.     argv += 1; argc -= 1;
  423.       }
  424.       if (argc < 2)
  425.     return TCL_OK;
  426.     }
  427.  
  428.     if(argc == 2 && *argv[1]== 'i' && !strcmp(argv[1],"info"))
  429.       /*XX curses info */
  430.       { 
  431.     char buf[30];
  432.     sprintf(buf,"%s%s %s%s %s%s %s%s",  (cd->cbreak)?"":"no", "cbreak",
  433.         (cd->raw)?"":"no", "raw",
  434.         (cd->nl)?"":"no", "nl",
  435.         (cd->echo)?"":"no", "echo");
  436.     Tcl_SetResult(interp,buf,TCL_STATIC); 
  437.     return TCL_OK;
  438.       }
  439.     
  440.     if(argc == 7 && *argv[1]== 'n' && !strcmp(argv[1],"newwin"))
  441.       /*XX curses newwin <win> <nlin> <ncol> <begin_y> <begin_x> */
  442.       {
  443.     WINDOW *w;
  444.     w = newwin(atoi(argv[3]),atoi(argv[4]),atoi(argv[5]),atoi(argv[6]));
  445.     if (!w)
  446.       return Error(interp, argv[1], argv[2]);
  447.     cd2 = (t_cldat2 *)ckalloc(sizeof *cd2);
  448.     memset((void*)cd2,0,sizeof *cd2);
  449.     cd2->cd=cd;
  450.     cd2->border=NULL;
  451.     cd2->win=w;
  452.     cd2->wbox=0; /* by default, no border */
  453.     Tcl_CreateCommand(interp,argv[2],WinProc,cd2,0);
  454.     return TCL_OK;
  455.     }
  456.  
  457.     Tcl_AddErrorInfo(interp,"curses ");
  458.     Tcl_AddErrorInfo(interp,argv[1]);
  459.     Tcl_AddErrorInfo(interp,": Huh ?");
  460.     return TCL_ERROR;
  461.     }
  462.  
  463. static int
  464. WinProc(cd2,interp,argc,argv)
  465.     t_cldat2 *cd2;
  466.     Tcl_Interp  *interp;
  467.     int argc;
  468.     char **argv;
  469.     {
  470.     int i;
  471.     Tcl_HashEntry *he;
  472.     char *win = *argv;
  473.  
  474.     if(cd2->cd->debug)
  475.     {
  476.     fprintf(stderr,"CURSES: WinProc %d ",argc);
  477.     for(i=0;i<argc;i++)
  478.         fprintf(stderr,"{%s} ",argv[i]);
  479.     fprintf(stderr,"\n");
  480.     }
  481.     if(argc < 2)
  482.     {
  483.     Tcl_AddErrorInfo(interp,"curses ");
  484.     Tcl_AddErrorInfo(interp,win);
  485.     Tcl_AddErrorInfo(interp,": no args");
  486.     return TCL_ERROR;
  487.     }
  488.  
  489.     while(argc > 1 && *argv[1] == '-')
  490.     {
  491.     if(argc >= 4 && !strcmp(argv[1],"-m"))
  492. /*XX <win> [-m <lin> <pos>] */
  493.         {
  494.         if(OK != wmove(cd2->win,atoi(argv[2]),atoi(argv[3])))
  495.         Error(interp,win,argv[1]);
  496.         argv += 3; argc -= 3;
  497.         }
  498.     else if(argc >= 3 && !strcmp(argv[1],"-a"))
  499. /*XX <win> [-a <{|so|ul|rev|blink|dim|bold}*> ] */
  500.         {
  501.         char *s,*t;
  502.  
  503.         i=0;
  504.         for(t=argv[2];t && *t;t=s)
  505.         {
  506.         for(s=t;*s && !isspace(*s);s++)
  507.             ;
  508.         if(!*s)
  509.             s=0;
  510.         else
  511.             *s++ = '\0';
  512.         if(!strcmp(t,"so")) i |= A_STANDOUT;
  513.         else if(!strcmp(t,"ul")) i |= A_UNDERLINE;
  514.         else if(!strcmp(t,"rev")) i |= A_REVERSE;
  515.         else if(!strcmp(t,"blink")) i |= A_BLINK;
  516.         else if(!strcmp(t,"dim")) i |= A_DIM;
  517.         else if(!strcmp(t,"bold")) i |= A_BOLD;
  518.         else
  519.             {
  520.             Tcl_AddErrorInfo(interp,"curses ");
  521.             Tcl_AddErrorInfo(interp,win);
  522.             Tcl_AddErrorInfo(interp," ");
  523.             Tcl_AddErrorInfo(interp,argv[1]);
  524.             Tcl_AddErrorInfo(interp," ");
  525.             Tcl_AddErrorInfo(interp,t);
  526.             Tcl_AddErrorInfo(interp,": Huh ?");
  527.             return TCL_ERROR;
  528.             }
  529.         }
  530.         wattrset(cd2->win,i);
  531.         argv += 2; argc -= 2;
  532.         }
  533.     else
  534.         {
  535.         Tcl_AddErrorInfo(interp,"curses ");
  536.         Tcl_AddErrorInfo(interp,win);
  537.         Tcl_AddErrorInfo(interp," ");
  538.         Tcl_AddErrorInfo(interp,argv[1]);
  539.         Tcl_AddErrorInfo(interp,": Huh ?");
  540.         return TCL_ERROR;
  541.         }
  542.     }
  543.     if(argc == 1)
  544.     return TCL_OK;
  545.     if(argc == 3 && *argv[1]== 'b' && !strcmp(argv[1],"box"))
  546. /*XX box [on | off]*/
  547.       {
  548.     if(!strcmp(argv[2], "on")) {
  549.       if (cd2->wbox)
  550.         /* already on! */
  551.         return Error(interp, win, argv[1]);
  552.       /* not on, so make make border on */
  553.       cd2->wbox = 1;
  554.       cd2->border = cd2->win;
  555.       cd2->win=newwin(cd2->border->_maxy - cd2->border->_begy - 2,
  556.               cd2->border->_maxx - cd2->border->_begx - 2,
  557.               cd2->border->_begy + 1, cd2->border->_begx + 1);
  558.       if (!cd2->win) {
  559.         cd2->wbox = 0;
  560.         cd2->win = cd2->border;
  561.         cd2->border = NULL;
  562.         return Error(interp, win, argv[1]);
  563.       }
  564.       copywin(cd2->border,cd2->win,1,1,0,0,
  565.           cd2->win->_maxy, cd2->win->_maxx, TRUE);
  566.       box(cd2->border,0,0);
  567.     }
  568.     if(!strcmp(argv[2], "off")) {
  569.       if (!cd2->wbox)
  570.         return Error(interp, win, argv[1]);
  571.       /* box can be turned off */
  572.       cd2->wbox = 0;
  573.       werase(cd2->border);
  574.       copywin(cd2->win,cd2->border,0,0,1,1,
  575.           cd2->win->_maxy-1, cd2->win->_maxx-1, TRUE);
  576.       delwin(cd2->win);
  577.       cd2->win = cd2->border;
  578.       cd2->border = NULL;
  579.     }
  580.     return TCL_OK;
  581.       }
  582.     if(argc == 3 && *argv[1] == 'a' && !strcmp(argv[1],"addstr"))
  583. /*XX <win> addstr <string> */
  584.     {
  585.     if(OK == waddstr(cd2->win,argv[2]))
  586.         return TCL_OK;
  587.     return Error(interp,win,argv[1]);
  588.     }
  589.     if(argc == 2 && *argv[1] == 'c' && !strcmp(argv[1],"clrtoeol"))
  590. /*XX <win> clrtoeol */
  591.     { wclrtoeol(cd2->win); return TCL_OK; }
  592.     if(argc == 2 && *argv[1] == 'c' && !strcmp(argv[1],"clrtobot"))
  593. /*XX <win> clrtobot */
  594.     { wclrtobot(cd2->win); return TCL_OK; }
  595.     if(argc == 2 && *argv[1] == 'r' && !strcmp(argv[1],"refresh"))
  596. /*XX <win> refresh */
  597.         { 
  598.       if (cd2->wbox) wrefresh(cd2->border); wrefresh(cd2->win); return TCL_OK; }
  599.     if(argc == 2 && *argv[1] == 'e' && !strcmp(argv[1],"erase"))
  600. /*XX <win> erase */
  601.     { werase(cd2->win); return TCL_OK; }
  602.     if(argc == 2 && *argv[1] == 'c' && !strcmp(argv[1],"clear"))
  603. /*XX <win> clear */
  604.     { wclear(cd2->win); return TCL_OK; }
  605.     if(argc == 2 && *argv[1] == 'g' && !strcmp(argv[1],"getch"))
  606. /*XX <win> getch */
  607.     {
  608.     char buf[2];
  609.     buf[1]=0;
  610.     buf[0]=wgetch(cd2->win);
  611.     Tcl_SetResult(interp,buf,TCL_STATIC);
  612.     return TCL_OK; 
  613.     }
  614.     if(argc == 3 && *argv[1] == 'g' && !strcmp(argv[1],"getstr"))
  615. /*XX <win> getstr <maxstrsize>*/
  616.       {
  617.     char *buf;
  618.     buf=(char *)malloc(1+atoi(argv[2]));
  619.     if(!buf)
  620.       return Error(interp,win,argv[1]);
  621.     memset((void*)buf,0,1+atoi(argv[2]));
  622.     if (OK!=wgetstr(cd2->win,buf)) {
  623.       free(buf);
  624.       return Error(interp,win,argv[1]);
  625.     }
  626.     Tcl_SetResult(interp,buf,TCL_STATIC);
  627.     free(buf);
  628.     return TCL_OK;
  629.       }
  630.  
  631.     Tcl_AddErrorInfo(interp,"curses ");
  632.     Tcl_AddErrorInfo(interp,win);
  633.     Tcl_AddErrorInfo(interp,": >>");
  634.     Tcl_AddErrorInfo(interp,argv[1]);
  635.     Tcl_AddErrorInfo(interp,"<< Huh ?");
  636.     return TCL_ERROR;
  637.     }
  638. --end
  639.  
  640. Cheers;
  641.  
  642. Nat.
  643. (gnat@kauri.vuw.ac.nz -- Nathan Torkington -- is the electronic text and
  644.  MS-DOS archivist for the Victoria University of Wellington, New Zealand)
  645.