home *** CD-ROM | disk | FTP | other *** search
/ ftp.ncftp.com / ftp.ncftp.com.zip / ftp.ncftp.com / ncftp / older_versions / ncftp-3.2.2-src.tar.bz2 / ncftp-3.2.2-src.tar / ncftp-3.2.2 / vis / wgets.c < prev    next >
C/C++ Source or Header  |  2005-01-01  |  15KB  |  723 lines

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