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 / LYStrings.c < prev    next >
C/C++ Source or Header  |  1998-05-10  |  46KB  |  2,047 lines

  1. #include <HTUtils.h>
  2. #include <tcp.h>
  3. #include <HTCJK.h>
  4. #include <LYCurses.h>
  5. #include <LYUtils.h>
  6. #include <LYStrings.h>
  7. #include <LYGlobalDefs.h>
  8. #include <GridText.h>
  9. #include <LYKeymap.h>
  10. #include <LYSignal.h>
  11. #include <LYClean.h>
  12. #include <LYMail.h>
  13. #include <LYNews.h>
  14. #include <LYOptions.h>
  15. #include <LYCharSets.h>
  16. #include <HTString.h>
  17.  
  18. #include <ctype.h>
  19.  
  20. #include <LYLeaks.h>
  21.  
  22. #define FREE(x) if (x) {free(x); x = NULL;}
  23.  
  24. extern BOOL HTPassHighCtrlRaw;
  25. extern HTCJKlang HTCJK;
  26.  
  27. /* If you want to add mouse support for some new platform, it's fairly
  28. ** simple to do.  Once you've determined the X and Y coordinates of
  29. ** the mouse event, loop through the elements in the links[] array and
  30. ** see if the coordinates fall within a highlighted link area.    If so,
  31. ** the code must set mouse_link to the index of the chosen link,
  32. ** and return a key value that corresponds to LYK_ACTIVATE.  The
  33. ** LYK_ACTIVATE code in LYMainLoop.c will then check mouse_link
  34. ** and activate that link.  If the mouse event didn't fall within a
  35. ** link, the code should just set mouse_link to -1 and return -1. --AMK
  36. **/
  37.  
  38. /* The number of the link selected w/ the mouse (-1 if none) */
  39. static int mouse_link = -1;
  40.  
  41. /* Return the value of mouse_link, erasing it */
  42. PUBLIC int get_mouse_link NOARGS
  43. {
  44.   int t;
  45.   t=mouse_link;
  46.   mouse_link = -1;
  47.   return t;
  48. }
  49.  
  50. /* Given X and Y coordinates of a mouse event, set mouse_link to the
  51. ** index of the corresponding hyperlink, or set mouse_link to -1 if no
  52. ** link matches the event.  Returns -1 if no link matched the click,
  53. ** or a keycode that must be returned from LYgetch() to activate the
  54. ** link.
  55. **/
  56.  
  57. PRIVATE int set_clicked_link ARGS2(int,x,int,y)
  58. {
  59.   int i;
  60.  
  61.   /* Loop over the links and see if we can get a match */
  62.   for(i=0; i < nlinks && mouse_link == -1; i++) {
  63.     /* Check the first line of the link */
  64.     if ( links[i].hightext != NULL &&
  65.      links[i].ly == y &&
  66.      (x - links[i].lx) < (int)strlen(links[i].hightext ) ) {
  67.       mouse_link=i;
  68.     }
  69.     /* Check the second line */
  70.     if (links[i].hightext2 != NULL &&
  71.     1+links[i].ly == y &&
  72.     (x - links[i].hightext2_offset) < (int)strlen(links[i].hightext2) ) {
  73.       mouse_link=i;
  74.     }
  75.   }
  76.   /* If no link was found, just return a do-nothing code */
  77.   if (mouse_link == -1) return -1;
  78.  
  79.   /* If a link was hit, we must look for a key which will activate LYK_ACTIVATE
  80.   ** XXX The 127 in the following line will depend on the size of the keymap[]
  81.   ** array.  However, usually we'll find LYK_ACTIVATE somewhere in the first
  82.   ** 127 keys (it's usually mapped to the Enter key)
  83.   **/
  84.   for (i=0; i<127; i++) {
  85.     if (LYisNonAlnumKeyname(i, LYK_ACTIVATE)) {
  86.       return i;
  87.     }
  88.   }
  89.     /* Whoops!    Nothing's defined as LYK_ACTIVATE!
  90.        Well, who are we to argue with the user?
  91.        Forget about the mouse click */
  92.   mouse_link = -1;
  93.   return -1;
  94. }
  95.  
  96.  
  97. /*
  98.  *  LYstrncpy() terminates strings with a null byte.
  99.  *  Writes a null byte into the n+1 byte of dst.
  100.  */
  101. PUBLIC char *LYstrncpy ARGS3(
  102.     char *,     dst,
  103.     CONST char *,    src,
  104.     int,        n)
  105. {
  106.     char *val;
  107.     int len=strlen(src);
  108.  
  109.     if (n < 0)
  110.     n = 0;
  111.  
  112.     val = strncpy(dst, src, n);
  113.     if (len < n)
  114.     *(dst+len) = '\0';
  115.     else
  116.     *(dst+n) = '\0';
  117.     return val;
  118. }
  119.  
  120. #define IS_NEW_GLYPH(ch) (utf_flag && ((unsigned char)(ch)&0xc0) != 0x80)
  121. #define IS_UTF_EXTRA(ch) (utf_flag && ((unsigned char)(ch)&0xc0) == 0x80)
  122.  
  123. /*
  124.  *  LYmbcsstrncpy() terminates strings with a null byte.
  125.  *  It takes account of multibyte characters.
  126.  *  The src string is copied until either end of string or max number of
  127.  *  either bytes or glyphs (mbcs sequences) (CJK or UTF8).  The utf_flag
  128.  *  argument should be TRUE for UTF8. - KW & FM
  129.  */
  130. PUBLIC char * LYmbcsstrncpy ARGS5(
  131.     char *,     dst,
  132.     CONST char *,    src,
  133.     int,        n_bytes,
  134.     int,        n_glyphs,
  135.     BOOL,        utf_flag)
  136. {
  137.     char *val = dst;
  138.     int i_bytes = 0, i_glyphs = 0;
  139.  
  140.     if (n_bytes < 0)
  141.     n_bytes = 0;
  142.     if (n_glyphs < 0)
  143.     n_glyphs = 0;
  144.  
  145.     for (; *src != '\0' && i_bytes < n_bytes; i_bytes++) {
  146.     if (IS_NEW_GLYPH(*src)) {
  147.         if (i_glyphs++ >= n_glyphs) {
  148.         *dst = '\0';
  149.         return val;
  150.         }
  151.     }
  152.     *(dst++) = *(src++);
  153.     }
  154.     *dst = '\0';
  155.  
  156.     return val;
  157. }
  158.  
  159. /*
  160.  *  LYmbcs_skip_glyphs() skips a given number of display positions
  161.  *  in a string and returns the resulting pointer.  It takes account
  162.  *  of UTF-8 encoded characters. - KW
  163.  */
  164. PUBLIC char * LYmbcs_skip_glyphs ARGS3(
  165.     char *,     data,
  166.     int,        n_glyphs,
  167.     BOOL,        utf_flag)
  168. {
  169.     int i_glyphs = 0;
  170.  
  171.     if (n_glyphs < 0)
  172.     n_glyphs = 0;
  173.  
  174.     if (!data)
  175.     return NULL;
  176.     if (!utf_flag)
  177.     return (data + n_glyphs);
  178.  
  179.     while (*data) {
  180.     if (IS_NEW_GLYPH(*data)) {
  181.         if (i_glyphs++ >= n_glyphs) {
  182.         return data;
  183.         }
  184.     }
  185.     data++;
  186.     }
  187.     return data;
  188. }
  189.  
  190. /*
  191.  *  LYmbcsstrlen() returns the printable length of a string
  192.  *  that might contain IsSpecial or multibyte (CJK or UTF8)
  193.  *  characters. - FM
  194.  */
  195. PUBLIC int LYmbcsstrlen ARGS2(
  196.     char *,     str,
  197.     BOOL,        utf_flag)
  198. {
  199.     int i, j, len = 0;
  200.  
  201.     if (!str && *str)
  202.     return(len);
  203.  
  204.     for (i = 0; str[i] != '\0'; i++) {
  205.     if (IsSpecialAttrChar(str[i])) {
  206.         continue;
  207.     } else {
  208.         len++;
  209.     }
  210.     if (IS_NEW_GLYPH(str[i])) {
  211.         j = 0;
  212.         while (str[(i + 1)] != '\0' &&
  213.            !IsSpecialAttrChar(str[(i + 1)]) &&
  214.            j < 5 &&
  215.            IS_UTF_EXTRA(str[(i + 1)])) {
  216.         i++;
  217.         j++;
  218.         }
  219.     } else if (!utf_flag && HTCJK != NOCJK && !isascii(str[i]) &&
  220.             str[(i + 1)] != '\0' &&
  221.             !IsSpecialAttrChar(str[(i + 1)])) {
  222.         i++;
  223.     }
  224.     }
  225.  
  226.     return(len);
  227. }
  228.  
  229. #undef GetChar
  230.  
  231. #ifdef USE_SLANG
  232. #ifdef VMS
  233. #define GetChar() ttgetc()
  234. #else
  235. #ifdef __DJGPP__
  236. #define GetChar SLkp_getkey
  237. #else
  238. #define GetChar (int)SLang_getkey
  239. #endif /* __DJGPP__ */
  240. #endif /* VMS */
  241. #endif /* USE_SLANG */
  242.  
  243. #if !defined(GetChar) && defined(NCURSES)
  244. #define GetChar() wgetch(my_subwindow ? my_subwindow : stdscr)
  245. #endif
  246.  
  247. #if !defined(GetChar) && defined(SNAKE)
  248. #define GetChar() wgetch(stdscr)
  249. #endif
  250.  
  251. #if !defined(GetChar) && defined(VMS)
  252. #define GetChar() ttgetc()
  253. #endif
  254.  
  255. #if !defined(GetChar)
  256. #if HAVE_KEYPAD
  257. #define GetChar getch
  258. #else
  259. #ifndef USE_GETCHAR
  260. #define USE_GETCHAR
  261. #endif /* !USE_GETCHAR */
  262. #define GetChar() getchar()  /* used to be "getc(stdin)" and "getch()" */
  263. #endif /* HAVE_KEYPAD */
  264. #endif /* !defined(GetChar) */
  265.  
  266. #if defined(NCURSES)
  267. /*
  268.  * Workaround a bug in ncurses order-of-refresh by setting a pointer to
  269.  * the topmost window that should be displayed.
  270.  */
  271. PRIVATE WINDOW *my_subwindow;
  272.  
  273. PUBLIC void LYsubwindow ARGS1(WINDOW *, param)
  274. {
  275.     my_subwindow = param;
  276. }
  277. #endif
  278.  
  279. #ifdef USE_SLANG_MOUSE
  280. PRIVATE int sl_parse_mouse_event ARGS3(int *, x, int *, y, int *, button)
  281. {
  282.     /* "ESC [ M" has already been processed.  There more characters are
  283.      * expected:  BUTTON X Y
  284.      */
  285.     *button = SLang_getkey ();
  286.     switch (*button)
  287.     {
  288.     case 040:            /* left button */
  289.     case 041:            /* middle button */
  290.     case 042:            /* right button */
  291.     *button -= 040;
  292.     break;
  293.  
  294.     default:            /* Hmmm.... */
  295.     SLang_flush_input ();
  296.     return -1;
  297.     }
  298.  
  299.     *x = SLang_getkey () - 33;
  300.     *y = SLang_getkey () - 33;
  301.     return 0;
  302. }
  303. #endif
  304.  
  305. #if defined(USE_SLANG_MOUSE) || defined(NCURSES_MOUSE_VERSION)
  306. PRIVATE int map_function_to_key ARGS1(char, keysym)
  307. {
  308.    int i;
  309.  
  310.    /* I would prefer to use sizeof keymap but its size is not available.
  311.     * A better method would be to declare it as some fixed size.
  312.     */
  313.    for (i = 1; i < 256; i++)
  314.      {
  315.     if (keymap[i] == keysym)
  316.       return i - 1;
  317.      }
  318.    return -1;
  319. }
  320. #endif
  321.  
  322. #if defined(USE_SLANG_MOUSE)
  323. PRIVATE int sl_read_mouse_event NOARGS
  324. {
  325.    int mouse_x, mouse_y, button;
  326.  
  327.    mouse_link = -1;
  328.    if (-1 != sl_parse_mouse_event (&mouse_x, &mouse_y, &button))
  329.      {
  330.     if (button == 0)  /* left */
  331.       return set_clicked_link (mouse_x, mouse_y);
  332.  
  333.     if (button == 2)   /* right */
  334.       {
  335.          /* Right button: go back to prev document.
  336.           * The problem is that we need to determine
  337.           * what to return to achieve this.
  338.           */
  339.          return map_function_to_key (LYK_PREV_DOC);
  340.       }
  341.      }
  342.    return -1;
  343. }
  344. #endif
  345.  
  346. PRIVATE BOOLEAN csi_is_csi = TRUE;
  347. PUBLIC void ena_csi ARGS1(
  348.     BOOLEAN,    flag)
  349. {
  350.     csi_is_csi = flag;
  351. }
  352.  
  353. #if defined(USE_SLANG_KEYMAPS)
  354. static SLKeyMap_List_Type *Keymap_List;
  355.  
  356. /* This value should be larger than anything in LYStrings.h */
  357. #define MOUSE_KEYSYM 0x1000
  358.  
  359. typedef struct
  360. {
  361.    char *name;
  362.    int keysym;
  363. }
  364. Keysym_String_List;
  365.  
  366. static Keysym_String_List Keysym_Strings [] =
  367. {
  368.    {"UPARROW",        UPARROW},
  369.    {"DNARROW",        DNARROW},
  370.    {"RTARROW",        RTARROW},
  371.    {"LTARROW",        LTARROW},
  372.    {"PGDOWN",        PGDOWN},
  373.    {"PGUP",        PGUP},
  374.    {"HOME",        HOME},
  375.    {"END",        END_KEY},
  376.    {"F1",        F1},
  377.    {"DO_KEY",        DO_KEY},
  378.    {"FIND_KEY",        FIND_KEY},
  379.    {"SELECT_KEY",    SELECT_KEY},
  380.    {"INSERT_KEY",    INSERT_KEY},
  381.    {"REMOVE_KEY",    REMOVE_KEY},
  382.    {"DO_NOTHING",    DO_NOTHING},
  383.    {NULL, -1}
  384. };
  385.  
  386. static int map_string_to_keysym (char *str, int *keysym)
  387. {
  388.    Keysym_String_List *k;
  389.  
  390.    k = Keysym_Strings;
  391.    while (k->name != NULL)
  392.      {
  393.     if (0 == strcmp (k->name, str))
  394.       {
  395.          *keysym = k->keysym;
  396.          return 0;
  397.       }
  398.     k++;
  399.      }
  400.    fprintf (stderr, "Keysym %s is unknown\n", str);
  401.    *keysym = -1;
  402.    return -1;
  403. }
  404.  
  405.  
  406. /* The second argument may either be a string or and integer */
  407. static int setkey_cmd (int argc GCC_UNUSED, SLcmd_Cmd_Table_Type *table)
  408. {
  409.    char *keyseq;
  410.    int keysym;
  411.  
  412.    keyseq = table->string_args [1];
  413.    switch (table->arg_type[2])
  414.      {
  415.       case SLANG_INT_TYPE:
  416.     keysym = table->int_args[2];
  417.     break;
  418.  
  419.       case SLANG_STRING_TYPE:
  420.         if (-1 == map_string_to_keysym (table->string_args[2], &keysym))
  421.       return -1;
  422.     break;
  423.  
  424.       default:
  425.     return -1;
  426.      }
  427.  
  428.    return SLkm_define_keysym (keyseq, keysym, Keymap_List);
  429. }
  430.  
  431. static int unsetkey_cmd (int argc GCC_UNUSED, SLcmd_Cmd_Table_Type *table)
  432. {
  433.    SLang_undefine_key (table->string_args[1], Keymap_List);
  434.    if (SLang_Error) return -1;
  435.    return 0;
  436. }
  437.  
  438. static SLcmd_Cmd_Type Keymap_Cmd_Table [] =
  439. {
  440.    {setkey_cmd,   "setkey",   "SG"},
  441.    {unsetkey_cmd, "unsetkey", "S"},
  442.    {NULL}
  443. };
  444.  
  445. static int read_keymap_file NOARGS
  446. {
  447.    char line[1024];
  448.    FILE *fp;
  449.    char file[1024];
  450.    char *home;
  451.    char *keymap_file;
  452.    int ret;
  453.    SLcmd_Cmd_Table_Type tbl;
  454.    int linenum;
  455.  
  456. #ifdef VMS
  457.    keymap_file = "lynx.keymaps";
  458.    home = "SYS$LOGIN:";
  459. #else
  460.    keymap_file = "/.lynx-keymaps";
  461.    home = getenv ("HOME");
  462.    if (home == NULL) home = "";
  463. #endif
  464.  
  465.    sprintf (file, "%s%s", home, keymap_file);
  466.  
  467.    if (NULL == (fp = fopen (file, "r")))
  468.      return 0;
  469.  
  470.    tbl.table = Keymap_Cmd_Table;
  471.  
  472.    linenum = 0;
  473.    ret = 0;
  474.    while (NULL != fgets (line, sizeof (line), fp))
  475.      {
  476.     char *s = LYSkipBlanks(line);
  477.  
  478.     linenum++;
  479.  
  480.     if ((*s == 0) || (*s == '#'))
  481.       continue;
  482.  
  483.     if (-1 == SLcmd_execute_string (s, &tbl))
  484.       {
  485.          ret = -1;
  486.          break;
  487.       }
  488.      }
  489.  
  490.    fclose (fp);
  491.  
  492.    if (ret == -1)
  493.      fprintf (stderr, "Error processing line %d of %s\n", linenum, file);
  494.  
  495.    return ret;
  496. }
  497.  
  498. int lynx_initialize_keymaps NOARGS
  499. {
  500.    int i;
  501.    char keybuf[2];
  502.  
  503.    if (NULL == (Keymap_List = SLang_create_keymap ("Lynx", NULL)))
  504.      return -1;
  505.  
  506.    keybuf[1] = 0;
  507.    for (i = 1; i < 256; i++)
  508.      {
  509.     keybuf[0] = (char) i;
  510.     SLkm_define_keysym (keybuf, i, Keymap_List);
  511.      }
  512.  
  513.    SLkm_define_keysym ("\033[A",   UPARROW,    Keymap_List);
  514.    SLkm_define_keysym ("\033OA",   UPARROW,    Keymap_List);
  515.    SLkm_define_keysym ("\033[B",   DNARROW,    Keymap_List);
  516.    SLkm_define_keysym ("\033OB",   DNARROW,    Keymap_List);
  517.    SLkm_define_keysym ("\033[C",   RTARROW,    Keymap_List);
  518.    SLkm_define_keysym ("\033OC",   RTARROW,    Keymap_List);
  519.    SLkm_define_keysym ("\033[D",   LTARROW,    Keymap_List);
  520.    SLkm_define_keysym ("\033OD",   LTARROW,    Keymap_List);
  521.    SLkm_define_keysym ("\033[1~",  FIND_KEY,   Keymap_List);
  522.    SLkm_define_keysym ("\033[2~",  INSERT_KEY, Keymap_List);
  523.    SLkm_define_keysym ("\033[3~",  REMOVE_KEY, Keymap_List);
  524.    SLkm_define_keysym ("\033[4~",  SELECT_KEY, Keymap_List);
  525.    SLkm_define_keysym ("\033[5~",  PGUP,       Keymap_List);
  526.    SLkm_define_keysym ("\033[6~",  PGDOWN,     Keymap_List);
  527.    SLkm_define_keysym ("\033[8~",  END_KEY,    Keymap_List);
  528.    SLkm_define_keysym ("\033[7~",  HOME,       Keymap_List);
  529.    SLkm_define_keysym ("\033[28~", F1,         Keymap_List);
  530.    SLkm_define_keysym ("\033[29~", DO_KEY,     Keymap_List);
  531.  
  532.    SLkm_define_keysym ("\033[M", MOUSE_KEYSYM, Keymap_List);
  533.  
  534.    if (SLang_Error
  535.        || (-1 == read_keymap_file ()))
  536.      SLang_exit_error ("Unable to initialize keymaps");
  537.  
  538.    return 0;
  539. }
  540.  
  541. int LYgetch (void)
  542. {
  543.    SLang_Key_Type *key;
  544.    int keysym;
  545.  
  546.    key = SLang_do_key (Keymap_List, (int (*)(void)) GetChar);
  547.    if ((key == NULL) || (key->type != SLKEY_F_KEYSYM))
  548.      return DO_NOTHING;
  549.  
  550.    keysym = key->f.keysym;
  551.  
  552. #if defined (USE_SLANG_MOUSE)
  553.    if (keysym == MOUSE_KEYSYM)
  554.      return sl_read_mouse_event ();
  555. #endif
  556.  
  557.    if ((keysym > DO_NOTHING) || (keysym < 0))
  558.      return 0;
  559.  
  560.    return keysym;
  561. }
  562. #else
  563.  
  564. /*
  565.  *  LYgetch() translates some escape sequences and may fake noecho.
  566.  */
  567. PUBLIC int LYgetch NOARGS
  568. {
  569.     int a, b, c, d = -1;
  570.  
  571. #if defined(IGNORE_CTRL_C) || defined(USE_GETCHAR) || !defined(NCURSES)
  572. re_read:
  573. #endif /* IGNORE_CTRL_C || USE_GETCHAR */
  574. #ifndef USE_SLANG
  575.     clearerr(stdin); /* needed here for ultrix and SOCKETSHR, but why? - FM */
  576. #endif /* !USE_SLANG */
  577. #if !defined(USE_SLANG) || defined(VMS)
  578.     c = GetChar();
  579. #else
  580.     if (LYCursesON) {
  581.     c = GetChar();
  582.     } else {
  583.     c = getchar();
  584.     if (c == EOF && errno == EINTR) /* Ctrl-Z causes EINTR in getchar() */
  585.         clearerr(stdin);
  586.     if (feof(stdin) || ferror(stdin) || c == EOF) {
  587. #ifdef IGNORE_CTRL_C
  588.         if (sigint)
  589.         sigint = FALSE;
  590. #endif /* IGNORE_CTRL_C */
  591.         return(7); /* use ^G to cancel whatever called us. */
  592.     }
  593.    }
  594. #endif /* !USE_SLANG || VMS */
  595.  
  596. /* The RAWDOSKEYHACK takes key definitions from curses.h (when using
  597.  * PDCURSES) or from the DJGPP file keys.h (when using SLANG) and maps
  598.  * them to the values used by the lynx file LYKeymap.c. */
  599.  
  600. #ifdef RAWDOSKEYHACK
  601.     if (raw_dos_key_hack) {
  602.     if (c == 0) c = '/';
  603.     if (c > 255) {        /* handle raw dos keys */
  604.         switch (c)
  605.         {
  606.         case 464: c = '-';    break;    /* keypad minus*/
  607.         case 465: c = '+';    break;    /* keypad plus*/
  608.         case 459: c = 13;    break;    /* keypad enter*/
  609.         case 463: c = '*';    break;    /* keypad * */
  610.         case 440: c = 'Q';    break;    /* alt x */
  611.         case 265: c = 'H';    break;    /* F1 */
  612.         default: break;
  613.         }
  614.     }
  615.     }
  616. #endif /* RAWDOSKEYHACK */
  617.  
  618. #ifdef USE_GETCHAR
  619.     if (c == EOF && errno == EINTR)    /* Ctrl-Z causes EINTR in getchar() */
  620.     goto re_read;
  621. #endif /* USE_GETCHAR */
  622.  
  623. #ifdef USE_SLANG
  624.     if (c == 0xFFFF && LYCursesON) {
  625. #ifdef IGNORE_CTRL_C
  626.     if (sigint) {
  627.         sigint = FALSE;
  628.         goto re_read;
  629.     }
  630. #endif /* IGNORE_CTRL_C */
  631.     return(7); /* use ^G to cancel whatever called us. */
  632.     }
  633. #else
  634.     if (feof(stdin) || ferror(stdin) || c == EOF) {
  635.     if (recent_sizechange)
  636.         return(7); /* use ^G to cancel whatever called us. */
  637. #ifdef IGNORE_CTRL_C
  638.     if (sigint) {
  639.         sigint = FALSE;
  640.         /* clearerr(stdin);  don't need here if stays above - FM */
  641.         goto re_read;
  642.     }
  643. #endif /* IGNORE_CTRL_C */
  644. #if !defined(USE_GETCHAR) && !defined(VMS) && !defined(NCURSES)
  645.     if (c == ERR && errno == EINTR) /* may have been handled signal - kw */
  646.         goto re_read;
  647. #endif /* USE_GETCHAR */
  648.  
  649.     cleanup();
  650. #ifndef NOSIGHUP
  651.     (void) signal(SIGHUP, SIG_DFL);
  652. #endif /* NOSIGHUP */
  653.     (void) signal(SIGTERM, SIG_DFL);
  654. #ifndef VMS
  655.     (void) signal(SIGINT, SIG_DFL);
  656. #endif /* !VMS */
  657. #ifdef SIGTSTP
  658.     if (no_suspend)
  659.       (void) signal(SIGTSTP,SIG_DFL);
  660. #endif /* SIGTSTP */
  661.     exit(0);
  662.     }
  663. #endif /* USE_SLANG */
  664.  
  665.     if (c == 27 || (csi_is_csi && c == 155)) {        /* handle escape sequence */
  666.     b = GetChar();
  667.  
  668.     if (b == '[' || b == 'O') {
  669.         a = GetChar();
  670.     } else {
  671.         a = b;
  672.     }
  673.  
  674.     switch (a) {
  675.     case 'A': c = UPARROW; break;
  676.     case 'x': c = UPARROW; break;  /* keypad up on pc ncsa telnet */
  677.     case 'B': c = DNARROW; break;
  678.     case 'r': c = DNARROW; break; /* keypad down on pc ncsa telnet */
  679.     case 'C': c = RTARROW; break;
  680.     case 'v': c = RTARROW; break; /* keypad right on pc ncsa telnet */
  681.     case 'D': c = LTARROW; break;
  682.     case 't': c = LTARROW; break;  /* keypad left on pc ncsa telnet */
  683.     case 'y': c = PGUP;    break;  /* keypad on pc ncsa telnet */
  684.     case 's': c = PGDOWN;  break;  /* keypad on pc ncsa telnet */
  685.     case 'w': c = HOME;    break;  /* keypad on pc ncsa telnet */
  686.     case 'q': c = END_KEY; break;  /* keypad on pc ncsa telnet */
  687.     case 'M':
  688. #ifdef USE_SLANG_MOUSE
  689.        if ((c == 27) && (b == '['))
  690.          {
  691.         c = sl_read_mouse_event ();
  692.          }
  693.        else
  694. #endif
  695.          c = '\n'; /* keypad enter on pc ncsa telnet */
  696.        break;
  697.  
  698.     case 'm':
  699. #ifdef VMS
  700.         if (b != 'O')
  701. #endif /* VMS */
  702.         c = '-';  /* keypad on pc ncsa telnet */
  703.         break;
  704.     case 'k':
  705.         if (b == 'O')
  706.         c = '+';  /* keypad + on my xterminal :) */
  707.         break;
  708.     case 'l':
  709. #ifdef VMS
  710.         if (b != 'O')
  711. #endif /* VMS */
  712.         c = '+';  /* keypad on pc ncsa telnet */
  713.         break;
  714.     case 'P':
  715. #ifdef VMS
  716.         if (b != 'O')
  717. #endif /* VMS */
  718.         c = F1;
  719.         break;
  720.     case 'u':
  721. #ifdef VMS
  722.         if (b != 'O')
  723. #endif /* VMS */
  724.         c = F1;  /* macintosh help button */
  725.         break;
  726.     case 'p':
  727. #ifdef VMS
  728.         if (b == 'O')
  729. #endif /* VMS */
  730.         c = '0';  /* keypad 0 */
  731.         break;
  732.     case '1':                /** VTxxx  Find  **/
  733.         if ((b == '[' || c == 155) && (d=GetChar()) == '~')
  734.         c = FIND_KEY;
  735.         break;
  736.     case '2':
  737.         if (b == '[' || c == 155) {
  738.         if ((d=GetChar())=='~')     /** VTxxx Insert **/
  739.             c = INSERT_KEY;
  740.         else if ((d == '8' ||
  741.               d == '9') &&
  742.              GetChar() == '~')
  743.          {
  744.             if (d == '8')         /** VTxxx    Help **/
  745.             c = F1;
  746.             else if (d == '9')         /** VTxxx     Do  **/
  747.             c = DO_KEY;
  748.             d = -1;
  749.          }
  750.         }
  751.         break;
  752.     case '3':                 /** VTxxx Delete **/
  753.         if ((b == '[' || c == 155) && (d=GetChar()) == '~')
  754.         c = REMOVE_KEY;
  755.         break;
  756.     case '4':                 /** VTxxx Select **/
  757.         if ((b == '[' || c == 155) && (d=GetChar()) == '~')
  758.         c = SELECT_KEY;
  759.         break;
  760.     case '5':                 /** VTxxx PrevScreen **/
  761.         if ((b == '[' || c == 155) && (d=GetChar()) == '~')
  762.         c = PGUP;
  763.         break;
  764.     case '6':                 /** VTxxx NextScreen **/
  765.         if ((b == '[' || c == 155) && (d=GetChar()) == '~')
  766.         c = PGDOWN;
  767.         break;
  768.     case '[':                 /** Linux F1-F5: ^[[[A etc. **/
  769.         if (b == '[' || c == 155) {
  770.         if ((d=GetChar()) == 'A')
  771.             c = F1;
  772.         break;
  773.         }
  774.     default:
  775.        if (TRACE) {
  776.         fprintf(tfp,"Unknown key sequence: %d:%d:%d\n",c,b,a);
  777.         if (!LYTraceLogFP) {
  778.             sleep(MessageSecs);
  779.         }
  780.        }
  781.     }
  782.     if (isdigit(a) && (b == '[' || c == 155) && d != -1 && d != '~')
  783.         d = GetChar();
  784.     }
  785. #if defined(__DJGPP__) && defined(USE_SLANG)
  786.     else { /* SLang keypad interface */
  787.     switch (c) {
  788.     case SL_KEY_UP:
  789.         c = UPARROW;
  790.         break;
  791.     case SL_KEY_DOWN:
  792.         c = DNARROW;
  793.         break;
  794.     case SL_KEY_RIGHT:
  795.         c = RTARROW;
  796.         break;
  797.     case SL_KEY_B2:
  798.         c = DO_NOTHING;
  799.         break;
  800.     case SL_KEY_LEFT:
  801.         c = LTARROW;
  802.         break;
  803.     case SL_KEY_PPAGE:
  804.     case SL_KEY_A3:
  805.         c = PGUP;
  806.         break;
  807.     case SL_KEY_NPAGE:
  808.     case SL_KEY_C3:
  809.         c = PGDOWN;
  810.         break;
  811.     case SL_KEY_HOME:
  812.     case SL_KEY_A1:
  813.         c = HOME;
  814.         break;
  815.     case SL_KEY_END:
  816.     case SL_KEY_C1:
  817.         c = END_KEY;
  818.         break;
  819.     case SL_KEY_F(1):
  820.         c = F1;
  821.         break;
  822.     case SL_KEY_BACKSPACE:
  823.         c = 127;
  824.         break;
  825.     }
  826.     }
  827. #endif
  828. #if HAVE_KEYPAD
  829.     else {
  830.     /*
  831.      *  Convert keypad() mode keys into Lynx defined keys.
  832.      */
  833.     switch(c) {
  834.     case KEY_DOWN:           /* The four arrow keys ... */
  835.        c = DNARROW;
  836.        break;
  837.     case KEY_UP:
  838.        c = UPARROW;
  839.        break;
  840.     case KEY_LEFT:
  841.        c = LTARROW;
  842.        break;
  843.     case KEY_RIGHT:        /* ... */
  844.        c = RTARROW;
  845.        break;
  846.     case KEY_HOME:           /* Home key (upward+left arrow) */
  847.        c = HOME;
  848.        break;
  849.     case KEY_CLEAR:        /* Clear screen */
  850.        c = 18; /* CTRL-R */
  851.        break;
  852.     case KEY_NPAGE:        /* Next page */
  853.        c = PGDOWN;
  854.        break;
  855.     case KEY_PPAGE:        /* Previous page */
  856.        c = PGUP;
  857.        break;
  858.     case KEY_LL:           /* home down or bottom (lower left) */
  859.        c = END_KEY;
  860.        break;
  861.                     /* The keypad is arranged like this:*/
  862.                     /*    a1    up      a3   */
  863.                     /*   left   b2    right  */
  864.                     /*    c1   down   c3   */
  865.     case KEY_A1:           /* upper left of keypad */
  866.        c = HOME;
  867.        break;
  868.     case KEY_A3:           /* upper right of keypad */
  869.        c = PGUP;
  870.        break;
  871.     case KEY_B2:           /* center of keypad */
  872.        c = DO_NOTHING;
  873.        break;
  874.     case KEY_C1:           /* lower left of keypad */
  875.        c = END_KEY;
  876.        break;
  877.     case KEY_C3:           /* lower right of keypad */
  878.        c = PGDOWN;
  879.        break;
  880. #ifdef KEY_END
  881.     case KEY_END:           /* end key        001 */
  882.        c = END_KEY;
  883.        break;
  884. #endif /* KEY_END */
  885. #ifdef KEY_HELP
  886.     case KEY_HELP:           /* help key        001 */
  887.        c = F1;
  888.        break;
  889. #endif /* KEY_HELP */
  890. #ifdef KEY_BACKSPACE
  891.     case KEY_BACKSPACE:
  892.        c = 127;           /* backspace key (delete, not Ctrl-H) */
  893.        break;
  894. #endif /* KEY_BACKSPACE */
  895. #ifdef KEY_F
  896.     case KEY_F(1):
  897.        c = F1;           /* VTxxx Help */
  898.        break;
  899.     case KEY_F(16):
  900.        c = DO_KEY;           /* VTxxx Do */
  901.        break;
  902. #endif /* KEY_F */
  903. #ifdef KEY_REDO
  904.     case KEY_REDO:           /* VTxxx Do */
  905.        c = DO_KEY;
  906.        break;
  907. #endif /* KEY_REDO */
  908. #ifdef KEY_FIND
  909.     case KEY_FIND:
  910.        c = FIND_KEY;       /* VTxxx Find */
  911.        break;
  912. #endif /* KEY_FIND */
  913. #ifdef KEY_SELECT
  914.     case KEY_SELECT:
  915.        c = SELECT_KEY;       /* VTxxx Select */
  916.        break;
  917. #endif /* KEY_SELECT */
  918. #ifdef KEY_IC
  919.     case KEY_IC:
  920.        c = INSERT_KEY;       /* VTxxx Insert */
  921.        break;
  922. #endif /* KEY_IC */
  923. #ifdef KEY_DC
  924.     case KEY_DC:
  925.        c = REMOVE_KEY;       /* VTxxx Remove */
  926.        break;
  927. #endif /* KEY_DC */
  928. #ifdef NCURSES_MOUSE_VERSION
  929.     case KEY_MOUSE:
  930.       {
  931. #ifndef DOSPATH
  932.        MEVENT event;
  933.        int err;
  934.  
  935.        c = -1;
  936.        mouse_link = -1;
  937.        err=getmouse(&event);
  938.        if (event.bstate & BUTTON1_CLICKED) {
  939.          c = set_clicked_link(event.x, event.y);
  940.        } else if (event.bstate & BUTTON3_CLICKED) {
  941.          c = map_function_to_key (LYK_PREV_DOC);
  942.        }
  943. #else /* pdcurses version */
  944.           int left,right;
  945.           /* yes, I am assuming that my screen will be a certain width. */
  946.           left = 6;
  947.           right = LYcols-6;
  948.           c = -1;
  949.           mouse_link = -1;
  950.           request_mouse_pos();
  951.           if (Mouse_status.button[0] & BUTTON_CLICKED) {
  952.         if (Mouse_status.y == (LYlines-1))
  953.                if (Mouse_status.x < left) c=LTARROW;
  954.                else if (Mouse_status.x > right) c='\b';
  955.                else c=PGDOWN;
  956.         else if (Mouse_status.y == 0)
  957.                if (Mouse_status.x < left) c=LTARROW;
  958.                else if (Mouse_status.x > right) c='\b';
  959.                else c=PGUP;
  960.         else c = set_clicked_link(Mouse_status.x, Mouse_status.y);
  961.           }
  962. #endif /* _WINDOWS */
  963.       }
  964.       break;
  965. #endif /* NCURSES_MOUSE_VERSION */
  966.     }
  967.     }
  968. #endif /* HAVE_KEYPAD */
  969.  
  970.     if (c > DO_NOTHING) {
  971.     /*
  972.      *  Don't return raw values for KEYPAD symbols which we may have
  973.      *  missed in the switch above if they are obviously invalid when
  974.      *  used as an index into (e.g.) keypad[]. - KW
  975.      */
  976.     return (0);
  977.     } else {
  978.     return(c);
  979.     }
  980. }
  981.  
  982. #endif                       /* NOT USE_SLANG_KEYMAPS */
  983.  
  984. /*
  985.  * Convert a null-terminated string to lowercase
  986.  */
  987. PUBLIC void LYLowerCase ARGS1(
  988.     char *,     buffer)
  989. {
  990.     size_t i;
  991.     for (i = 0; buffer[i]; i++)
  992.     buffer[i] = TOLOWER(buffer[i]);
  993. }
  994.  
  995. /*
  996.  * Convert a null-terminated string to uppercase
  997.  */
  998. PUBLIC void LYUpperCase ARGS1(
  999.     char *,     buffer)
  1000. {
  1001.     size_t i;
  1002.     for (i = 0; buffer[i]; i++)
  1003.     buffer[i] = TOUPPER(buffer[i]);
  1004. }
  1005.  
  1006. /*
  1007.  * Remove ALL whitespace from a string (including embedded blanks).
  1008.  */
  1009. PUBLIC void LYRemoveBlanks ARGS1(
  1010.     char *,     buffer)
  1011. {
  1012.     if (buffer != 0) {
  1013.     size_t i, j;
  1014.     for (i = j = 0; buffer[i]; i++)
  1015.         if (!isspace((unsigned char)(buffer[i])))
  1016.         buffer[j++] = buffer[i];
  1017.     buffer[j] = 0;
  1018.     }
  1019. }
  1020.  
  1021. /*
  1022.  * Skip whitespace
  1023.  */
  1024. PUBLIC char * LYSkipBlanks ARGS1(
  1025.     char *,     buffer)
  1026. {
  1027.     while (isspace((unsigned char)(*buffer)))
  1028.     buffer++;
  1029.     return buffer;
  1030. }
  1031.  
  1032. /*
  1033.  * Skip non-whitespace
  1034.  */
  1035. PUBLIC char * LYSkipNonBlanks ARGS1(
  1036.     char *,     buffer)
  1037. {
  1038.     while (*buffer != 0 && !isspace((unsigned char)(*buffer)))
  1039.     buffer++;
  1040.     return buffer;
  1041. }
  1042.  
  1043. /*
  1044.  * Skip CONST whitespace
  1045.  */
  1046. PUBLIC CONST char * LYSkipCBlanks ARGS1(
  1047.     CONST char *,    buffer)
  1048. {
  1049.     while (isspace((unsigned char)(*buffer)))
  1050.     buffer++;
  1051.     return buffer;
  1052. }
  1053.  
  1054. /*
  1055.  * Skip CONST non-whitespace
  1056.  */
  1057. PUBLIC CONST char * LYSkipCNonBlanks ARGS1(
  1058.     CONST char *,    buffer)
  1059. {
  1060.     while (*buffer != 0 && !isspace((unsigned char)(*buffer)))
  1061.     buffer++;
  1062.     return buffer;
  1063. }
  1064.  
  1065. /*
  1066.  * Trim leading blanks from a string
  1067.  */
  1068. PUBLIC void LYTrimLeading ARGS1(
  1069.     char *,     buffer)
  1070. {
  1071.     char *skipped = LYSkipBlanks(buffer);
  1072.     while ((*buffer++ = *skipped++) != 0)
  1073.     ;
  1074. }
  1075.  
  1076. /*
  1077.  * Trim trailing blanks from a string
  1078.  */
  1079. PUBLIC void LYTrimTrailing ARGS1(
  1080.     char *,     buffer)
  1081. {
  1082.     size_t i = strlen(buffer);
  1083.     while (i != 0 && isspace((unsigned char)buffer[i-1]))
  1084.     buffer[--i] = 0;
  1085. }
  1086.  
  1087. /*
  1088. **  Display the current value of the string and allow the user
  1089. **  to edit it.
  1090. */
  1091.  
  1092. #define EDREC     EditFieldData
  1093.  
  1094. /*
  1095.  *  Shorthand to get rid of all most of the "edit->suchandsos".
  1096.  */
  1097. #define Buf     edit->buffer
  1098. #define Pos     edit->pos
  1099. #define StrLen     edit->strlen
  1100. #define MaxLen     edit->maxlen
  1101. #define DspWdth  edit->dspwdth
  1102. #define DspStart edit->xpan
  1103. #define Margin     edit->margin
  1104.  
  1105. PUBLIC void LYSetupEdit ARGS4(
  1106.     EDREC *,    edit,
  1107.     char *,     old,
  1108.     int,        maxstr,
  1109.     int,        maxdsp)
  1110. {
  1111.     /*
  1112.      *    Initialize edit record
  1113.      */
  1114.     LYGetYX(edit->sy, edit->sx);
  1115.     edit->pad    = ' ';
  1116.     edit->dirty = TRUE;
  1117.     edit->panon = FALSE;
  1118.  
  1119.     StrLen  = strlen(old);
  1120.     MaxLen  = maxstr;
  1121.     DspWdth = maxdsp;
  1122.     Margin  = 0;
  1123.     Pos = strlen(old);
  1124.     DspStart = 0;
  1125.  
  1126.     if (maxstr > maxdsp) {  /* Need panning? */
  1127.     if (DspWdth > 4)    /* Else "{}" take up precious screen space */
  1128.         edit->panon = TRUE;
  1129.  
  1130.     /*
  1131.      *  Figure out margins.  If too big, we do a lot of unnecessary
  1132.      *  scrolling.    If too small, user doesn't have sufficient
  1133.      *  look-ahead.  Let's say 25% for each margin, upper bound is
  1134.      *  10 columns.
  1135.      */
  1136.     Margin = DspWdth/4;
  1137.     if (Margin > 10)
  1138.         Margin = 10;
  1139.     }
  1140.  
  1141.     /*
  1142.      *    We expect the called function to pass us a default (old) value
  1143.      *    with a length that is less than or equal to maxstr, and to
  1144.      *    handle any messaging associated with actions to achieve that
  1145.      *    requirement.  However, in case the calling function screwed
  1146.      *    up, we'll check it here, and ensure that no buffer overrun can
  1147.      *    occur by loading only as much of the head as fits. - FM
  1148.      */
  1149.     if (strlen(old) >= maxstr) {
  1150.     strncpy(edit->buffer, old, maxstr);
  1151.     edit->buffer[maxstr] = '\0';
  1152.     StrLen = maxstr;
  1153.     } else {
  1154.     strcpy(edit->buffer, old);
  1155.     }
  1156. }
  1157.  
  1158. PUBLIC int LYEdit1 ARGS4(
  1159.     EDREC *,    edit,
  1160.     int,        ch,
  1161.     int,        action,
  1162.     BOOL,        maxMessage)
  1163. {   /* returns 0    character processed
  1164.      *           ch   otherwise
  1165.      */
  1166.     int i;
  1167.     int length;
  1168.  
  1169.     if (MaxLen <= 0)
  1170.     return(0); /* Be defensive */
  1171.  
  1172.     length = strlen(&Buf[0]);
  1173.     StrLen = length;
  1174.  
  1175.     switch (action) {
  1176.     case LYE_AIX:
  1177.     /*
  1178.      *  Hex 97.
  1179.      *  Fall through as a character for CJK, or if this is a valid
  1180.      *  character in the current display character set.
  1181.      *  Otherwise, we treat this as LYE_ENTER.
  1182.      */
  1183.      if (HTCJK == NOCJK && LYlowest_eightbit[current_char_set] > 0x97)
  1184.          return(ch);
  1185.     case LYE_CHAR:
  1186.     /*
  1187.      *  ch is printable or ISO-8859-1 escape character.
  1188.      */
  1189.     if (Pos <= (MaxLen) && StrLen < (MaxLen)) {
  1190.         for(i = length; i >= Pos; i--)    /* Make room */
  1191.         Buf[i+1] = Buf[i];
  1192.         Buf[length+1]='\0';
  1193.         Buf[Pos] = (unsigned char) ch;
  1194.         Pos++;
  1195.     } else if (maxMessage) {
  1196.         _statusline(MAXLEN_REACHED_DEL_OR_MOV);
  1197.     }
  1198.     break;
  1199.  
  1200.     case LYE_BACKW:
  1201.     /*
  1202.      *  Backword.
  1203.      *  Definition of word is very naive: 1 or more a/n characters.
  1204.      */
  1205.     while (Pos && !isalnum(Buf[Pos-1]))
  1206.         Pos--;
  1207.     while (Pos &&  isalnum(Buf[Pos-1]))
  1208.         Pos--;
  1209.     break;
  1210.  
  1211.     case LYE_FORWW:
  1212.     /*
  1213.      *  Word forward.
  1214.      */
  1215.     while (isalnum(Buf[Pos]))
  1216.         Pos++;   /* '\0' is not a/n */
  1217.     while (!isalnum(Buf[Pos]) && Buf[Pos])
  1218.         Pos++ ;
  1219.     break;
  1220.  
  1221.     case LYE_ERASE:
  1222.     /*
  1223.      *  Erase the line to start fresh.
  1224.      */
  1225.      Buf[0] = '\0';
  1226.      /* fall through */
  1227.  
  1228.     case LYE_BOL:
  1229.     /*
  1230.      *  Go to first column.
  1231.      */
  1232.     Pos = 0;
  1233.     break;
  1234.  
  1235.     case LYE_EOL:
  1236.     /*
  1237.      *  Go to last column.
  1238.      */
  1239.     Pos = length;
  1240.     break;
  1241.  
  1242.     case LYE_DELNW:
  1243.     /*
  1244.      *  Delete next word.
  1245.      */
  1246.     {
  1247.         int pos0 = Pos;
  1248.         LYEdit1 (edit, 0, LYE_FORWW, FALSE);
  1249.         while (Pos > pos0)
  1250.         LYEdit1(edit, 0, LYE_DELP, FALSE);
  1251.     }
  1252.     break;
  1253.  
  1254.     case LYE_DELPW:
  1255.     /*
  1256.      *  Delete previous word.
  1257.      */
  1258.     {
  1259.         int pos0 = Pos;
  1260.         LYEdit1 (edit, 0, LYE_BACKW, FALSE);
  1261.         pos0 -= Pos;
  1262.         while (pos0--)
  1263.         LYEdit1(edit, 0, LYE_DELN, FALSE);
  1264.     }
  1265.     break;
  1266.  
  1267.     case LYE_DELN:
  1268.     /*
  1269.      *  Delete next character
  1270.      */
  1271.     if (Pos >= length)
  1272.         break;
  1273.     Pos++;
  1274.     /* fall through */
  1275.  
  1276.     case LYE_DELP:
  1277.     /*
  1278.      *  Delete preceding character.
  1279.      */
  1280.     if (length == 0 || Pos == 0)
  1281.         break;
  1282.     Pos--;
  1283.     for (i = Pos; i < length; i++)
  1284.         Buf[i] = Buf[i+1];
  1285.     i--;
  1286.     Buf[i] = 0;
  1287.     break;
  1288.  
  1289.     case LYE_DELC:
  1290.     /*
  1291.      *  Delete current character.
  1292.      */
  1293.     if (length == 0 || Pos == length)
  1294.         break;
  1295.     for (i = Pos; i < length; i++)
  1296.         Buf[i] = Buf[i+1];
  1297.     i--;
  1298.     Buf[i] = 0;
  1299.     break;
  1300.  
  1301.     case LYE_FORW:
  1302.     /*
  1303.      *  Move cursor to the right.
  1304.      */
  1305.     if (Pos < length)
  1306.         Pos++;
  1307.     break;
  1308.  
  1309.     case LYE_BACK:
  1310.     /*
  1311.      *  Left-arrow move cursor to the left.
  1312.      */
  1313.     if (Pos > 0)
  1314.         Pos--;
  1315.     break;
  1316.  
  1317.     case LYE_UPPER:
  1318.     LYUpperCase(Buf);
  1319.     break;
  1320.  
  1321.     case LYE_LOWER:
  1322.     LYLowerCase(Buf);
  1323.     break;
  1324.  
  1325.     default:
  1326.     return(ch);
  1327.     }
  1328.     edit->dirty = TRUE;
  1329.     StrLen = strlen(&Buf[0]);
  1330.     return(0);
  1331. }
  1332.  
  1333.  
  1334. PUBLIC void LYRefreshEdit ARGS1(
  1335.     EDREC *,    edit)
  1336. {
  1337.     int i;
  1338.     int length;
  1339.     int nrdisplayed;
  1340.     int padsize;
  1341.     char *str;
  1342.     char buffer[3];
  1343.  
  1344.     buffer[0] = buffer[1] = buffer[2] = '\0';
  1345.     if (!edit->dirty || (DspWdth == 0))
  1346.     return;
  1347.     edit->dirty = FALSE;
  1348.  
  1349.     length=strlen(&Buf[0]);
  1350.     edit->strlen = length;
  1351. /*
  1352.  *  Now we have:
  1353.  *          .--DspWdth---.
  1354.  *    +---------+=============+-----------+
  1355.  *    |      |M           M|        |    (M=margin)
  1356.  *    +---------+=============+-----------+
  1357.  *    0      DspStart             length
  1358.  *
  1359.  *  Insertion point can be anywhere between 0 and stringlength.
  1360.  *  Figure out new display starting point.
  1361.  *
  1362.  *   The first "if" below makes Lynx scroll several columns at a time when
  1363.  *   extending the string. Looks awful, but that way we can keep up with
  1364.  *   data entry at low baudrates.
  1365.  */
  1366.     if ((DspStart + DspWdth) <= length)
  1367.     if (Pos >= (DspStart + DspWdth) - Margin)
  1368.         DspStart=(Pos - DspWdth) + Margin;
  1369.  
  1370.     if (Pos < DspStart + Margin) {
  1371.     DspStart = Pos - Margin;
  1372.     if (DspStart < 0)
  1373.         DspStart = 0;
  1374.     }
  1375.  
  1376.     str = &Buf[DspStart];
  1377.  
  1378.     nrdisplayed = length-DspStart;
  1379.     if (nrdisplayed > DspWdth)
  1380.     nrdisplayed = DspWdth;
  1381.  
  1382.     move(edit->sy, edit->sx);
  1383.     if (edit->hidden) {
  1384.     for (i = 0; i < nrdisplayed; i++)
  1385.         addch('*');
  1386.     } else {
  1387.     for (i = 0; i < nrdisplayed; i++)
  1388.         if ((buffer[0] = str[i]) == 1 || buffer[0] == 2 ||
  1389.         ((unsigned char)buffer[0] == 160 &&
  1390.          !(HTPassHighCtrlRaw || HTCJK != NOCJK ||
  1391.            (LYCharSet_UC[current_char_set].enc != UCT_ENC_8859 &&
  1392.             !(LYCharSet_UC[current_char_set].like8859
  1393.               & UCT_R_8859SPECL))))) {
  1394.         addch(' ');
  1395.         } else {
  1396.         /* For CJK strings, by Masanobu Kimura */
  1397.         if (HTCJK != NOCJK && !isascii(buffer[0])) {
  1398.             if (i < (nrdisplayed - 1))
  1399.             buffer[1] = str[++i];
  1400.             addstr(buffer);
  1401.             buffer[1] = '\0';
  1402.         } else {
  1403.             addstr(buffer);
  1404.         }
  1405.         }
  1406.     }
  1407.  
  1408.     /*
  1409.      *    Erase rest of input area.
  1410.      */
  1411.     padsize = DspWdth-nrdisplayed;
  1412.     while (padsize--)
  1413.     addch((unsigned char)edit->pad);
  1414.  
  1415.     /*
  1416.      *    Scrolling indicators.
  1417.      */
  1418.     if (edit->panon) {
  1419.     if ((DspStart + nrdisplayed) < length) {
  1420.         move(edit->sy, edit->sx+nrdisplayed-1);
  1421.         addch('}');
  1422.     }
  1423.     if (DspStart) {
  1424.         move(edit->sy, edit->sx);
  1425.         addch('{');
  1426.     }
  1427.     }
  1428.  
  1429.     move(edit->sy, edit->sx + Pos - DspStart);
  1430.     refresh();
  1431. }
  1432.  
  1433.  
  1434. PUBLIC int LYgetstr ARGS4(
  1435.     char *,     inputline,
  1436.     int,        hidden,
  1437.     size_t,     bufsize,
  1438.     int,        recall)
  1439. {
  1440.     int x, y, MaxStringSize;
  1441.     int ch;
  1442.     EditFieldData MyEdit;
  1443.  
  1444.     LYGetYX(y, x);        /* Use screen from cursor position to eol */
  1445.     MaxStringSize = (bufsize < sizeof(MyEdit.buffer)) ?
  1446.             (bufsize - 1) : (sizeof(MyEdit.buffer) - 1);
  1447.     LYSetupEdit(&MyEdit, inputline, MaxStringSize, (LYcols-1)-x);
  1448.     MyEdit.hidden = hidden ;
  1449.  
  1450.     for (;;) {
  1451. again:
  1452.     LYRefreshEdit(&MyEdit);
  1453.     ch = LYgetch();
  1454. #ifdef VMS
  1455.     if (term_letter || term_options || term_message || HadVMSInterrupt) {
  1456.         HadVMSInterrupt = FALSE;
  1457.         ch = 7;
  1458.     }
  1459. #else
  1460.     if (term_letter || term_options || term_message)
  1461.         ch = 7;
  1462. #endif /* VMS */
  1463.     if (recall && (ch == UPARROW || ch == DNARROW)) {
  1464.         strcpy(inputline, MyEdit.buffer);
  1465.         return(ch);
  1466.     }
  1467.     if (keymap[ch + 1] == LYK_REFRESH)
  1468.         goto again;
  1469.     switch (EditBinding(ch)) {
  1470.     case LYE_TAB:
  1471.         ch = '\t';
  1472.         /* fall through */
  1473.     case LYE_AIX:
  1474.         /*
  1475.          *    Hex 97.
  1476.          *    Treat as a character for CJK, or if this is a valid
  1477.          *    character in the current display character set.
  1478.          *    Otherwise, we treat this as LYE_ENTER.
  1479.          */
  1480.         if (ch != '\t' &&
  1481.         (HTCJK != NOCJK ||
  1482.          LYlowest_eightbit[current_char_set] <= 0x97)) {
  1483.         LYLineEdit(&MyEdit,ch, FALSE);
  1484.         break;
  1485.         }
  1486.     case LYE_ENTER:
  1487.         /*
  1488.          *    Terminate the string and return.
  1489.          */
  1490.         strcpy(inputline, MyEdit.buffer);
  1491.         return(ch);
  1492.         break;
  1493.  
  1494.     case LYE_ABORT:
  1495.         /*
  1496.          *    Control-C or Control-G aborts.
  1497.          */
  1498.         inputline[0] = '\0';
  1499.         return(-1);
  1500.         break;
  1501.  
  1502.     case LYE_LKCMD:
  1503.         /*
  1504.          *    Used only in form_getstr() for invoking
  1505.          *    the LYK_F_LINK_NUM prompt when in form
  1506.          *    text fields. - FM
  1507.          */
  1508.         break;
  1509.  
  1510.     default:
  1511.         LYLineEdit(&MyEdit, ch, FALSE);
  1512.     }
  1513.     }
  1514. }
  1515.  
  1516. /*
  1517.  *  LYstrstr will find the first occurrence of the string
  1518.  *  pointed to by tarptr in the string pointed to by chptr.
  1519.  *  It returns NULL if string not found.
  1520.  *  It is a case insensitive search.
  1521.  */
  1522. PUBLIC char * LYstrstr ARGS2(
  1523.     char *,     chptr,
  1524.     char *,     tarptr)
  1525. {
  1526.     int len = strlen(tarptr);
  1527.  
  1528.     for(; *chptr != '\0'; chptr++) {
  1529.     if (0 == UPPER8(*chptr, *tarptr)) {
  1530.         if (0 == strncasecomp8(chptr+1, tarptr+1, len-1))
  1531.         return(chptr);
  1532.     }
  1533.     } /* end for */
  1534.  
  1535.     return(NULL); /* string not found or initial chptr was empty */
  1536. }
  1537.  
  1538. /*
  1539.  *  LYno_attr_char_case_strstr will find the first occurrence of the
  1540.  *  string pointed to by tarptr in the string pointed to by chptr.
  1541.  *  It ignores the characters: LY_UNDERLINE_START_CHAR and
  1542.  *                   LY_UNDERLINE_END_CHAR
  1543.  *                   LY_BOLD_START_CHAR
  1544.  *                   LY_BOLD_END_CHAR
  1545.  *                   LY_SOFT_HYPHEN
  1546.  *                   if present in chptr.
  1547.  *  It is a case insensitive search.
  1548.  */
  1549. PUBLIC char * LYno_attr_char_case_strstr ARGS2(
  1550.     char *,     chptr,
  1551.     char *,     tarptr)
  1552. {
  1553.     register char *tmpchptr, *tmptarptr;
  1554.  
  1555.     if (!chptr)
  1556.     return(NULL);
  1557.  
  1558.     while (IsSpecialAttrChar(*chptr) && *chptr != '\0')
  1559.     chptr++;
  1560.  
  1561.     for (; *chptr != '\0'; chptr++) {
  1562.      if (0 == UPPER8(*chptr, *tarptr)) {
  1563.         /*
  1564.          *    See if they line up.
  1565.          */
  1566.         tmpchptr = chptr+1;
  1567.         tmptarptr = tarptr+1;
  1568.  
  1569.         if (*tmptarptr == '\0')  /* one char target */
  1570.          return(chptr);
  1571.  
  1572.         while (1) {
  1573.         if (!IsSpecialAttrChar(*tmpchptr)) {
  1574.             if (0 != UPPER8(*tmpchptr, *tmptarptr))
  1575.             break;
  1576.             tmpchptr++;
  1577.             tmptarptr++;
  1578.         } else {
  1579.             tmpchptr++;
  1580.         }
  1581.         if (*tmptarptr == '\0')
  1582.             return(chptr);
  1583.         if (*tmpchptr == '\0')
  1584.             break;
  1585.         }
  1586.     }
  1587.     } /* end for */
  1588.  
  1589.     return(NULL);
  1590. }
  1591.  
  1592. /*
  1593.  *  LYno_attr_char_strstr will find the first occurrence of the
  1594.  *  string pointed to by tarptr in the string pointed to by chptr.
  1595.  *  It ignores the characters: LY_UNDERLINE_START_CHAR and
  1596.  *                   LY_UNDERLINE_END_CHAR
  1597.  *                   LY_BOLD_START_CHAR
  1598.  *                   LY_BOLD_END_CHAR
  1599.  *                LY_SOFT_HYPHEN
  1600.  *                   if present in chptr.
  1601.  *  It is a case sensitive search.
  1602.  */
  1603. PUBLIC char * LYno_attr_char_strstr ARGS2(
  1604.     char *,     chptr,
  1605.     char *,     tarptr)
  1606. {
  1607.     register char *tmpchptr, *tmptarptr;
  1608.  
  1609.     if (!chptr)
  1610.     return(NULL);
  1611.  
  1612.     while (IsSpecialAttrChar(*chptr) && *chptr != '\0')
  1613.     chptr++;
  1614.  
  1615.     for (; *chptr != '\0'; chptr++) {
  1616.     if ((*chptr) == (*tarptr)) {
  1617.         /*
  1618.          *    See if they line up.
  1619.          */
  1620.         tmpchptr = chptr + 1;
  1621.         tmptarptr = tarptr + 1;
  1622.  
  1623.         if (*tmptarptr == '\0')  /* one char target */
  1624.          return(chptr);
  1625.  
  1626.         while (1) {
  1627.          if (!IsSpecialAttrChar(*tmpchptr)) {
  1628.             if ((*tmpchptr) != (*tmptarptr))
  1629.             break;
  1630.             tmpchptr++;
  1631.             tmptarptr++;
  1632.          } else {
  1633.             tmpchptr++;
  1634.          }
  1635.          if (*tmptarptr == '\0')
  1636.              return(chptr);
  1637.          if (*tmpchptr == '\0')
  1638.              break;
  1639.         }
  1640.     }
  1641.     } /* end for */
  1642.  
  1643.     return(NULL);
  1644. }
  1645.  
  1646. /*
  1647.  * LYno_attr_mbcs_case_strstr will find the first occurrence of the string
  1648.  * pointed to by tarptr in the string pointed to by chptr.
  1649.  * It takes account of MultiByte Character Sequences (UTF8).
  1650.  * The physical length of the displayed string up to the end of the target
  1651.  * string is returned in *nendp if the search is successful.
  1652.  * It ignores the characters: LY_UNDERLINE_START_CHAR and
  1653.  *                  LY_UNDERLINE_END_CHAR
  1654.  *                  LY_BOLD_START_CHAR
  1655.  *                LY_BOLD_END_CHAR
  1656.  *                LY_SOFT_HYPHEN
  1657.  *                  if present in chptr.
  1658.  * It assumes UTF8 if utf_flag is set.
  1659.  *  It is a case insensitive search. - KW & FM
  1660.  */
  1661. PUBLIC char * LYno_attr_mbcs_case_strstr ARGS5(
  1662.     char *,     chptr,
  1663.     char *,     tarptr,
  1664.     BOOL,        utf_flag,
  1665.     int *,        nstartp,
  1666.     int *,        nendp)
  1667. {
  1668.     register char *tmpchptr, *tmptarptr;
  1669.     int len = 0;
  1670.     int offset;
  1671.  
  1672.     if (!(chptr && tarptr))
  1673.     return(NULL);
  1674.  
  1675.     /*
  1676.      *    Skip initial IsSpecial chars. - FM
  1677.      */
  1678.     while (IsSpecialAttrChar(*chptr) && *chptr != '\0')
  1679.     chptr++;
  1680.  
  1681.     /*
  1682.      *    Seek a first target match. - FM
  1683.      */
  1684.     for (; *chptr != '\0'; chptr++) {
  1685.     if ((!utf_flag && HTCJK != NOCJK && !isascii(*chptr) &&
  1686.          *chptr == *tarptr &&
  1687.          *(chptr + 1) != '\0' &&
  1688.          !IsSpecialAttrChar(*(chptr + 1))) ||
  1689.         (0 == UPPER8(*chptr, *tarptr))) {
  1690.         int tarlen = 0;
  1691.         offset = len;
  1692.         len++;
  1693.  
  1694.         /*
  1695.          *    See if they line up.
  1696.          */
  1697.         tmpchptr = (chptr + 1);
  1698.         tmptarptr = (tarptr + 1);
  1699.  
  1700.         if (*tmptarptr == '\0') {
  1701.         /*
  1702.          *  One char target.
  1703.          */
  1704.         *nstartp = offset;
  1705.         *nendp = len;
  1706.          return(chptr);
  1707.         }
  1708.         if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) &&
  1709.          *chptr == *tarptr &&
  1710.          *tmpchptr != '\0' &&
  1711.          !IsSpecialAttrChar(*tmpchptr)) {
  1712.         /*
  1713.          *  Check the CJK multibyte. - FM
  1714.          */
  1715.         if (*tmpchptr == *tmptarptr) {
  1716.             /*
  1717.              *    It's a match.  Advance to next char. - FM
  1718.              */
  1719.             tmpchptr++;
  1720.             tmptarptr++;
  1721.             if (*tmptarptr == '\0') {
  1722.             /*
  1723.              *  One character match. - FM
  1724.              */
  1725.             *nstartp = offset;
  1726.             *nendp = len + tarlen;
  1727.             return(chptr);
  1728.             }
  1729.             tarlen++;
  1730.         } else {
  1731.             /*
  1732.              *    It's not a match, so go back to
  1733.              *    seeking a first target match. - FM
  1734.              */
  1735.             chptr++;
  1736.             continue;
  1737.         }
  1738.         }
  1739.         /*
  1740.          *    See if the rest of the target matches. - FM
  1741.          */
  1742.         while (1) {
  1743.          if (!IsSpecialAttrChar(*tmpchptr)) {
  1744.             if (!utf_flag && HTCJK != NOCJK && !isascii(*tmpchptr)) {
  1745.             if (*tmpchptr == *tmptarptr &&
  1746.                 *(tmpchptr + 1) == *(tmptarptr + 1) &&
  1747.                 !IsSpecialAttrChar(*(tmpchptr + 1))) {
  1748.                 tmpchptr++;
  1749.                 tmptarptr++;
  1750.             } else {
  1751.             break;
  1752.             }
  1753.             } else if (0 != UPPER8(*tmpchptr, *tmptarptr)) {
  1754.             break;
  1755.             }
  1756.  
  1757.             if (!IS_UTF_EXTRA(*tmptarptr)) {
  1758.             tarlen++;
  1759.             }
  1760.             tmpchptr++;
  1761.             tmptarptr++;
  1762.  
  1763.          } else {
  1764.             tmpchptr++;
  1765.          }
  1766.  
  1767.          if (*tmptarptr == '\0') {
  1768.             *nstartp = offset;
  1769.              *nendp = len + tarlen;
  1770.              return(chptr);
  1771.          }
  1772.         if (*tmpchptr == '\0') {
  1773.              break;
  1774.         }
  1775.         }
  1776.     } else if (!(IS_UTF_EXTRA(*chptr) ||
  1777.               IsSpecialAttrChar(*chptr))) {
  1778.         if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) &&
  1779.         *(chptr + 1) != '\0' &&
  1780.         !IsSpecialAttrChar(*(chptr + 1))) {
  1781.         chptr++;
  1782.         }
  1783.         len++;
  1784.     }
  1785.     } /* end for */
  1786.  
  1787.     return(NULL);
  1788. }
  1789.  
  1790. /*
  1791.  * LYno_attr_mbcs_strstr will find the first occurrence of the string
  1792.  * pointed to by tarptr in the string pointed to by chptr.
  1793.  *  It takes account of CJK and MultiByte Character Sequences (UTF8).
  1794.  *  The physical lengths of the displayed string up to the start and
  1795.  *  end of the target string are returned in *nstartp and *nendp if
  1796.  *  the search is successful.
  1797.  * It ignores the characters: LY_UNDERLINE_START_CHAR and
  1798.  *                  LY_UNDERLINE_END_CHAR
  1799.  *                  LY_BOLD_START_CHAR
  1800.  *                  LY_BOLD_END_CHAR
  1801.  *                LY_SOFT_HYPHEN
  1802.  *                  if present in chptr.
  1803.  * It assumes UTF8 if utf_flag is set.
  1804.  *  It is a case sensitive search. - KW & FM
  1805.  */
  1806. PUBLIC char * LYno_attr_mbcs_strstr ARGS5(
  1807.     char *,     chptr,
  1808.     char *,     tarptr,
  1809.     BOOL,        utf_flag,
  1810.     int *,        nstartp,
  1811.     int *,        nendp)
  1812. {
  1813.     register char *tmpchptr, *tmptarptr;
  1814.     int len = 0;
  1815.     int offset;
  1816.  
  1817.     if (!(chptr && tarptr))
  1818.     return(NULL);
  1819.  
  1820.     /*
  1821.      *    Skip initial IsSpecial chars. - FM
  1822.      */
  1823.     while (IsSpecialAttrChar(*chptr) && *chptr != '\0')
  1824.     chptr++;
  1825.  
  1826.     /*
  1827.      *    Seek a first target match. - FM
  1828.      */
  1829.     for (; *chptr != '\0'; chptr++) {
  1830.     if ((*chptr) == (*tarptr)) {
  1831.         int tarlen = 0;
  1832.         offset = len;
  1833.         len++;
  1834.  
  1835.         /*
  1836.          *    See if they line up.
  1837.          */
  1838.         tmpchptr = (chptr + 1);
  1839.         tmptarptr = (tarptr + 1);
  1840.  
  1841.         if (*tmptarptr == '\0') {
  1842.         /*
  1843.          *  One char target.
  1844.          */
  1845.         *nstartp = offset;
  1846.         *nendp = len + 1;
  1847.          return(chptr);
  1848.         }
  1849.         if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) &&
  1850.          *tmpchptr != '\0' &&
  1851.          !IsSpecialAttrChar(*tmpchptr)) {
  1852.         /*
  1853.          *  Check the CJK multibyte. - FM
  1854.          */
  1855.         if (*tmpchptr == *tmptarptr) {
  1856.             /*
  1857.              *    It's a match.  Advance to next char. - FM
  1858.              */
  1859.             tmpchptr++;
  1860.             tmptarptr++;
  1861.             if (*tmptarptr == '\0') {
  1862.             /*
  1863.              *  One character match. - FM
  1864.              */
  1865.             *nstartp = offset;
  1866.             *nendp = len + tarlen;
  1867.             return(chptr);
  1868.             }
  1869.             tarlen++;
  1870.         } else {
  1871.             /*
  1872.              *    It's not a match, so go back to
  1873.              *    seeking a first target match. - FM
  1874.              */
  1875.             chptr++;
  1876.             continue;
  1877.         }
  1878.         }
  1879.         /*
  1880.          *    See if the rest of the target matches. - FM
  1881.          */
  1882.         while (1) {
  1883.          if (!IsSpecialAttrChar(*tmpchptr)) {
  1884.             if (!utf_flag && HTCJK != NOCJK && !isascii(*tmpchptr)) {
  1885.             if (*tmpchptr == *tmptarptr &&
  1886.                 *(tmpchptr + 1) == *(tmptarptr + 1) &&
  1887.                 !IsSpecialAttrChar(*(tmpchptr + 1))) {
  1888.                 tmpchptr++;
  1889.                 tmptarptr++;
  1890.             } else {
  1891.                 break;
  1892.             }
  1893.             } else if ((*tmpchptr) != (*tmptarptr)) {
  1894.             break;
  1895.             }
  1896.  
  1897.             if (!IS_UTF_EXTRA(*tmptarptr)) {
  1898.             tarlen++;
  1899.             }
  1900.             tmpchptr++;
  1901.             tmptarptr++;
  1902.          } else {
  1903.             tmpchptr++;
  1904.          }
  1905.  
  1906.          if (*tmptarptr == '\0') {
  1907.             *nstartp = offset;
  1908.              *nendp = len + tarlen;
  1909.              return(chptr);
  1910.          }
  1911.         if (*tmpchptr == '\0') {
  1912.              break;
  1913.         }
  1914.         }
  1915.     } else if (!(IS_UTF_EXTRA(*chptr) ||
  1916.               IsSpecialAttrChar(*chptr))) {
  1917.         if (!utf_flag && HTCJK != NOCJK && !isascii(*chptr) &&
  1918.         *(chptr + 1) != '\0' &&
  1919.         !IsSpecialAttrChar(*(chptr + 1))) {
  1920.         chptr++;
  1921.         }
  1922.         len++;
  1923.     }
  1924.     } /* end for */
  1925.  
  1926.     return(NULL);
  1927. }
  1928.  
  1929. /*
  1930.  *  Allocate a new copy of a string, and returns it.
  1931.  */
  1932. PUBLIC char * SNACopy ARGS3(
  1933.     char **,    dest,
  1934.     CONST char *,    src,
  1935.     int,        n)
  1936. {
  1937.     FREE(*dest);
  1938.     if (src) {
  1939.     *dest = (char *)calloc(1, n + 1);
  1940.     if (*dest == NULL) {
  1941.         CTRACE(tfp, "Tried to calloc %d bytes\n", n);
  1942.         outofmem(__FILE__, "SNACopy");
  1943.     }
  1944.     strncpy (*dest, src, n);
  1945.     *(*dest + n) = '\0'; /* terminate */
  1946.     }
  1947.     return *dest;
  1948. }
  1949.  
  1950. /*
  1951.  *  String Allocate and Concatenate.
  1952.  */
  1953. PUBLIC char * SNACat ARGS3(
  1954.     char **,    dest,
  1955.     CONST char *,    src,
  1956.     int,        n)
  1957. {
  1958.     if (src && *src) {
  1959.     if (*dest) {
  1960.         int length = strlen(*dest);
  1961.         *dest = (char *)realloc(*dest, length + n + 1);
  1962.         if (*dest == NULL)
  1963.         outofmem(__FILE__, "SNACat");
  1964.         strncpy(*dest + length, src, n);
  1965.         *(*dest + length + n) = '\0'; /* terminate */
  1966.     } else {
  1967.         *dest = (char *)calloc(1, strlen(src) + 1);
  1968.         if (*dest == NULL)
  1969.         outofmem(__FILE__, "SNACat");
  1970.         strncpy(*dest, src, n);
  1971.         *dest[n] = '\0'; /* terminate */
  1972.     }
  1973.     }
  1974.     return *dest;
  1975. }
  1976.  
  1977. /*
  1978. **   UPPER8 ?
  1979. **   it was "TOUPPER(a) - TOUPPER(b)" in its previous life...
  1980. **
  1981. **   It was realized that case-insensitive user search
  1982. **   got information about upper/lower mapping from TOUPPER
  1983. **   (precisely from "(TOUPPER(a) - TOUPPER(b))==0").
  1984. **   This function depends on locale in its 8bit mapping
  1985. **   and usually fails with DOS/WINDOWS display charsets
  1986. **   as well as on non-UNIX systems.
  1987. **
  1988. **   We extend this function for 8bit letters
  1989. **   using Lynx internal chartrans feature:
  1990. **   we assume that upper/lower case letters
  1991. **   have their "7bit approximation" images (in def7_uni.tbl)
  1992. **   matched case-insensitive (7bit).
  1993. **
  1994. **   By this technique we automatically cover *any* charset
  1995. **   known for Lynx chartrans and need no any extra information for it.
  1996. **
  1997. **   The cost of this assumption is that several differently accented letters
  1998. **   may be interpreted as equal, but this side effect is negligible
  1999. **   if the user search string is more than one character long.  - LP
  2000. **
  2001. **   We enable new technique only if  DisplayCharsetMatchLocale = FALSE
  2002. **   (see description in LYCharSets.c)
  2003. */
  2004. PUBLIC int UPPER8 ARGS2(int,ch1, int,ch2)
  2005. {
  2006.  
  2007.     /* case-insensitive match for us-ascii */
  2008.     if ((unsigned char)ch1 < 128 && (unsigned char)ch2 < 128)
  2009.     return(TOUPPER(ch1) - TOUPPER(ch2));
  2010.  
  2011.     /* case-insensitive match for upper half */
  2012.     if ((unsigned char)ch1 > 127 && (unsigned char)ch2 >127)
  2013.     {
  2014.     if (DisplayCharsetMatchLocale)
  2015.        return(TOUPPER(ch1) - TOUPPER(ch2)); /* old-style */
  2016.     else
  2017.     {
  2018.     /* compare "7bit approximation" for letters >127   */
  2019.     /* BTW, if we remove the check for >127 above       */
  2020.     /* we get even more "relaxed" insensitive match... */
  2021.  
  2022.     CONST char *disp_charset = LYCharSet_UC[current_char_set].MIMEname;
  2023.     int charset_in, charset_out, uck1, uck2;
  2024.     char replace_buf1 [10], replace_buf2 [10];
  2025.  
  2026.     charset_in  = UCGetLYhndl_byMIME(disp_charset);
  2027.     charset_out = UCGetLYhndl_byMIME("us-ascii");
  2028.  
  2029.     uck1 = UCTransCharStr(replace_buf1, sizeof(replace_buf1), ch1,
  2030.                   charset_in, charset_out, YES);
  2031.     uck2 = UCTransCharStr(replace_buf2, sizeof(replace_buf2), ch2,
  2032.                   charset_in, charset_out, YES);
  2033.  
  2034.     if ((uck1 > 0) && (uck2 > 0))  /* both replacement strings found */
  2035.         return (strcasecomp(replace_buf1, replace_buf2));
  2036.  
  2037.     /* check to be sure we have not lost any strange characters */
  2038.     /* which are not found in def7_uni.tbl but _equal_ in fact. */
  2039.     /* this also applied for "x-transparent" display mode.        */
  2040.     if ((unsigned char)ch1==(unsigned char)ch2)
  2041.         return(0);     /* match */
  2042.     }
  2043.     }
  2044.  
  2045.     return(-10);  /* mismatch, if we come to here */
  2046. }
  2047.