home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / ncftp-2.3.0-src.tgz / tar.out / contrib / ncftp / WGets.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  15KB  |  729 lines

  1. /* WGets.c */
  2.  
  3. #include "Sys.h"
  4. #include "Util.h"
  5. #include "Curses.h"
  6. #include "Complete.h"
  7.  
  8. #ifdef USE_CURSES
  9.  
  10. /* The only reason we need to include this junk, is because on some systems
  11.  * the function killchar() is actually a macro that uses definitions in
  12.  * termios.h.  Example:  #define killchar()      (__baset.c_cc[VKILL])
  13.  */
  14.  
  15. #ifdef HAVE_TERMIOS_H
  16. #        include <termios.h>
  17. #else
  18. #    ifdef HAVE_TERMIO_H
  19. #        include <termio.h>
  20. #    else
  21. #        ifdef HAVE_SYS_IOCTL_H
  22. #            include <sys/ioctl.h>    /* For TIOxxxx constants. */
  23. #        endif
  24. #        include <sgtty.h>
  25. #    endif
  26. #endif /* !HAVE_TERMIOS_H */
  27.  
  28. #include <ctype.h>
  29.  
  30. #include "Strn.h"
  31. #include "LineList.h"
  32. #include "WGets.h"
  33.  
  34. /* Pointer to current position in the buffer. */
  35. static char *gBufPtr;
  36.  
  37. /* When we draw the display window in the buffer, this is the first
  38.  * character to draw, at the far left.
  39.  *
  40.  * The "display window" is the current area being edited by the user.
  41.  * For example, you specify that you can only use 10 screen columns to
  42.  * input a string that can have a maximum size of 30 characters.
  43.  *
  44.  * Let's say the current buffer has "abcdefghijklmnopqrstuvw" in it.
  45.  *     abcdefghijklmnopqrstuvw
  46.  *          ^  ^     ^
  47.  *          s  c     e
  48.  *
  49.  * The "display window" for this example would be "fghijklmno"
  50.  * <s> (gWinStartPtr) points to "f" and <e> (gWinEndPtr) points to "o".
  51.  * <c> (gBufPtr) points to the current character under the cursor, so
  52.  * the letter "i" would be the hilited/blinking cursor.
  53.  *
  54.  * This display window allows you to set aside a certain amount of screen
  55.  * area for editing, but allowing for longer input strings.  The display
  56.  * window will scroll as needed.
  57.  */
  58. static char *gWinStartPtr;
  59.  
  60. /* This would be the last character drawn in the display window. */
  61. static char *gWinEndPtr;
  62.  
  63. /* Number of characters in the buffer. */
  64. static size_t gBufLen;
  65.  
  66. /* If true, the display window needs to be redrawn. */
  67. static int gNeedUpdate;
  68.  
  69. /* The curses library window we are doing the editing in.  This window
  70.  * is different from what I call the "display window."   The display
  71.  * window is a subregion of the curses window, and does not have to have
  72.  * a separate WINDOW pointer just for the editing.
  73.  */
  74. static WINDOW *gW;
  75.  
  76. /* The column and row where the display window starts. */
  77. static int gSy, gSx;
  78.  
  79. /* This is the buffer for the characters typed. */
  80. static char *gDst;
  81.  
  82. /* This is the length of the display window on screen.  It should <=
  83.  * the size of the buffer itself.
  84.  */
  85. static int gWindowWidth;
  86.  
  87. /* This is the size of the buffer. */
  88. static size_t gDstSize;
  89.  
  90. /* This flag tells whether we are allowed to use the contents of the buffer
  91.  * passed by the caller, and whether the contents had length 1 or more.
  92.  */
  93. static int gHadStartingString;
  94.  
  95. /* This is a flag to tell if the user did any editing.  If any characters
  96.  * are added or deleted, this flag will be set.  If the user just used the
  97.  * arrow keys to move around and/or just hit return, it will be false.
  98.  */
  99. static int gChanged;
  100.  
  101. /* This is a flag to tell if we have moved at all on the line before
  102.  * hitting return.  This is mostly used for ^D handling.  We want ^D to
  103.  * return EOF if they hit right it away on a new line.
  104.  */
  105. static int gMoved;
  106.  
  107. /* We have the flexibility with respect to echoing characters. We can just
  108.  * echo the same character we read back to the screen like normal, always
  109.  * echo "bullets," or not echo at all.
  110.  */
  111. static int gEchoMode;
  112.  
  113. /* You can specify that the routine maintain a history buffer. If so, then
  114.  * the user can use the arrow keys to move up and down through the history
  115.  * to edit previous lines.
  116.  */
  117. static LineListPtr gHistory;
  118.  
  119. /* This is a pointer to the line in the history that is being used as a copy
  120.  * for editing.
  121.  */
  122. static LinePtr gCurHistLine;
  123.  
  124. static void
  125. wg_SetCursorPos(char *newPos)
  126. {
  127.     if (newPos > gWinEndPtr) {
  128.         /* Shift window right.
  129.          * (Text will appear to shift to the left.)
  130.          */
  131.         gWinStartPtr = newPos;
  132.         if (gWindowWidth > 7)
  133.             gWinStartPtr -= gWindowWidth * 2 / 10;
  134.         else if (gWindowWidth > 1)
  135.             gWinStartPtr -= 1;
  136.         gBufPtr = newPos;
  137.         gWinEndPtr = gWinStartPtr + gWindowWidth - 1;
  138.     } else if (newPos < gWinStartPtr) {
  139.         /* Shift window left.
  140.          * (Text will appear to shift to the right.)
  141.          */
  142.         gWinStartPtr = newPos;
  143.         if (gWindowWidth > 7)
  144.             gWinStartPtr -= gWindowWidth * 2 / 10;
  145.         else if (gWindowWidth > 1)
  146.             gWinStartPtr -= 1;
  147.         if (gWinStartPtr < gDst)
  148.             gWinStartPtr = gDst;
  149.         gBufPtr = newPos;
  150.         gWinEndPtr = gWinStartPtr + gWindowWidth - 1;
  151.     } else {
  152.         /* Can just move cursor without shifting window. */
  153.         gBufPtr = newPos;
  154.     }
  155. }    /* wg_SetCursorPos */
  156.  
  157.  
  158.  
  159.  
  160. static void
  161. wg_AddCh(int c)
  162. {
  163.     size_t n;
  164.     char *limit;
  165.  
  166.     if (gBufLen < gDstSize) {
  167.         limit = gDst + gBufLen;
  168.         if (gBufPtr == limit) {
  169.             /* Just add a character to the end.  No need to do
  170.              * a memory move for this.
  171.              */
  172.             *gBufPtr = c;
  173.             gBufLen++;
  174.             wg_SetCursorPos(gBufPtr + 1);
  175.         } else {
  176.             /* Have to move characters after the cursor over one
  177.              * position so we can insert a character.
  178.              */
  179.             n = limit - gBufPtr;
  180.             MEMMOVE(gBufPtr + 1, gBufPtr, n);
  181.             *gBufPtr = c;
  182.             gBufLen++;
  183.             wg_SetCursorPos(gBufPtr + 1);
  184.         }
  185.         gNeedUpdate = 1;
  186.         gChanged = 1;
  187.     } else {
  188.         beep();
  189.     }
  190. }    /* wg_AddCh */
  191.  
  192.  
  193.  
  194.  
  195. static void
  196. wg_KillCh(int count)
  197. {
  198.     size_t n;
  199.     char *limit;
  200.  
  201.     if (count > gBufPtr - gDst)
  202.         count = gBufPtr - gDst;
  203.     if (count) {
  204.         limit = gDst + gBufLen;
  205.         if (gBufPtr != limit) {
  206.             /* Delete the characters before the character under the
  207.              * cursor, and move everything after it back one.
  208.              */
  209.             n = limit - gBufPtr;
  210.             memcpy(gBufPtr - count, gBufPtr, n);
  211.         }
  212.         gBufLen -= count;
  213.         wg_SetCursorPos(gBufPtr - count);    /* Does a --gBufPtr. */
  214.         gNeedUpdate = 1;
  215.         gChanged = 1;
  216.     } else {
  217.         beep();
  218.     }
  219. }    /* wg_KillCh */
  220.  
  221. static int
  222. IsWordChar(char c)
  223. {
  224.     return !isspace(c) && c != '/';
  225. }
  226.  
  227. static void
  228. wg_KillWord(void)
  229. {
  230.     int count;
  231.     int off = gBufPtr - gDst - 1;
  232.     count = off;
  233.  
  234.     /* Find the end of the previous word */
  235.     while (off >= 0 && !IsWordChar(gDst[off]))
  236.         off--;
  237.     /* Find the start of the word */
  238.     while (off >= 0 && IsWordChar(gDst[off]))
  239.         off--;
  240.     count = count - off;
  241.     wg_KillCh(count);
  242. }    /* wg_KillWord */
  243.  
  244.  
  245. static void
  246. wg_ForwardKillCh(void)
  247. {
  248.     size_t n;
  249.     char *limit;
  250.  
  251.     if (gBufLen > 0) {
  252.         limit = gDst + gBufLen;
  253.         if (gBufPtr == limit) {
  254.             /* Nothing in front to delete. */
  255.             beep();
  256.         } else {
  257.             n = limit - gBufPtr - 1;
  258.             memcpy(gBufPtr, gBufPtr + 1, n);
  259.             --gBufLen;
  260.             gNeedUpdate = 1;
  261.             gChanged = 1;
  262.         }
  263.     } else {
  264.         beep();
  265.     }
  266. }    /* wg_ForwardKillCh */
  267.  
  268.  
  269.  
  270. static void
  271. wg_GoLeft(void)
  272. {
  273.     if (gBufPtr > gDst) {
  274.         wg_SetCursorPos(gBufPtr - 1);    /* Does a --gBufPtr. */
  275.         gNeedUpdate = 1;
  276.         gMoved = 1;
  277.     } else {
  278.         beep();
  279.     }
  280. }    /* wg_GoLeft */
  281.  
  282.  
  283.  
  284.  
  285. static void
  286. wg_GoRight(void)
  287. {
  288.     if (gBufPtr < (gDst + gBufLen)) {
  289.         wg_SetCursorPos(gBufPtr + 1);    /* Does a ++gBufPtr. */
  290.         gNeedUpdate = 1;
  291.         gMoved = 1;
  292.     } else {
  293.         beep();
  294.     }
  295. }    /* wg_GoRight */
  296.  
  297.  
  298.  
  299. static void
  300. wg_GoLineStart(void)
  301. {
  302.     wg_SetCursorPos(gDst);
  303.     gNeedUpdate = 1;
  304.     gMoved = 1;
  305. }    /* wg_GoLineStart */
  306.  
  307.  
  308.  
  309.  
  310. static void
  311. wg_GoLineEnd(void)
  312. {
  313.     wg_SetCursorPos(gDst + gBufLen);
  314.     gNeedUpdate = 1;
  315.     gMoved = 1;
  316. }    /* wg_GoLineEnd */
  317.  
  318.  
  319.  
  320.  
  321. static void
  322. wg_LineKill(void)
  323. {
  324.     gBufPtr = gDst;
  325.     gWinStartPtr = gBufPtr;
  326.     gWinEndPtr = gWinStartPtr + gWindowWidth - 1;
  327.     gBufPtr[gDstSize] = '\0';
  328.     gBufLen = 0;
  329.     gNeedUpdate = 1;
  330.  
  331.     /* Reset this so it acts as a new line.  We want them to be able to
  332.      * hit ^D until they do something with this line.
  333.      */
  334.     gMoved = 0;
  335.  
  336.     /* We now have an empty string.  If we originally had something in the
  337.      * buffer, then mark it as changed since we just erased that.
  338.      */
  339.     gChanged = gHadStartingString;
  340. }    /* wg_LineKill */
  341.  
  342.  
  343.  
  344. static void
  345. wg_HistoryUp(void)
  346. {
  347.     if (gHistory == wg_NoHistory) {
  348.         /* Not using history. */
  349.         beep();
  350.         return;
  351.     }
  352.  
  353.     if (gCurHistLine != NULL) {
  354.         /* If not null, then the user had already scrolled up and was
  355.          * editing a line in the history.
  356.          */
  357.         gCurHistLine = gCurHistLine->prev;
  358.     } else {
  359.         /* Was on original line to edit, but wants to go back one. */
  360.         gCurHistLine = gHistory->last;
  361.         if (gCurHistLine == NULL) {
  362.             /* No lines at all in the history. */
  363.             beep();
  364.             return;
  365.         }
  366.     }
  367.  
  368.     wg_LineKill();
  369.     if (gCurHistLine != NULL) {
  370.         Strncpy(gDst, gCurHistLine->line, gDstSize);
  371.         gBufLen = strlen(gDst);
  372.         wg_GoLineEnd();
  373.     }
  374.     /* Otherwise, was on the first line in the history, but went "up" from here
  375.      * which wraps around to the bottom.  This last line is the new line
  376.      * to edit.
  377.      */
  378. }    /* wg_HistoryUp */
  379.  
  380.  
  381.  
  382. static void
  383. wg_HistoryDown(void)
  384. {
  385.     if (gHistory == wg_NoHistory) {
  386.         /* Not using history. */
  387.         beep();
  388.         return;
  389.     }
  390.  
  391.     if (gCurHistLine != NULL) {
  392.         /* If not null, then the user had already scrolled up and was
  393.          * editing a line in the history.
  394.          */
  395.         gCurHistLine = gCurHistLine->next;
  396.     } else {
  397.         /* Was on original line to edit, but wants to go down one.
  398.          * We'll wrap around and go to the very first line.
  399.          */
  400.         gCurHistLine = gHistory->first;
  401.         if (gCurHistLine == NULL) {
  402.             /* No lines at all in the history. */
  403.             beep();
  404.             return;
  405.         }
  406.     }
  407.     
  408.     wg_LineKill();
  409.     if (gCurHistLine != NULL) {
  410.         Strncpy(gDst, gCurHistLine->line, gDstSize);
  411.         gBufLen = strlen(gDst);
  412.         wg_GoLineEnd();
  413.     }
  414.     /* Otherwise, was on the last line in the history, but went down from here
  415.      * which means we should resume editing a fresh line.
  416.      */
  417. }    /* wg_HistoryDown */
  418.  
  419.  
  420.  
  421.  
  422. static void
  423. wg_Update(void)
  424. {
  425.     char *lastCharPtr;
  426.     char *cp;
  427.  
  428.     wmove(gW, gSy, gSx);
  429.     lastCharPtr = gDst + gBufLen;
  430.     *lastCharPtr = '\0';
  431.     if (gEchoMode == wg_RegularEcho) {
  432.         for (cp = gWinStartPtr; cp < lastCharPtr; cp++) {
  433.             if (cp > gWinEndPtr)
  434.                 goto xx;
  435.             waddch(gW, (unsigned char) *cp);
  436.         }
  437.     } else if (gEchoMode == wg_BulletEcho) {
  438.         for (cp = gWinStartPtr; cp < lastCharPtr; cp++) {
  439.             if (cp > gWinEndPtr)
  440.                 goto xx;
  441.             waddch(gW, wg_Bullet);
  442.         }
  443.     } else /* if (gEchoMode == wg_NoEcho) */ {
  444.         for (cp = gWinStartPtr; cp < lastCharPtr; cp++) {
  445.             if (cp > gWinEndPtr)
  446.                 goto xx;
  447.             waddch(gW, ' ');
  448.         }
  449.     }
  450.  
  451.     /* Rest of display window is empty, so write out spaces. */
  452.     for ( ; cp <= gWinEndPtr; cp++)
  453.         waddch(gW, ' ');
  454. xx:
  455.     wmove(gW, gSy, gSx + (gBufPtr - gWinStartPtr));
  456.     wrefresh(gW);
  457.     gNeedUpdate = 0;
  458. } /* wg_Update */
  459.  
  460.  
  461.  
  462.  
  463. int
  464. wg_Gets(WGetsParamPtr wgpp)
  465. {
  466.     int c, result;
  467.     int lineKill;
  468.     int maxx, maxy;
  469. #ifdef WG_DEBUG
  470.     FILE *trace;
  471. #endif
  472.  
  473.     /* Sanity checks. */
  474.     if (wgpp == NULL)
  475.         return (wg_BadParamBlock);
  476.  
  477.     if (wgpp->dstSize < 2)
  478.         return (wg_DstSizeTooSmall);
  479.     gDstSize = wgpp->dstSize - 1;    /* Leave room for nul. */
  480.     
  481.     if (wgpp->fieldLen < 1)
  482.         return (wg_WindowTooSmall);
  483.     gWindowWidth = wgpp->fieldLen;
  484.  
  485.     if (wgpp->w == NULL)
  486.         return (wg_BadCursesWINDOW);
  487.     gW = wgpp->w;
  488.  
  489.     getmaxyx(gW, maxy, maxx);
  490.     if ((wgpp->sy < 0) || (wgpp->sy > maxy))
  491.         return (wg_BadCoordinates);
  492.     gSy = wgpp->sy;
  493.  
  494.     if ((wgpp->sx < 0) || (wgpp->sx > maxx))
  495.         return (wg_BadCoordinates);
  496.     gSx = wgpp->sx;
  497.  
  498.     if (wgpp->dst == NULL)
  499.         return (wg_BadBufferPointer);
  500.     gDst = wgpp->dst;
  501.  
  502.     gHistory = wgpp->history;    /* Will be NULL if not using history. */
  503.     gCurHistLine = NULL;        /* Means we haven't scrolled into history. */
  504.  
  505.     gEchoMode = wgpp->echoMode;
  506.     gChanged = 0;
  507.     gMoved = 0;
  508.     
  509.     result = 0;
  510.     wmove(gW, gSy, gSx);
  511.     wrefresh(gW);
  512.  
  513. #ifdef WG_DEBUG
  514.     trace = fopen(wg_TraceFileName, "a");
  515.     if (trace != NULL) {
  516.         fprintf(trace, "<START>\n");
  517.     }
  518. #endif
  519.  
  520.     cbreak();
  521.     /* Should already have echo turned off. */
  522.     /* noecho(); */
  523.     nodelay(gW, FALSE);
  524.     keypad(gW, TRUE);
  525. #ifdef HAVE_NOTIMEOUT
  526.     notimeout(gW, TRUE);
  527. #endif
  528.  
  529.     lineKill = (int) killchar();
  530.  
  531.     gNeedUpdate = 1;
  532.     gBufPtr = gDst;
  533.     gWinStartPtr = gBufPtr;
  534.     gWinEndPtr = gWinStartPtr + gWindowWidth - 1;
  535.     gBufPtr[gDstSize] = '\0';
  536.     gHadStartingString = 0;
  537.     if (wgpp->useCurrentContents) {
  538.         gBufLen = strlen(gBufPtr);
  539.         if (gBufLen > 0)
  540.             gHadStartingString = 1;
  541.     } else {
  542.         gBufLen = 0;
  543.     }
  544.  
  545.     while (1) {
  546.         if (gNeedUpdate) 
  547.             wg_Update();
  548.  
  549.         c = wgetch(gW);
  550. #ifdef WG_DEBUG
  551.         if (trace != NULL) {
  552.             switch (c) {
  553.                 case '\r': fprintf(trace, "(\\r)\n"); break;
  554.                 case '\n': fprintf(trace, "(\\n)\n"); break;
  555. #ifdef KEY_ENTER
  556.                 case KEY_ENTER: fprintf(trace, "(KEY_ENTER)\n"); break;
  557. #endif
  558.                 default: fprintf(trace, "[%c] = 0x%X\n", c, c);
  559.             }
  560.         }
  561. #endif
  562.         switch (c) {
  563.             case '\r':
  564.             case '\n':
  565. #ifdef KEY_ENTER
  566.             case KEY_ENTER:
  567. #endif
  568.                 goto done;            
  569.  
  570.             case '\b':
  571. #ifdef KEY_BACKSPACE
  572.             case KEY_BACKSPACE:
  573. #endif
  574.             case 0x7f:
  575.                 wg_KillCh(1);
  576.                 break;
  577.  
  578. #ifdef KEY_FWDDEL        /* Need to find a real symbol for forward delete. */
  579.             case KEY_FWDDEL:
  580.                 wg_ForwardKillCh();
  581.                 break;
  582. #endif
  583.  
  584. #ifdef KEY_EXIT
  585.             case KEY_EXIT:
  586. #endif
  587. #ifdef KEY_CLOSE
  588.             case KEY_CLOSE:
  589. #endif
  590. #ifdef KEY_CANCEL
  591.             case KEY_CANCEL:
  592. #endif
  593.             case 0x04:        /* Control-D */
  594.                 /* If we haven't changed the buffer, and the cursor has
  595.                  * not moved from the first position, return EOF.
  596.                  */
  597.                 if (!gChanged && !gMoved) {
  598.                     result = wg_EOF;
  599.                     goto done;
  600.                 }
  601.                 /* fall */
  602. #ifdef KEY_DC
  603.             case KEY_DC:
  604. #endif
  605.                 if (gBufPtr == gDst + gBufLen) {
  606.                     wg_AddCh('*'); wg_Update();
  607.                     CompleteOptions(gDst, gBufPtr-gDst-1);
  608.                     wg_KillCh(1);
  609.                 } else {
  610.                     wg_ForwardKillCh();        /* Emacs ^D */
  611.                 }
  612.                 break;
  613.  
  614. #ifdef KEY_CLEAR
  615.             case KEY_CLEAR:
  616. #endif
  617.             case 0x0C:        /* Control-L */
  618.                 touchwin(curscr);
  619.                 wrefresh(curscr);
  620.                 break;
  621.  
  622. #ifdef KEY_LEFT
  623.             case KEY_LEFT:
  624. #endif
  625.             case 0x02:        /* Control-F */
  626.                 wg_GoLeft();
  627.                 break;
  628.  
  629. #ifdef KEY_RIGHT
  630.             case KEY_RIGHT:
  631. #endif
  632.             case 0x06:        /* Control-B */
  633.                 wg_GoRight();
  634.                 break;
  635.  
  636. #ifdef KEY_UP
  637.             case KEY_UP:
  638. #endif
  639.             case 0x10:        /* Control-P */
  640.                 wg_HistoryUp();
  641.                 break;
  642.  
  643. #ifdef KEY_DOWN
  644.             case KEY_DOWN:
  645. #endif
  646.             case 0x0E:        /* Control-N */
  647.                 wg_HistoryDown();
  648.                 break;
  649.  
  650. #ifdef KEY_HOME
  651.             case KEY_HOME:
  652. #endif
  653.             case 0x01:        /* Control-A */
  654.                 wg_GoLineStart();
  655.                 break;
  656. #ifdef KEY_END
  657.             case KEY_END:
  658. #endif
  659.             case 0x05:        /* Control-E */
  660.                 wg_GoLineEnd();
  661.                 break;
  662. #ifdef KEY_EOL
  663.             case KEY_EOL:
  664. #endif
  665.             case 0x0B:
  666.                 while (gBufLen > 0 && gBufPtr < gDst + gBufLen)
  667.                     wg_ForwardKillCh();     /* Emacs ^K */
  668.                 break;
  669.  
  670.             case -1:
  671.                 /* This can happen if getch() was interrupted by a
  672.                  * signal like ^Z.
  673.                  */
  674.                 break;
  675.  
  676.             case 23:  /* ^W */
  677.                 wg_KillWord();
  678.                 break;
  679.  
  680.             case '\t': {
  681.                 int i;
  682.                 char *comp;
  683.                 char *tmp;
  684.                 for (i=0;i<3;i++)
  685.                     wg_AddCh('.');
  686.                 wg_Update();
  687.                 comp = CompleteGet(gDst, gBufPtr-gDst-3);
  688.                 wg_KillCh(3);
  689.                 gDst[gBufLen] = '\0';
  690.                 if (comp) {
  691.                     for (tmp = comp; *tmp; tmp++)
  692.                         wg_AddCh(*tmp);
  693.                     free(comp);
  694.                 }
  695.                 break;
  696.             }
  697.                 
  698.             default:
  699.                 if (c < 0400) {
  700.                     if (c == lineKill)
  701.                         wg_LineKill();
  702.                     else
  703.                         wg_AddCh(c);
  704.                 }
  705.         }
  706.     }
  707.  
  708. done:
  709.     nocbreak();
  710.  
  711.     gDst[gBufLen] = '\0';
  712.     wgpp->changed = gChanged;
  713.     wgpp->dstLen = gBufLen;
  714.     if ((gHistory != wg_NoHistory) && (gBufLen > 0))
  715.         AddLine(wgpp->history, gDst);
  716.     
  717. #ifdef WG_DEBUG
  718.         if (trace != NULL) {
  719.             fprintf(trace, "<DONE>\n");
  720.             fclose(trace);
  721.         }
  722. #endif
  723.     return (result);
  724. }    /* wg_Gets */
  725.  
  726. #endif    /* USE_CURSES */
  727.  
  728. /* eof */
  729.