home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / lynx2.8.1dev.10.tar.gz / lynx2.8.1dev.10.tar / lynx2-8 / src / LYForms.c < prev    next >
C/C++ Source or Header  |  1998-05-02  |  38KB  |  1,504 lines

  1. #include <HTUtils.h>
  2. #include <tcp.h>
  3. #include <HTCJK.h>
  4. #include <HTTP.h>
  5. #include <HTAlert.h>
  6. #include <LYCurses.h>
  7. #include <GridText.h>
  8. #include <LYCharSets.h>
  9. #include <UCAux.h>
  10. #include <LYUtils.h>
  11. #include <LYStructs.h>  /* includes HTForms.h */
  12. #include <LYStrings.h>
  13. #include <LYGlobalDefs.h>
  14. #include <LYKeymap.h>
  15. #include <LYSignal.h>
  16.  
  17. #include <LYLeaks.h>
  18.  
  19. #ifdef USE_COLOR_STYLE
  20. #include <AttrList.h>
  21. #include <LYHash.h>
  22. #endif
  23.  
  24. extern HTCJKlang HTCJK;
  25.  
  26. PRIVATE int form_getstr PARAMS((
  27.     struct link *    form_link));
  28. PRIVATE int popup_options PARAMS((
  29.     int        cur_selection,
  30.     OptionType *    list,
  31.     int        ly,
  32.     int        lx,
  33.     int        width,
  34.     int        i_length,
  35.     int        disabled));
  36.  
  37. PUBLIC int change_form_link ARGS6(
  38.     struct link *,    form_link,
  39.     int,        mode,
  40.     document *,    newdoc,
  41.     BOOLEAN *,    refresh_screen,
  42.     char *,        link_name,
  43.     char *,        link_value)
  44. {
  45.     FormInfo *form = form_link->form;
  46.     int c = DO_NOTHING;
  47.     int OrigNumValue;
  48.  
  49.     /*
  50.      *  If there is no form to perform action on, don't do anything.
  51.      */
  52.     if (form == NULL) {
  53.         return(c);
  54.     }
  55.  
  56.     /*
  57.      *  Move to the link position.
  58.      */
  59.     move(form_link->ly, form_link->lx);
  60.  
  61.     switch(form->type) {
  62.     case F_CHECKBOX_TYPE:
  63.         if (form->disabled == YES)
  64.         break;
  65.         if (form->num_value) {
  66.         form_link->hightext = unchecked_box;
  67.         form->num_value = 0;
  68.         } else {
  69.         form_link->hightext = checked_box;
  70.         form->num_value = 1;
  71.         }
  72.         break;
  73.  
  74.     case F_OPTION_LIST_TYPE:
  75.         if (!form->select_list) {
  76.         HTAlert(BAD_HTML_NO_POPUP);
  77.         c = DO_NOTHING;
  78.         break;
  79.         }
  80.  
  81.         if (form->disabled == YES) {
  82.         int dummy;
  83.         dummy = popup_options(form->num_value, form->select_list,
  84.                 form_link->ly, form_link->lx, form->size,
  85.                 form->size_l, form->disabled);
  86. #if defined(FANCY_CURSES) || defined(USE_SLANG)
  87.         if (!enable_scrollback)
  88. #if defined(VMS) && !defined(USE_SLANG)
  89.             c = DO_NOTHING;
  90. #else
  91.             c = 23;  /* CTRL-W refresh without clearok */
  92. #endif /* VMS && !USE_SLANG */
  93.         else
  94. #endif /* FANCY_CURSES || USE_SLANG */
  95.             c = 12;  /* CTRL-L for repaint */
  96.         break;
  97.         }
  98.         OrigNumValue = form->num_value;
  99.         form->num_value = popup_options(form->num_value, form->select_list,
  100.                 form_link->ly, form_link->lx, form->size,
  101.                 form->size_l, form->disabled);
  102.  
  103.         {
  104.         OptionType * opt_ptr = form->select_list;
  105.         int i;
  106.         for (i = 0; i < form->num_value; i++, opt_ptr = opt_ptr->next)
  107.             ; /* null body */
  108.         /*
  109.          *  Set the name.
  110.          */
  111.         form->value = opt_ptr->name;
  112.         /*
  113.          *  Set the value.
  114.          */
  115.         form->cp_submit_value = opt_ptr->cp_submit_value;
  116.          /*
  117.           *  Set charset in which we have the submit value. - kw
  118.           */
  119.         form->value_cs = opt_ptr->value_cs;
  120.         }
  121. #if defined(FANCY_CURSES) || defined(USE_SLANG)
  122.         if (!enable_scrollback)
  123. #if defined(VMS) && !defined(USE_SLANG)
  124.         if (form->num_value == OrigNumValue)
  125.             c = DO_NOTHING;
  126.         else
  127. #endif /* VMS && !USE_SLANG*/
  128.         c = 23;     /* CTRL-W refresh without clearok */
  129.         else
  130. #endif /* FANCY_CURSES || USE_SLANG */
  131.                 c = 12;  /* CTRL-L for repaint */
  132.             break;
  133.  
  134.     case F_RADIO_TYPE:
  135.         if (form->disabled == YES)
  136.         break;
  137.         /*
  138.          *  Radio buttons must have one and
  139.          *  only one down at a time!
  140.          */
  141.         if (form->num_value) {
  142.         _statusline(NEED_CHECKED_RADIO_BUTTON);
  143.         sleep(MessageSecs);
  144.  
  145.         } else {
  146.         int i;
  147.         /*
  148.          *  Run though list of the links on the screen and
  149.          *  unselect any that are selected. :)
  150.          */
  151.         lynx_start_radio_color ();
  152.         for (i = 0; i < nlinks; i++) {
  153.             if (links[i].type == WWW_FORM_LINK_TYPE &&
  154.             links[i].form->type == F_RADIO_TYPE &&
  155.             links[i].form->number == form->number &&
  156.             /*
  157.              *  If it has the same name and its on...
  158.              */
  159.             !strcmp(links[i].form->name, form->name) &&
  160.             links[i].form->num_value) {
  161.             move(links[i].ly, links[i].lx);
  162.             addstr(unchecked_radio);
  163.             links[i].hightext = unchecked_radio;
  164.             }
  165.         }
  166.         lynx_stop_radio_color ();
  167.         /*
  168.          *  Will unselect other button and select this one.
  169.          */
  170.         HText_activateRadioButton(form);
  171.         /*
  172.          *  Now highlight this one.
  173.          */
  174.         form_link->hightext = checked_radio;
  175.         }
  176.         break;
  177.  
  178.     case F_TEXT_TYPE:
  179.     case F_TEXTAREA_TYPE:
  180.     case F_PASSWORD_TYPE:
  181.         c = form_getstr(form_link);
  182.         if (form->type == F_PASSWORD_TYPE)
  183.         form_link->hightext = STARS(strlen(form->value));
  184.         else
  185.         form_link->hightext = form->value;
  186.         break;
  187.  
  188.     case F_RESET_TYPE:
  189.         if (form->disabled == YES)
  190.         break;
  191.         HText_ResetForm(form);
  192.         *refresh_screen = TRUE;
  193.         break;
  194.  
  195.     case F_TEXT_SUBMIT_TYPE:
  196.         c = form_getstr(form_link);
  197.         if (form->disabled == YES &&
  198.         (c == '\r' || c == '\n')) {
  199.         c = '\t';
  200.         break;
  201.         }
  202.         if (c == '\r' || c == '\n') {
  203.         form_link->hightext = form->value;
  204.         if (!form->submit_action || *form->submit_action == '\0') {
  205.             _statusline(NO_FORM_ACTION);
  206.             sleep(MessageSecs);
  207.             c = DO_NOTHING;
  208.             break;
  209.         } else if (form->submit_method == URL_MAIL_METHOD && no_mail) {
  210.             HTAlert(FORM_MAILTO_DISALLOWED);
  211.             c = DO_NOTHING;
  212.             break;
  213.         } else {
  214.             if (form->no_cache &&
  215.             form->submit_method != URL_MAIL_METHOD) {
  216.             LYforce_no_cache = TRUE;
  217.             reloading = TRUE;
  218.             }
  219.             HText_SubmitForm(form, newdoc, link_name, form->value);
  220.         }
  221.         if (form->submit_method == URL_MAIL_METHOD) {
  222.             *refresh_screen = TRUE;
  223.         } else {
  224.             /*
  225.              *  Returns new document URL.
  226.              */
  227.             newdoc->link = 0;
  228.             newdoc->internal_link = FALSE;
  229.         }
  230.         c = DO_NOTHING;
  231.         break;
  232.         } else {
  233.         form_link->hightext = form->value;
  234.         }
  235.         break;
  236.  
  237.     case F_SUBMIT_TYPE:
  238.     case F_IMAGE_SUBMIT_TYPE:
  239.         if (form->disabled == YES)
  240.         break;
  241.         if (form->no_cache &&
  242.         form->submit_method != URL_MAIL_METHOD) {
  243.         LYforce_no_cache = TRUE;
  244.         reloading = TRUE;
  245.         }
  246.         HText_SubmitForm(form, newdoc, link_name, link_value);
  247.         if (form->submit_method == URL_MAIL_METHOD)
  248.         *refresh_screen = TRUE;
  249.         else {
  250.         /* returns new document URL */
  251.         newdoc->link = 0;
  252.         newdoc->internal_link = FALSE;
  253.         }
  254.         break;
  255.  
  256.     }
  257.  
  258.     return(c);
  259. }
  260.  
  261. PRIVATE int form_getstr ARGS1(
  262.     struct link *,    form_link)
  263. {
  264.     FormInfo *form = form_link->form;
  265.     char *value = form->value;
  266.     int ch;
  267.     int far_col;
  268.     int max_length;
  269.     int startcol, startline;
  270.     BOOL HaveMaxlength = FALSE;
  271.     int action;
  272.  
  273. #ifdef VMS
  274.     extern BOOLEAN HadVMSInterrupt;    /* Flag from cleanup_sig() AST */
  275. #endif
  276.  
  277.     EditFieldData MyEdit;
  278.     BOOLEAN Edited = FALSE;        /* Value might be updated? */
  279.  
  280.     /*
  281.      *  Get the initial position of the cursor.
  282.      */
  283.     LYGetYX(startline, startcol);
  284.     if ((startcol + form->size) > (LYcols - 1))
  285.     far_col = (LYcols - 1);
  286.     else
  287.     far_col = (startcol + form->size);
  288.  
  289.     /*
  290.      *  Make sure the form field value does not exceed our buffer. - FM
  291.      */
  292.     max_length = ((form->maxlength > 0 &&
  293.            form->maxlength < sizeof(MyEdit.buffer)) ?
  294.                         form->maxlength :
  295.                         (sizeof(MyEdit.buffer) - 1));
  296.     if (strlen(form->value) > max_length) {
  297.     /*
  298.      *  We can't fit the entire value into the editing buffer,
  299.      *  so enter as much of the tail as fits. - FM
  300.      */
  301.     value += (strlen(form->value) - max_length);
  302.     if (!form->disabled &&
  303.         !(form->submit_method == URL_MAIL_METHOD && no_mail)) {
  304.         /*
  305.          *  If we can edit it, report that we are using the tail. - FM
  306.          */
  307.         _statusline(FORM_VALUE_TOO_LONG);
  308.         sleep(MessageSecs);
  309.         switch(form->type) {
  310.         case F_PASSWORD_TYPE:
  311.             statusline(FORM_LINK_PASSWORD_MESSAGE);
  312.             break;
  313.         case F_TEXT_SUBMIT_TYPE:
  314.             if (form->submit_method == URL_MAIL_METHOD) {
  315.             statusline(FORM_LINK_TEXT_SUBMIT_MAILTO_MSG);
  316.             } else if (form->no_cache) {
  317.             statusline(FORM_LINK_TEXT_RESUBMIT_MESSAGE);
  318.             } else {
  319.             statusline(FORM_LINK_TEXT_SUBMIT_MESSAGE);
  320.             }
  321.             break;
  322.         case F_TEXT_TYPE:
  323.         case F_TEXTAREA_TYPE:
  324.             statusline(FORM_LINK_TEXT_MESSAGE);
  325.             break;
  326.         default:
  327.             break;
  328.         }
  329.         move(startline, startcol);
  330.     }
  331.     }
  332.  
  333.     /*
  334.      *  Print panned line
  335.      */
  336.     LYSetupEdit(&MyEdit, value, max_length, (far_col - startcol));
  337.     MyEdit.pad = '_';
  338.     MyEdit.hidden = (form->type == F_PASSWORD_TYPE);
  339.     LYRefreshEdit(&MyEdit);
  340.  
  341.     /*
  342.      *  And go for it!
  343.      */
  344.     for (;;) {
  345. again:
  346.     ch = LYgetch();
  347. #ifdef VMS
  348.     if (HadVMSInterrupt) {
  349.         HadVMSInterrupt = FALSE;
  350.         ch = 7;
  351.     }
  352. #endif /* VMS */
  353.  
  354.     /*
  355.      *  Filter out global navigation keys that should not be passed
  356.      *  to line editor, and LYK_REFRESH.
  357.      */
  358.     action = EditBinding(ch);
  359.     if (action == LYE_ENTER)
  360.         break;
  361.     if (action == LYE_LKCMD) {
  362.         _statusline(ENTER_LYNX_COMMAND);
  363.         ch = LYgetch();
  364. #ifdef VMS
  365.         if (HadVMSInterrupt) {
  366.         HadVMSInterrupt = FALSE;
  367.         ch = 7;
  368.         }
  369. #endif /* VMS */
  370.         break;
  371.     }
  372.     if (action == LYE_AIX &&
  373.         (HTCJK == NOCJK && LYlowest_eightbit[current_char_set] > 0x97))
  374.         break;
  375.     if (action == LYE_TAB) {
  376.         ch = (int)('\t');
  377.         break;
  378.     }
  379.     if (action == LYE_ABORT) {
  380.         return(DO_NOTHING);
  381.     }
  382.     if (keymap[ch + 1] == LYK_REFRESH)
  383.         break;
  384.     switch (ch) {
  385.         case DNARROW:
  386.         case UPARROW:
  387.         case PGUP:
  388.         case PGDOWN:
  389. #ifdef NOTDEFINED
  390.         case HOME:
  391.         case END_KEY:
  392.         case FIND_KEY:
  393.         case SELECT_KEY:
  394. #endif /* NOTDEFINED */
  395.         goto breakfor;
  396.  
  397.         /*
  398.          *  Left arrrow in column 0 deserves special treatment here,
  399.          *  else you can get trapped in a form without submit button!
  400.          */
  401.         case LTARROW:
  402.         if (MyEdit.pos == 0) {
  403.             int c = 'Y';    /* Go back immediately if no changes */
  404.             if (strcmp(MyEdit.buffer, value)) {
  405.             _statusline(PREV_DOC_QUERY);
  406.             c = LYgetch();
  407.             }
  408.             if (TOUPPER(c) == 'Y') {
  409.             return(ch);
  410.             } else {
  411.             if (form->disabled == YES)
  412.                 _statusline(ARROWS_OR_TAB_TO_MOVE);
  413.             else
  414.                 _statusline(ENTER_TEXT_ARROWS_OR_TAB);
  415.             }
  416.         }
  417.         /* fall through */
  418.  
  419.         default:
  420.         if (form->disabled == YES)
  421.             goto again;
  422.         /*
  423.          *  Make sure the statusline uses editmode help.
  424.          */
  425.         LYLineEdit(&MyEdit, ch, TRUE);
  426.         if (MyEdit.strlen >= max_length) {
  427.             HaveMaxlength = TRUE;
  428.         } else if (HaveMaxlength &&
  429.                MyEdit.strlen < max_length) {
  430.             HaveMaxlength = FALSE;
  431.             _statusline(ENTER_TEXT_ARROWS_OR_TAB);
  432.         }
  433.         if (strcmp(value, MyEdit.buffer)) {
  434.             Edited = TRUE;
  435.         }
  436.         LYRefreshEdit(&MyEdit);
  437.     }
  438.     }
  439. breakfor:
  440.     if (Edited) {
  441.     char  *p;
  442.  
  443.     /*
  444.      *  Load the new value.
  445.      */
  446.     if (value == form->value) {
  447.         /*
  448.          *  The previous value did fit in the line buffer,
  449.          *  so replace it with the new value. - FM
  450.          */
  451.         StrAllocCopy(form->value, MyEdit.buffer);
  452.     } else {
  453.         /*
  454.          *  Combine the modified tail with the unmodified head. - FM
  455.          */
  456.         form->value[(strlen(form->value) - strlen(value))] = '\0';
  457.         StrAllocCat(form->value, MyEdit.buffer);
  458.         _statusline(FORM_TAIL_COMBINED_WITH_HEAD);
  459.         sleep(MessageSecs);
  460.     }
  461.  
  462.     /*
  463.      *  Remove trailing spaces
  464.      *
  465.      *  Do we really need to do that here? Trailing spaces will only
  466.      *  be there if user keyed them in. Rather rude to throw away
  467.      *  their hard earned spaces. Better deal with trailing spaces
  468.      *  when submitting the form????
  469.      */
  470.     p = &(form->value[strlen(form->value)]);
  471.     while ((p != form->value) && (p[-1] == ' '))
  472.         p--;
  473.     *p = '\0';
  474.  
  475.     /*
  476.      *  If the field has been changed, assume that it is now in
  477.      *  current display character set, even if for some reason
  478.      *  it wasn't!  Hopefully a user will only submit the form
  479.      *  if the non-ASCII characters are displayed correctly, which
  480.      *  means (assuming that the display character set has been set
  481.      *  truthfully) the user confirms by changing the field that
  482.      *  the character encoding is right. - kw
  483.      */
  484.     if (form->value && *form->value)
  485.         form->value_cs = current_char_set;
  486.     }
  487.     return(ch);
  488. }
  489.  
  490. /*
  491. **  This function prompts for an option or page number.
  492. **  If a 'g' or 'p' suffix is included, that will be
  493. **  loaded into c.  Otherwise, c is zeroed. - FM & LE
  494. */
  495. PRIVATE int get_popup_option_number ARGS1(
  496.     int *,        c)
  497. {
  498.     char temp[120];
  499.  
  500.     /*
  501.      *  Load the c argument into the prompt buffer.
  502.      */
  503.     temp[0] = *c;
  504.     temp[1] = '\0';
  505.     _statusline(SELECT_OPTION_NUMBER);
  506.  
  507.     /*
  508.      *  Get the number, possibly with a suffix, from the user.
  509.      */
  510.     if (LYgetstr(temp, VISIBLE, sizeof(temp), NORECALL) < 0 || *temp == 0) {
  511.     _statusline(CANCELLED);
  512.     sleep(InfoSecs);
  513.     *c = '\0';
  514.     return(0);
  515.     }
  516.  
  517.     /*
  518.      *  If we had a 'g' or 'p' suffix, load it into c.
  519.      *  Otherwise, zero c.  Then return the number.
  520.      */
  521.     if (strchr(temp, 'g') != NULL || strchr(temp, 'G') != NULL) {
  522.     *c = 'g';
  523.     } else if (strchr(temp, 'p') != NULL || strchr(temp, 'P') != NULL) {
  524.     *c = 'p';
  525.     } else {
  526.     *c = '\0';
  527.     }
  528.     return(atoi(temp));
  529. }
  530.  
  531. /* Use this rather than the 'wprintw()' function to write a blank-padded
  532.  * string to the given window, since someone's asserted that printw doesn't
  533.  * handle 8-bit characters unlike addstr (though more info would be useful).
  534.  *
  535.  * We're blank-filling so that with SVr4 curses, it'll show the background
  536.  * color to a uniform width in the popup-menu.
  537.  */
  538. #ifndef USE_SLANG
  539. PRIVATE void paddstr ARGS3(
  540.     WINDOW *,    the_window,
  541.     int,        width,
  542.     char *,     the_string)
  543. {
  544.     width -= strlen(the_string);
  545.     waddstr(the_window, the_string);
  546.     while (width-- > 0)
  547.     waddstr(the_window, " ");
  548. }
  549. #endif
  550.  
  551.  
  552. PRIVATE int popup_options ARGS7(
  553.     int,        cur_selection,
  554.     OptionType *,    list,
  555.     int,        ly,
  556.     int,        lx,
  557.     int,        width,
  558.     int,        i_length,
  559.     int,        disabled)
  560. {
  561.     /*
  562.      *  Revamped to handle within-tag VALUE's, if present,
  563.      *  and to position the popup window appropriately,
  564.      *  taking the user_mode setting into account. -- FM
  565.      */
  566.     int c = 0, cmd = 0, i = 0, j = 0;
  567.     int orig_selection = cur_selection;
  568. #ifndef USE_SLANG
  569.     WINDOW * form_window;
  570. #endif /* !USE_SLANG */
  571.     int num_options = 0, top, bottom, length = -1;
  572.     OptionType * opt_ptr = list;
  573.     int window_offset = 0;
  574.     int lines_to_show;
  575.     int npages;
  576. #ifdef VMS
  577.     extern BOOLEAN HadVMSInterrupt; /* Flag from cleanup_sig() AST */
  578. #endif /* VMS */
  579.     static char prev_target[512];        /* Search string buffer */
  580.     static char prev_target_buffer[512];    /* Next search buffer */
  581.     static BOOL first = TRUE;
  582.     char *cp;
  583.     int ch = 0, recall;
  584.     int QueryTotal;
  585.     int QueryNum;
  586.     BOOLEAN FirstRecall = TRUE;
  587.     OptionType * tmp_ptr;
  588.     BOOLEAN ReDraw = FALSE;
  589.     int number;
  590.     char buffer[512];
  591.  
  592.     /*
  593.      * Initialize the search string buffer. - FM
  594.      */
  595.     if (first) {
  596.     *prev_target_buffer = '\0';
  597.     first = FALSE;
  598.     }
  599.     *prev_target = '\0';
  600.     QueryTotal = (search_queries ? HTList_count(search_queries) : 0);
  601.     recall = ((QueryTotal >= 1) ? RECALL : NORECALL);
  602.     QueryNum = QueryTotal;
  603.  
  604.     /*
  605.      *  Set lines_to_show based on the user_mode global.
  606.      */
  607.     if (user_mode == NOVICE_MODE)
  608.     lines_to_show = LYlines-4;
  609.     else
  610.     lines_to_show = LYlines-2;
  611.  
  612.     /*
  613.      *  Counting the number of options to be displayed.
  614.      *   num_options ranges 0...n
  615.      */
  616.     for (; opt_ptr->next; num_options++, opt_ptr = opt_ptr->next)
  617.      ; /* null body */
  618.  
  619.     /*
  620.      *  Let's assume for the sake of sanity that ly is the number
  621.      *   corresponding to the line the selection box is on.
  622.      *  Let's also assume that cur_selection is the number of the
  623.      *   item that should be initially selected, as 0 beign the
  624.      *   first item.
  625.      *  So what we have, is the top equal to the current screen line
  626.      *   subtracting the cur_selection + 1 (the one must be for the
  627.      *   top line we will draw in a box).  If the top goes under 0,
  628.      *   consider it 0.
  629.      */
  630.     top = ly - (cur_selection + 1);
  631.     if (top < 0)
  632.     top = 0;
  633.  
  634.     /*
  635.      *  Check and see if we need to put the i_length parameter up to
  636.      *  the number of real options.
  637.      */
  638.     if (!i_length) {
  639.     i_length = num_options;
  640.     } else {
  641.     /*
  642.      *  Otherwise, it is really one number too high.
  643.      */
  644.     i_length--;
  645.     }
  646.  
  647.     /*
  648.      *  The bottom is the value of the top plus the number of options
  649.      *  to view plus 3 (one for the top line, one for the bottom line,
  650.      *  and one to offset the 0 counted in the num_options).
  651.      */
  652.     bottom = top + i_length + 3;
  653.  
  654.     /*
  655.      *  Hmm...  If the bottom goes beyond the number of lines available,
  656.      */
  657.     if (bottom > lines_to_show) {
  658.     /*
  659.      *  Position the window at the top if we have more
  660.      *  options than will fit in the window.
  661.      */
  662.     if (i_length+3 > lines_to_show) {
  663.         top = 0;
  664.         bottom = top + i_length+3;
  665.         if (bottom > lines_to_show)
  666.         bottom = lines_to_show + 1;
  667.     } else {
  668.         /*
  669.          *  Try to position the window so that the selected option will
  670.          *    appear where the selection box currently is positioned.
  671.          *  It could end up too high, at this point, but we'll move it
  672.          *    down latter, if that has happened.
  673.          */
  674.         top = (lines_to_show + 1) - (i_length + 3);
  675.         bottom = (lines_to_show + 1);
  676.     }
  677.     }
  678.  
  679.     /*
  680.      *  This is really fun, when the length is 4, it means 0-4, or 5.
  681.      */
  682.     length = (bottom - top) - 2;
  683.  
  684.     /*
  685.      *  Move the window down if it's too high.
  686.      */
  687.     if (bottom < ly + 2) {
  688.     bottom = ly + 2;
  689.     if (bottom > lines_to_show + 1)
  690.         bottom = lines_to_show + 1;
  691.     top = bottom - length - 2;
  692.     }
  693.  
  694.     /*
  695.      *  Set up the overall window, including the boxing characters ('*'),
  696.      *  if it all fits.  Otherwise, set up the widest window possible. - FM
  697.      */
  698. #ifdef USE_SLANG
  699.     SLsmg_fill_region(top, lx - 1, bottom - top, width + 4, ' ');
  700. #else
  701.     if (!(form_window = newwin(bottom - top, width + 4, top, lx - 1)) &&
  702.     !(form_window = newwin(bottom - top, 0, top, 0))) {
  703.     HTAlert(POPUP_FAILED);
  704.     return(orig_selection);
  705.     }
  706.     scrollok(form_window, TRUE);
  707. #ifdef PDCURSES
  708.     keypad(form_window, TRUE);
  709. #endif /* PDCURSES */
  710. #ifdef NCURSES
  711.     LYsubwindow(form_window);
  712. #endif
  713. #if defined(HAVE_GETBKGD) /* not defined in ncurses 1.8.7 */
  714.     wbkgd(form_window, getbkgd(stdscr));
  715.     wbkgdset(form_window, getbkgd(stdscr));
  716. #endif
  717. #endif /* USE_SLANG */
  718.  
  719.     /*
  720.      *  Set up the window_offset for options.
  721.      *   cur_selection ranges from 0...n
  722.      *   length ranges from 0...m
  723.      */
  724.     if (cur_selection >= length) {
  725.     window_offset = cur_selection - length + 1;
  726.     }
  727.  
  728.     /*
  729.      *  Compute the number of popup window pages. - FM
  730.      */
  731.     npages = ((num_options + 1) > length) ?
  732.         (((num_options + 1) + (length - 1))/(length))
  733.                       : 1;
  734. /*
  735.  * OH!  I LOVE GOTOs! hack hack hack
  736.  *        07-11-94 GAB
  737.  *      MORE hack hack hack
  738.  *        09-05-94 FM
  739.  */
  740. redraw:
  741.     opt_ptr = list;
  742.  
  743.     /*
  744.      *  Display the boxed options.
  745.      */
  746.     for (i = 0; i <= num_options; i++, opt_ptr = opt_ptr->next) {
  747.     if (i >= window_offset && i - window_offset < length) {
  748. #ifdef USE_SLANG
  749.         SLsmg_gotorc(top + ((i + 1) - window_offset), (lx - 1 + 2));
  750.         SLsmg_write_nstring(opt_ptr->name, width);
  751. #else
  752.         wmove(form_window, ((i + 1) - window_offset), 2);
  753.         paddstr(form_window, width, opt_ptr->name);
  754. #endif /* USE_SLANG */
  755.     }
  756.     }
  757. #ifdef USE_SLANG
  758.     SLsmg_draw_box(top, (lx - 1), (bottom - top), (width + 4));
  759. #else
  760. #ifdef VMS
  761.     VMSbox(form_window, (bottom - top), (width + 4));
  762. #else
  763.     LYbox(form_window, TRUE);
  764. #endif /* VMS */
  765.     wrefresh(form_window);
  766. #endif /* USE_SLANG */
  767.     opt_ptr = NULL;
  768.  
  769.     /*
  770.      *  Loop on user input.
  771.      */
  772.     while (cmd != LYK_ACTIVATE) {
  773.  
  774.     /*
  775.      *  Unreverse cur selection.
  776.      */
  777.     if (opt_ptr != NULL) {
  778. #ifdef USE_SLANG
  779.         SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 2));
  780.         SLsmg_write_nstring(opt_ptr->name, width);
  781. #else
  782.         wmove(form_window, ((i + 1) - window_offset), 2);
  783.         paddstr(form_window, width, opt_ptr->name);
  784. #endif /* USE_SLANG */
  785.     }
  786.  
  787.     opt_ptr = list;
  788.  
  789.     for (i = 0; i < cur_selection; i++, opt_ptr = opt_ptr->next)
  790.         ; /* null body */
  791.  
  792. #ifdef USE_SLANG
  793.     SLsmg_set_color(2);
  794.     SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 2));
  795.     SLsmg_write_nstring(opt_ptr->name, width);
  796.     SLsmg_set_color(0);
  797.     /*
  798.      *  If LYShowCursor is ON, move the cursor to the left
  799.      *  of the current option, so that blind users, who are
  800.      *  most likely to have LYShowCursor ON, will have it's
  801.      *  string spoken or passed to the braille interface as
  802.      *  each option is made current.  Otherwise, move it to
  803.      *  the bottom, right column of the screen, to "hide"
  804.      *  the cursor as for the main document, and let sighted
  805.      *  users rely on the current option's highlighting or
  806.      *  color without the distraction of a blinking cursor
  807.      *  in the window. - FM
  808.      */
  809.     if (LYShowCursor)
  810.         SLsmg_gotorc((top + ((i + 1) - window_offset)), (lx - 1 + 1));
  811.     else
  812.         SLsmg_gotorc((LYlines - 1), (LYcols - 1));
  813.     SLsmg_refresh();
  814. #else
  815.     wstart_reverse(form_window);
  816.     wmove(form_window, ((i + 1) - window_offset), 2);
  817.     paddstr(form_window, width, opt_ptr->name);
  818.     wstop_reverse(form_window);
  819.     /*
  820.      *  If LYShowCursor is ON, move the cursor to the left
  821.      *  of the current option, so that blind users, who are
  822.      *  most likely to have LYShowCursor ON, will have it's
  823.      *  string spoken or passed to the braille interface as
  824.      *  each option is made current.  Otherwise, leave it to
  825.      *  the right of the current option, since we can't move
  826.      *  it out of the window, and let sighted users rely on
  827.      *  the highlighting of the current option without the
  828.      *  distraction of a blinking cursor preceding it. - FM
  829.      */
  830.     if (LYShowCursor)
  831.         wmove(form_window, ((i + 1) - window_offset), 1);
  832.     wrefresh(form_window);
  833. #endif /* USE_SLANG  */
  834.  
  835.     c = LYgetch();
  836.     if (c == 3 || c == 7)    /* Control-C or Control-G */
  837.         cmd = LYK_QUIT;
  838.     else
  839.         cmd = keymap[c+1];
  840. #ifdef VMS
  841.     if (HadVMSInterrupt) {
  842.         HadVMSInterrupt = FALSE;
  843.         cmd = LYK_QUIT;
  844.     }
  845. #endif /* VMS */
  846.  
  847.     switch(cmd) {
  848.         case LYK_F_LINK_NUM:
  849.         c = '\0';
  850.         case LYK_1:
  851.         case LYK_2:
  852.         case LYK_3:
  853.         case LYK_4:
  854.         case LYK_5:
  855.         case LYK_6:
  856.         case LYK_7:
  857.         case LYK_8:
  858.         case LYK_9:
  859.         /*
  860.          *  Get a number from the user, possibly with
  861.          *  a 'g' or 'p' suffix (which will be loaded
  862.          *  into c). - FM & LE
  863.          */
  864.         number = get_popup_option_number((int *)&c);
  865.  
  866.         /*
  867.          *  Check for a 'p' suffix. - FM
  868.          */
  869.         if (c == 'p') {
  870.             /*
  871.              *  Treat 1 or less as the first page. - FM
  872.              */
  873.             if (number <= 1) {
  874.             if (window_offset == 0) {
  875.                 _statusline(ALREADY_AT_OPTION_BEGIN);
  876.                 sleep(MessageSecs);
  877.                 if (disabled) {
  878.                 _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
  879.                 } else {
  880.                 _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
  881.                 }
  882.                 break;
  883.             }
  884.             window_offset = 0;
  885.             cur_selection = 0;
  886.             if (disabled) {
  887.                 _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
  888.             } else {
  889.                 _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
  890.             }
  891.             goto redraw;
  892.             }
  893.  
  894.             /*
  895.              *  Treat a number equal to or greater than the
  896.              *  number of pages as the last page. - FM
  897.              */
  898.             if (number >= npages) {
  899.             if (window_offset >= ((num_options - length) + 1)) {
  900.                 _statusline(ALREADY_AT_OPTION_END);
  901.                 sleep(MessageSecs);
  902.                 if (disabled) {
  903.                 _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
  904.                 } else {
  905.                 _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
  906.                 }
  907.                 break;
  908.             }
  909.             window_offset = ((npages - 1) * length);
  910.             if (window_offset > (num_options - length)) {
  911.                 window_offset = (num_options - length + 1);
  912.             }
  913.             if (cur_selection < window_offset)
  914.                 cur_selection = window_offset;
  915.             if (disabled) {
  916.                 _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
  917.             } else {
  918.                 _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
  919.             }
  920.             goto redraw;
  921.             }
  922.  
  923.             /*
  924.              *  We want an intermediate page. - FM
  925.              */
  926.             if (((number - 1) * length) == window_offset) {
  927.             sprintf(buffer, ALREADY_AT_OPTION_PAGE, number);
  928.             _statusline(buffer);
  929.             sleep(MessageSecs);
  930.             if (disabled) {
  931.                 _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
  932.             } else {
  933.                 _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
  934.             }
  935.             break;
  936.             }
  937.             cur_selection = window_offset = ((number - 1) * length);
  938.             if (disabled) {
  939.             _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
  940.             } else {
  941.             _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
  942.             }
  943.             goto redraw;
  944.  
  945.         }
  946.  
  947.         /*
  948.          *  Check for a positive number, which signifies
  949.          *  that an option should be sought. - FM
  950.          */
  951.         if (number > 0) {
  952.             /*
  953.              *  Decrement the number so as to correspond
  954.              *  with our cur_selection values. - FM
  955.              */
  956.             number--;
  957.  
  958.             /*
  959.              *  If the number is in range and had no legal
  960.              *  suffix, select the indicated option. - FM
  961.              */
  962.             if (number <= num_options && c == '\0') {
  963.             cur_selection = number;
  964.             cmd = LYK_ACTIVATE;
  965.             break;
  966.             }
  967.  
  968.             /*
  969.              *  Verify that we had a 'g' suffix,
  970.              *  and act on the number. - FM
  971.              */
  972.             if (c == 'g') {
  973.             if (cur_selection == number) {
  974.                 /*
  975.                  *  The option already is current. - FM
  976.                  */
  977.                 sprintf(buffer,
  978.                     OPTION_ALREADY_CURRENT, (number + 1));
  979.                 _statusline(buffer);
  980.                 sleep(MessageSecs);
  981.                 if (disabled) {
  982.                 _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
  983.                 } else {
  984.                 _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
  985.                 }
  986.                 break;
  987.             }
  988.  
  989.             if (number <= num_options) {
  990.                 /*
  991.                  *  The number is in range and had a 'g'
  992.                  *  suffix, so make it the current option,
  993.                  *  scrolling if needed. - FM
  994.                  */
  995.                 j = (number - cur_selection);
  996.                 cur_selection = number;
  997.                 if ((j > 0) &&
  998.                 (cur_selection - window_offset) >= length) {
  999.                 window_offset += j;
  1000.                 if (window_offset > (num_options - length + 1))
  1001.                     window_offset = (num_options - length + 1);
  1002.                 } else if ((cur_selection - window_offset) < 0) {
  1003.                 window_offset -= abs(j);
  1004.                 if (window_offset < 0)
  1005.                     window_offset = 0;
  1006.                 }
  1007.                 if (disabled) {
  1008.                 _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
  1009.                 } else {
  1010.                 _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
  1011.                 }
  1012.                 goto redraw;
  1013.             }
  1014.  
  1015.             /*
  1016.              *  Not in range. - FM
  1017.              */
  1018.             _statusline(BAD_OPTION_NUM_ENTERED);
  1019.             sleep(MessageSecs);
  1020.             }
  1021.         }
  1022.  
  1023.         /*
  1024.          *  Restore the popup statusline. - FM
  1025.          */
  1026.         if (disabled) {
  1027.             _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
  1028.         } else {
  1029.             _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
  1030.         }
  1031.         break;
  1032.  
  1033.         case LYK_PREV_LINK:
  1034.         case LYK_UP_LINK:
  1035.  
  1036.         if (cur_selection > 0)
  1037.             cur_selection--;
  1038.  
  1039.         /*
  1040.          *  Scroll the window up if necessary.
  1041.          */
  1042.         if ((cur_selection - window_offset) < 0) {
  1043.             window_offset--;
  1044.             goto redraw;
  1045.         }
  1046.         break;
  1047.  
  1048.         case LYK_NEXT_LINK:
  1049.         case LYK_DOWN_LINK:
  1050.         if (cur_selection < num_options)
  1051.             cur_selection++;
  1052.  
  1053.         /*
  1054.          *  Scroll the window down if necessary
  1055.          */
  1056.         if ((cur_selection - window_offset) >= length) {
  1057.             window_offset++;
  1058.             goto redraw;
  1059.         }
  1060.         break;
  1061.  
  1062.         case LYK_NEXT_PAGE:
  1063.         /*
  1064.          *  Okay, are we on the last page of the list?
  1065.          *  If not then,
  1066.          */
  1067.         if (window_offset != (num_options - length + 1)) {
  1068.             /*
  1069.              *  Modify the current selection to not be a
  1070.              *  coordinate in the list, but a coordinate
  1071.              *  on the item selected in the window.
  1072.              */
  1073.             cur_selection -= window_offset;
  1074.  
  1075.             /*
  1076.              *  Page down the proper length for the list.
  1077.              *  If simply to far, back up.
  1078.              */
  1079.             window_offset += length;
  1080.             if (window_offset > (num_options - length)) {
  1081.             window_offset = (num_options - length + 1);
  1082.             }
  1083.  
  1084.             /*
  1085.              *  Readjust the current selection to be a
  1086.              *  list coordinate rather than window.
  1087.              *  Redraw this thing.
  1088.              */
  1089.             cur_selection += window_offset;
  1090.             goto redraw;
  1091.         }
  1092.         else if (cur_selection < num_options) {
  1093.             /*
  1094.              *  Already on last page of the list so just
  1095.              *  redraw it with the last item selected.
  1096.              */
  1097.             cur_selection = num_options;
  1098.         }
  1099.         break;
  1100.  
  1101.         case LYK_PREV_PAGE:
  1102.         /*
  1103.          *  Are we on the first page of the list?
  1104.          *  If not then,
  1105.          */
  1106.         if (window_offset != 0) {
  1107.             /*
  1108.              *  Modify the current selection to not be a
  1109.              *  list coordinate, but a window coordinate.
  1110.              */
  1111.             cur_selection -= window_offset;
  1112.  
  1113.             /*
  1114.              *  Page up the proper length.
  1115.              *  If too far, back up.
  1116.              */
  1117.             window_offset -= length;
  1118.             if (window_offset < 0) {
  1119.             window_offset = 0;
  1120.             }
  1121.  
  1122.             /*
  1123.              *  Readjust the current selection.
  1124.              */
  1125.             cur_selection += window_offset;
  1126.             goto redraw;
  1127.         } else if (cur_selection > 0) {
  1128.             /*
  1129.              *  Already on the first page so just
  1130.              *  back up to the first item.
  1131.              */
  1132.             cur_selection = 0;
  1133.         }
  1134.         break;
  1135.  
  1136.         case LYK_HOME:
  1137.         cur_selection = 0;
  1138.         if (window_offset > 0) {
  1139.             window_offset = 0;
  1140.             goto redraw;
  1141.         }
  1142.         break;
  1143.  
  1144.         case LYK_END:
  1145.         cur_selection = num_options;
  1146.         if (window_offset != (num_options - length + 1)) {
  1147.             window_offset = (num_options - length + 1);
  1148.             goto redraw;
  1149.         }
  1150.         break;
  1151.  
  1152.         case LYK_DOWN_TWO:
  1153.         cur_selection += 2;
  1154.         if (cur_selection > num_options)
  1155.             cur_selection = num_options;
  1156.  
  1157.         /*
  1158.          *  Scroll the window down if necessary.
  1159.          */
  1160.         if ((cur_selection - window_offset) >= length) {
  1161.             window_offset += 2;
  1162.             if (window_offset > (num_options - length + 1))
  1163.             window_offset = (num_options - length + 1);
  1164.             goto redraw;
  1165.         }
  1166.         break;
  1167.  
  1168.         case LYK_UP_TWO:
  1169.         cur_selection -= 2;
  1170.         if (cur_selection < 0)
  1171.             cur_selection = 0;
  1172.  
  1173.         /*
  1174.          *  Scroll the window up if necessary.
  1175.          */
  1176.         if ((cur_selection - window_offset) < 0) {
  1177.             window_offset -= 2;
  1178.             if (window_offset < 0)
  1179.             window_offset = 0;
  1180.             goto redraw;
  1181.         }
  1182.         break;
  1183.  
  1184.         case LYK_DOWN_HALF:
  1185.         cur_selection += (length/2);
  1186.         if (cur_selection > num_options)
  1187.             cur_selection = num_options;
  1188.  
  1189.         /*
  1190.          *  Scroll the window down if necessary.
  1191.          */
  1192.         if ((cur_selection - window_offset) >= length) {
  1193.             window_offset += (length/2);
  1194.             if (window_offset > (num_options - length + 1))
  1195.             window_offset = (num_options - length + 1);
  1196.             goto redraw;
  1197.         }
  1198.         break;
  1199.  
  1200.         case LYK_UP_HALF:
  1201.         cur_selection -= (length/2);
  1202.         if (cur_selection < 0)
  1203.             cur_selection = 0;
  1204.  
  1205.         /*
  1206.          *  Scroll the window up if necessary.
  1207.          */
  1208.         if ((cur_selection - window_offset) < 0) {
  1209.             window_offset -= (length/2);
  1210.             if (window_offset < 0)
  1211.             window_offset = 0;
  1212.             goto redraw;
  1213.         }
  1214.         break;
  1215.  
  1216.         case LYK_REFRESH:
  1217.         lynx_force_repaint();
  1218.         refresh();
  1219.         break;
  1220.  
  1221.         case LYK_NEXT:
  1222.         if (recall && *prev_target_buffer == '\0') {
  1223.             /*
  1224.              *  We got a 'n'ext command with no prior query
  1225.              *  specified within the popup window.  See if
  1226.              *  one was entered when the popup was retracted,
  1227.              *  and if so, assume that's what's wanted.  Note
  1228.              *  that it will become the default within popups,
  1229.              *  unless another is entered within a popup.  If
  1230.              *  the within popup default is to be changed at
  1231.              *  that point, use WHEREIS ('/') and enter it,
  1232.              *  or the up- or down-arrow keys to seek any of
  1233.              *  the previously entered queries, regardless of
  1234.              *  whether they were entered within or outside
  1235.              *  of a popup window. - FM
  1236.              */
  1237.             if ((cp = (char *)HTList_objectAt(search_queries,
  1238.                               0)) != NULL) {
  1239.             strcpy(prev_target_buffer, cp);
  1240.             QueryNum = 0;
  1241.             FirstRecall = FALSE;
  1242.             }
  1243.         }
  1244.         strcpy(prev_target, prev_target_buffer);
  1245.         case LYK_WHEREIS:
  1246.         if (*prev_target == '\0' ) {
  1247.             _statusline(ENTER_WHEREIS_QUERY);
  1248.             if ((ch = LYgetstr(prev_target, VISIBLE,
  1249.                        sizeof(prev_target_buffer),
  1250.                        recall)) < 0) {
  1251.             /*
  1252.              *  User cancelled the search via ^G. - FM
  1253.              */
  1254.             _statusline(CANCELLED);
  1255.             sleep(InfoSecs);
  1256.             goto restore_popup_statusline;
  1257.             }
  1258.         }
  1259.  
  1260. check_recall:
  1261.         if (*prev_target == '\0' &&
  1262.             !(recall && (ch == UPARROW || ch == DNARROW))) {
  1263.             /*
  1264.              *  No entry.  Simply break.   - FM
  1265.              */
  1266.             _statusline(CANCELLED);
  1267.             sleep(InfoSecs);
  1268.             goto restore_popup_statusline;
  1269.         }
  1270.  
  1271.         if (recall && ch == UPARROW) {
  1272.             if (FirstRecall) {
  1273.             /*
  1274.              *  Use the current string or
  1275.              *  last query in the list. - FM
  1276.              */
  1277.             FirstRecall = FALSE;
  1278.             if (*prev_target_buffer) {
  1279.                 for (QueryNum = (QueryTotal - 1);
  1280.                  QueryNum > 0; QueryNum--) {
  1281.                 if ((cp = (char *)HTList_objectAt(
  1282.                             search_queries,
  1283.                             QueryNum)) != NULL &&
  1284.                     !strcmp(prev_target_buffer, cp)) {
  1285.                     break;
  1286.                 }
  1287.                 }
  1288.             } else {
  1289.                 QueryNum = 0;
  1290.             }
  1291.             } else {
  1292.             /*
  1293.              *  Go back to the previous query in the list. - FM
  1294.              */
  1295.             QueryNum++;
  1296.             }
  1297.             if (QueryNum >= QueryTotal)
  1298.             /*
  1299.              *  Roll around to the last query in the list. - FM
  1300.              */
  1301.             QueryNum = 0;
  1302.             if ((cp = (char *)HTList_objectAt(search_queries,
  1303.                               QueryNum)) != NULL) {
  1304.             strcpy(prev_target, cp);
  1305.             if (*prev_target_buffer &&
  1306.                 !strcmp(prev_target_buffer, prev_target)) {
  1307.                 _statusline(EDIT_CURRENT_QUERY);
  1308.             } else if ((*prev_target_buffer && QueryTotal == 2) ||
  1309.                    (!(*prev_target_buffer) &&
  1310.                       QueryTotal == 1)) {
  1311.                 _statusline(EDIT_THE_PREV_QUERY);
  1312.             } else {
  1313.                 _statusline(EDIT_A_PREV_QUERY);
  1314.             }
  1315.             if ((ch = LYgetstr(prev_target, VISIBLE,
  1316.                 sizeof(prev_target_buffer), recall)) < 0) {
  1317.                 /*
  1318.                  *  User cancelled the search via ^G. - FM
  1319.                  */
  1320.                 _statusline(CANCELLED);
  1321.                 sleep(InfoSecs);
  1322.                 goto restore_popup_statusline;
  1323.             }
  1324.             goto check_recall;
  1325.             }
  1326.         } else if (recall && ch == DNARROW) {
  1327.             if (FirstRecall) {
  1328.             /*
  1329.              *  Use the current string or
  1330.              *  first query in the list. - FM
  1331.              */
  1332.             FirstRecall = FALSE;
  1333.             if (*prev_target_buffer) {
  1334.             for (QueryNum = 0;
  1335.                  QueryNum < (QueryTotal - 1); QueryNum++) {
  1336.                 if ((cp = (char *)HTList_objectAt(
  1337.                             search_queries,
  1338.                             QueryNum)) != NULL &&
  1339.                 !strcmp(prev_target_buffer, cp)) {
  1340.                     break;
  1341.                 }
  1342.             }
  1343.             } else {
  1344.             QueryNum = (QueryTotal - 1);
  1345.             }
  1346.         } else {
  1347.             /*
  1348.              *  Advance to the next query in the list. - FM
  1349.              */
  1350.             QueryNum--;
  1351.         }
  1352.         if (QueryNum < 0)
  1353.             /*
  1354.              *  Roll around to the first query in the list. - FM
  1355.              */
  1356.             QueryNum = (QueryTotal - 1);
  1357.             if ((cp = (char *)HTList_objectAt(search_queries,
  1358.                               QueryNum)) != NULL) {
  1359.             strcpy(prev_target, cp);
  1360.             if (*prev_target_buffer &&
  1361.                 !strcmp(prev_target_buffer, prev_target)) {
  1362.                 _statusline(EDIT_CURRENT_QUERY);
  1363.             } else if ((*prev_target_buffer &&
  1364.                     QueryTotal == 2) ||
  1365.                    (!(*prev_target_buffer) &&
  1366.                     QueryTotal == 1)) {
  1367.                 _statusline(EDIT_THE_PREV_QUERY);
  1368.             } else {
  1369.                 _statusline(EDIT_A_PREV_QUERY);
  1370.             }
  1371.             if ((ch = LYgetstr(prev_target, VISIBLE,
  1372.                        sizeof(prev_target_buffer),
  1373.                        recall)) < 0) {
  1374.                 /*
  1375.                  * User cancelled the search via ^G. - FM
  1376.                  */
  1377.                 _statusline(CANCELLED);
  1378.                 sleep(InfoSecs);
  1379.                 goto restore_popup_statusline;
  1380.             }
  1381.             goto check_recall;
  1382.             }
  1383.         }
  1384.         /*
  1385.          *  Replace the search string buffer with the new target. - FM
  1386.          */
  1387.         strcpy(prev_target_buffer, prev_target);
  1388.         HTAddSearchQuery(prev_target_buffer);
  1389.  
  1390.         /*
  1391.          *  Start search at the next option. - FM
  1392.          */
  1393.         for (j = 1, tmp_ptr = opt_ptr->next;
  1394.              tmp_ptr != NULL; tmp_ptr = tmp_ptr->next, j++) {
  1395.             if (case_sensitive) {
  1396.             if (strstr(tmp_ptr->name, prev_target_buffer) != NULL)
  1397.                 break;
  1398.             } else {
  1399.             if (LYstrstr(tmp_ptr->name, prev_target_buffer) != NULL)
  1400.                 break;
  1401.             }
  1402.         }
  1403.         if (tmp_ptr != NULL) {
  1404.             /*
  1405.              *  We have a hit, so make that option the current. - FM
  1406.              */
  1407.             cur_selection += j;
  1408.             /*
  1409.              *  Scroll the window down if necessary.
  1410.              */
  1411.             if ((cur_selection - window_offset) >= length) {
  1412.             window_offset += j;
  1413.             if (window_offset > (num_options - length + 1))
  1414.                 window_offset = (num_options - length + 1);
  1415.             ReDraw = TRUE;
  1416.             }
  1417.             goto restore_popup_statusline;
  1418.         }
  1419.  
  1420.         /*
  1421.          *  If we started at the beginning, it can't be present. - FM
  1422.          */
  1423.         if (cur_selection == 0) {
  1424.             _user_message(STRING_NOT_FOUND, prev_target_buffer);
  1425.             sleep(MessageSecs);
  1426.             goto restore_popup_statusline;
  1427.         }
  1428.  
  1429.         /*
  1430.          *  Search from the beginning to the current option. - FM
  1431.          */
  1432.         for (j = 0, tmp_ptr = list;
  1433.              j < cur_selection; tmp_ptr = tmp_ptr->next, j++) {
  1434.             if (case_sensitive) {
  1435.             if (strstr(tmp_ptr->name, prev_target_buffer) != NULL)
  1436.                 break;
  1437.             } else {
  1438.             if (LYstrstr(tmp_ptr->name, prev_target_buffer) != NULL)
  1439.                 break;
  1440.             }
  1441.         }
  1442.         if (j < cur_selection) {
  1443.             /*
  1444.              *  We have a hit, so make that option the current. - FM
  1445.              */
  1446.             j = (cur_selection - j);
  1447.             cur_selection -= j;
  1448.             /*
  1449.              *  Scroll the window up if necessary.
  1450.              */
  1451.             if ((cur_selection - window_offset) < 0) {
  1452.             window_offset -= j;
  1453.             if (window_offset < 0)
  1454.                 window_offset = 0;
  1455.             ReDraw = TRUE;
  1456.             }
  1457.             goto restore_popup_statusline;
  1458.         }
  1459.  
  1460.         /*
  1461.          *  Didn't find it in the preceding options either. - FM
  1462.          */
  1463.         _user_message(STRING_NOT_FOUND, prev_target_buffer);
  1464.         sleep(MessageSecs);
  1465.  
  1466. restore_popup_statusline:
  1467.         /*
  1468.          *  Restore the popup statusline and
  1469.          *  reset the search variables. - FM
  1470.          */
  1471.         if (disabled)
  1472.             _statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
  1473.         else
  1474.             _statusline(FORM_LINK_OPTION_LIST_MESSAGE);
  1475.         *prev_target = '\0';
  1476.         QueryTotal = (search_queries ? HTList_count(search_queries)
  1477.                          : 0);
  1478.         recall = ((QueryTotal >= 1) ? RECALL : NORECALL);
  1479.         QueryNum = QueryTotal;
  1480.         if (ReDraw == TRUE) {
  1481.             ReDraw = FALSE;
  1482.             goto redraw;
  1483.         }
  1484.         break;
  1485.  
  1486.         case LYK_QUIT:
  1487.         case LYK_ABORT:
  1488.         case LYK_PREV_DOC:
  1489.         cur_selection = orig_selection;
  1490.         cmd = LYK_ACTIVATE; /* to exit */
  1491.         break;
  1492.     }
  1493.  
  1494.     }
  1495. #ifndef USE_SLANG
  1496.     delwin(form_window);
  1497. #ifdef NCURSES
  1498.     LYsubwindow(0);
  1499. #endif
  1500. #endif /* !USE_SLANG */
  1501.  
  1502.     return(disabled ? orig_selection : cur_selection);
  1503. }
  1504.