home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume30 / tin / part10 / misc.c < prev    next >
C/C++ Source or Header  |  1992-05-20  |  15KB  |  864 lines

  1. /*
  2.  *  Project   : tin - a threaded Netnews reader
  3.  *  Module    : misc.c
  4.  *  Author    : I.Lea & R.Skrenta
  5.  *  Created   : 01-04-91
  6.  *  Updated   : 10-05-92
  7.  *  Notes     :
  8.  *  Copyright : (c) Copyright 1991-92 by Iain Lea & Rich Skrenta
  9.  *              You may  freely  copy or  redistribute  this software,
  10.  *              so  long as there is no profit made from its use, sale
  11.  *              trade or  reproduction.  You may not change this copy-
  12.  *              right notice, and it must be included in any copy made
  13.  */
  14.  
  15. #include    "tin.h"
  16.  
  17. static char *mailbox_name = (char *) 0;
  18. static int  mailbox_size;
  19.  
  20.  
  21. void asfail (file, line, cond)
  22.     char    *file;
  23.     int    line;
  24.     char    *cond;
  25. {
  26.       fprintf (stderr, "%s: assertion failure: %s (%d): %s\n",
  27.           progname, file, line, cond);
  28.       fflush (stderr);
  29.       
  30.      /*
  31.       * create a core dump
  32.       */
  33. #ifdef SIGABRT    
  34.     sigdisp(SIGABRT, SIG_DFL);
  35.      kill (process_id, SIGABRT);
  36. #else
  37. #    ifdef SIGILL
  38.         sigdisp(SIGILL, SIG_DFL);
  39.          kill (process_id, SIGILL);
  40. #    else
  41. #        ifdef SIGIOT
  42.             sigdisp(SIGIOT, SIG_DFL);
  43.              kill (process_id, SIGIOT);
  44. #        endif
  45. #    endif
  46. #endif
  47.  
  48.     exit(1);
  49. }
  50.  
  51.  
  52. void copy_fp (fp_ip, fp_op, prefix)
  53.     FILE *fp_ip;
  54.     FILE *fp_op;
  55.     char *prefix;
  56. {
  57.     extern int errno;
  58.     char buf[8192];
  59.  
  60.     while (fgets (buf, sizeof (buf), fp_ip) != NULL) {
  61.         if (fprintf (fp_op, "%s%s", prefix, buf) == EOF) {
  62.             if (errno == EPIPE) {
  63.                 return;
  64.             }
  65.             sprintf (msg, "Error: fprintf() failed in copy_fp(). errno=%d", errno);
  66.             perror_message (msg, "");
  67.         }
  68.     }
  69. }
  70.  
  71.  
  72. char *get_val (env, def)
  73.     char *env;        /* Environment variable we're looking for    */
  74.     char *def;        /* Default value if no environ value found    */
  75. {
  76.     char *ptr;
  77.  
  78.     if ((ptr = (char *) getenv(env)) != NULL)
  79.         return (ptr);
  80.     else
  81.         return (def);
  82. }
  83.  
  84.  
  85. int invoke_editor (nam)
  86.     char *nam;
  87. {
  88.     char buf[LEN];
  89.     char *my_editor;
  90.     static char editor[LEN];
  91.     static int first = TRUE;
  92.  
  93.     if (first) {
  94.         my_editor = (char *) getenv ("VISUAL");
  95.  
  96.         strcpy (editor, my_editor != NULL ? my_editor : get_val ("EDITOR", DEFAULT_EDITOR));
  97.         first = FALSE;
  98.     }
  99.  
  100.     if (start_editor_offset) {
  101.         sprintf (buf, "%s +%d %s", editor, start_line_offset, nam);
  102.     } else {
  103.         sprintf (buf, "%s %s", editor, nam);
  104.     }
  105.  
  106.     wait_message (buf);
  107.  
  108.     return invoke_cmd (buf);
  109. }
  110.  
  111.  
  112. void shell_escape ()
  113. {
  114.     char shell[LEN];
  115.     char *p;
  116.  
  117. #ifdef SIGTSTP
  118.     sigtype_t (*susp)() = (sigtype_t *) 0;
  119. #endif
  120.  
  121.     sprintf (msg, txt_shell_escape, default_shell_command);
  122.     
  123.     if (! prompt_string (msg, shell))
  124.         my_strncpy (shell, get_val ("SHELL", DEFAULT_SHELL), sizeof (shell));
  125.  
  126.     for (p = shell; *p && (*p == ' ' || *p == '\t'); p++)
  127.         continue;
  128.  
  129.     if (*p) {
  130.         my_strncpy (default_shell_command, p, sizeof (default_shell_command));
  131.     } else {
  132.         if (default_shell_command[0]) {
  133.             my_strncpy (shell, default_shell_command, sizeof (shell));
  134.         } else {
  135.             my_strncpy (shell, get_val ("SHELL", DEFAULT_SHELL), sizeof (shell));
  136.         }
  137.         p = shell;
  138.     }
  139.  
  140.     ClearScreen ();
  141.     sprintf (msg, "Shell Command (%s)", p);
  142.     center_line (0, TRUE, msg);
  143.     MoveCursor (INDEX_TOP, 0);
  144.     
  145.     EndWin ();
  146.     Raw (FALSE);
  147.  
  148. #ifdef SIGTSTP
  149.     if (do_sigtstp)
  150.         susp = signal (SIGTSTP, SIG_DFL);
  151. #endif
  152.  
  153.     system (p);
  154.  
  155. #ifdef SIGTSTP
  156.     if (do_sigtstp)
  157.         signal (SIGTSTP, susp);
  158. #endif
  159.  
  160.     Raw (TRUE);
  161.     InitWin ();
  162.  
  163.     mail_setup ();
  164.  
  165.     continue_prompt ();
  166.  
  167.     if (draw_arrow_mark) {
  168.         ClearScreen ();
  169.     }
  170. }
  171.  
  172.  
  173. void tin_done (ret)
  174.     int ret;
  175. {
  176.     extern char index_file[PATH_LEN];
  177.     char group_path[PATH_LEN], *p;
  178.     int ask = TRUE;
  179.     register int i, j;
  180.     
  181.     /*
  182.      * check if any groups were read & ask if they should marked read
  183.      */
  184.     if (catchup_read_groups) {
  185.         for (i = 0 ; i < group_top ; i++) {
  186.             if (active[my_group[i]].attribute.read) {
  187.                 if (ask) {
  188.                     if (prompt_yn (LINES, "Catchup all groups entered during this session? (y/n): ", 'n')) {
  189.                         ask = FALSE;
  190.                         thread_arts = FALSE;    /* speeds up index loading */
  191.                     } else {
  192.                         break;
  193.                     }
  194.                 }
  195.                 sprintf (msg, "Catchup %s...", active[my_group[i]].name);
  196.                 wait_message (msg);
  197.                 my_strncpy (group_path, active[my_group[i]].name, sizeof (group_path));
  198.                 for (p = group_path ; *p ; p++) {
  199.                     if (*p == '.') {
  200.                         *p = '/';
  201.                     }
  202.                 }
  203.                 index_group (active[my_group[i]].name, group_path);
  204.                 for (j = 0; j < top; j++) {
  205.                     arts[j].unread = ART_READ;
  206.                 }
  207.                 update_newsrc (active[my_group[i]].name, my_group[i], FALSE);
  208.             }
  209.         }
  210.     }
  211.     nntp_close ();            /* disconnect from NNTP server */
  212.     free_all_arrays ();        /* deallocate all arrays */
  213.     ClearScreen ();
  214.     EndWin ();
  215.     Raw (FALSE);
  216.  
  217.     if (read_news_via_nntp && xindex_supported) {
  218.         unlink (index_file);
  219.     }
  220.  
  221.     exit (ret);
  222. }
  223.  
  224. #ifdef USE_MKDIR
  225. mkdir (path, mode)
  226.     char *path;
  227.     int mode;
  228. {
  229.     char buf[LEN];
  230.     struct stat sb;
  231.  
  232.     sprintf(buf, "mkdir %s", path);
  233.     if (stat (path, &sb) == -1) {
  234.         system (buf);
  235.         chmod (path, mode);
  236.     }
  237. }
  238. #endif
  239.  
  240. /*
  241.  * hash group name for fast lookup later 
  242.  */
  243.  
  244. long hash_groupname (group)
  245.     char *group;
  246. {
  247.     unsigned long hash_value;
  248.     unsigned char *ptr = (unsigned char *) group;
  249.  
  250.     hash_value = *ptr++;
  251.  
  252.     while (*ptr)
  253.         hash_value = ((hash_value << 1) ^ *ptr++) % TABLE_SIZE;
  254.  
  255.     return (hash_value);
  256. }
  257.  
  258.  
  259. void rename_file (old_filename, new_filename)
  260.     char *old_filename;
  261.     char *new_filename;
  262. {    
  263.     char buf[LEN];
  264.     
  265.     unlink (new_filename);
  266.     
  267.     if (link (old_filename, new_filename) == -1) {
  268.         sprintf (buf, txt_rename_error, old_filename, new_filename);
  269.         perror_message (buf, "ONE");
  270.         return;
  271.     }
  272.     if (unlink (old_filename) == -1) {
  273.         sprintf (buf, txt_rename_error, old_filename, new_filename);
  274.         perror_message (buf, "TWO");
  275.         return;
  276.     }
  277. }
  278.  
  279.  
  280. char *str_dup (str)
  281.     char *str;
  282. {
  283.     char *dup = (char *) 0;
  284.  
  285.     if (str) {
  286.         dup = my_malloc (strlen (str)+1);
  287.         strcpy (dup, str);
  288.     }
  289.     return dup;
  290. }
  291.  
  292.  
  293. int invoke_cmd (nam)
  294.     char *nam;
  295. {
  296.     int ret;
  297.     int time_remaining;
  298.     
  299. #ifdef SIGTSTP
  300.     sigtype_t (*susp)() = (sigtype_t *) 0;
  301. #endif
  302. #ifndef NO_RESYNC_ACTIVE_FILE
  303.     time_remaining = alarm (0);    /* save time remaining on alarm clock */
  304. #endif
  305.  
  306.     EndWin ();
  307.     Raw (FALSE);
  308.  
  309. #ifdef SIGTSTP
  310.     if (do_sigtstp)
  311.         susp = signal(SIGTSTP, SIG_DFL);
  312. #endif
  313.  
  314.     ret = system (nam);
  315.  
  316. #ifdef SIGTSTP
  317.     if (do_sigtstp)
  318.         signal (SIGTSTP, susp);
  319. #endif
  320.  
  321.     Raw (TRUE);
  322.     InitWin ();
  323.  
  324. #ifndef NO_RESYNC_ACTIVE_FILE
  325.     alarm (time_remaining);    /* restart resync alarm clock */
  326. #endif
  327.     
  328.     return ret == 0;
  329. }
  330.  
  331.  
  332. void draw_percent_mark (cur_num, max_num)
  333.     int cur_num;
  334.     int max_num;
  335. {
  336.     char buf[32];
  337.     int percent = 0;
  338.  
  339.     if (NOTESLINES <= 0) {
  340.         return;
  341.     }
  342.  
  343.     if (cur_num <= 0 && max_num <= 0) {
  344.         return;
  345.     }
  346.         
  347.     percent = cur_num * 100 / max_num;
  348.     sprintf (buf, "%s(%d%%) [%d/%d]", txt_more, percent, cur_num, max_num);
  349.     MoveCursor (LINES, (COLS - (int) strlen (buf))-(1+BLANK_PAGE_COLS));
  350.     StartInverse ();    
  351.     fputs (buf, stdout);
  352.     fflush (stdout);
  353.     EndInverse ();
  354. }
  355.  
  356. void set_real_uid_gid ()
  357. {
  358.     if (local_index)
  359.         return;
  360.  
  361.     umask (real_umask);
  362.     
  363. #if defined(BSD) && ! defined(sinix)
  364. #ifdef sun
  365.     if (seteuid (real_uid) == -1) {
  366.         perror_message ("Error setreuid(real) failed", "");
  367.     }
  368.     if (setegid (real_gid) == -1) {
  369.         perror_message ("Error setregid(real) failed", "");
  370.     }
  371. #else
  372.     if (setreuid (tin_uid, real_uid) == -1) {
  373.         perror_message ("Error setreuid(real) failed", "");
  374.     }
  375.     if (setregid (tin_gid, real_gid) == -1) {
  376.         perror_message ("Error setregid(real) failed", "");
  377.     }
  378. #endif    /* sun */    
  379. #else
  380.     if (setuid (real_uid) == -1) {
  381.         perror_message ("Error setuid(real) failed", "");
  382.     }
  383.     if (setgid (real_gid) == -1) {
  384.         perror_message ("Error setgid(real) failed", "");
  385.     }
  386. #endif
  387. }
  388.  
  389.  
  390. void set_tin_uid_gid ()
  391. {
  392.     if (local_index)
  393.         return;
  394.  
  395.     umask (real_umask);
  396.     
  397. #if defined(BSD) && ! defined(sinix)
  398. #ifdef sun
  399.     if (seteuid (tin_uid) == -1) {
  400.         perror_message ("Error setreuid(real) failed", "");
  401.     }
  402.     if (setegid (tin_gid) == -1) {
  403.         perror_message ("Error setregid(real) failed", "");
  404.     }
  405. #else
  406.     if (setreuid (real_uid, tin_uid) == -1) {
  407.         perror_message ("Error setreuid(tin) failed", "");
  408.     }
  409.     if (setregid (real_gid, tin_gid) == -1) {
  410.         perror_message ("Error setregid(tin) failed", "");
  411.     }
  412. #endif    /* sun */    
  413. #else
  414.     if (setuid (tin_uid) == -1) {
  415.         perror_message ("Error setuid(tin) failed", "");
  416.     }
  417.     if (setgid (tin_gid) == -1) {
  418.         perror_message ("Error setgid(tin) failed", "");
  419.     }
  420. #endif
  421. }
  422.  
  423.  
  424. void basename (dirname, program)
  425.     char *dirname;        /* argv[0] */
  426.     char *program;        /* progname is returned */
  427. {
  428.     int i;
  429.     
  430.     strcpy (program, dirname);
  431.     
  432.     for (i=(int) strlen (dirname)-1 ; i ; i--) {
  433.         if (dirname[i] == '/') {
  434.             strcpy (program, dirname+(i+1));
  435.             break;
  436.         }
  437.     }
  438. }
  439.  
  440.  
  441. /*
  442.  *  Record size of mailbox so we can detect if new mail has arrived
  443.  */
  444.  
  445. void mail_setup ()
  446. {
  447.     struct stat buf;
  448.  
  449.     mailbox_name = get_val ("MAIL", mailbox);
  450.  
  451.     if (stat (mailbox_name, &buf) >= 0) {
  452.         mailbox_size = buf.st_size;
  453.     } else {
  454.         mailbox_size = 0;
  455.     }
  456. }
  457.  
  458. /*
  459.  *  Return TRUE if new mail has arrived
  460.  */
  461.  
  462. int mail_check ()
  463. {
  464.     struct stat buf;
  465.  
  466.     if (mailbox_name != (char *) 0 &&
  467.         stat(mailbox_name, &buf) >= 0 &&
  468.         mailbox_size < buf.st_size) {
  469.         return TRUE;
  470.     }
  471.  
  472.     return FALSE;
  473. }
  474.  
  475. /*
  476.  *  Parse various From: lines into the component mail addresses and
  477.  *  real names
  478.  */
  479.  
  480. void parse_from (str, addr, name)
  481.     char *str;
  482.     char *addr;
  483.     char *name;
  484. {
  485.     register int c;
  486.     register char *cp, *ncp;
  487.     int gotlt, lastsp, level;
  488.  
  489.     gotlt = 0;
  490.     lastsp = 0;
  491.     cp = addr;
  492.     ncp = name;
  493.     while (*str == ' ')
  494.         ++str;
  495.     while (c = *str++)
  496.         switch (c) {
  497.         case '(':
  498.             ncp = name;
  499.             level = 1;
  500.             while (*str != '\0' && level) {
  501.                 switch (c = *str++) {
  502.                     case '(':
  503.                         *ncp++ = c;
  504.                         level++;
  505.                         break;
  506.                     case ')':
  507.                         level--;
  508.                         if (level > 0)
  509.                             *ncp++ = c;
  510.                         break;
  511.                     default:
  512.                         if (c != '"') {    /* IL */
  513.                             *ncp++ = c;
  514.                         }    
  515.                         break;
  516.                 }
  517.             }
  518.             if (*str)
  519.                 str++;
  520.             lastsp = 0;
  521.             break;
  522.         case ' ':
  523.             if (str[0] == 'a' && str[1] == 't' && str[2] == ' ')
  524.                 str += 3, *cp++ = '@';
  525.             else if (str[0] == '@' && str[1] == ' ')
  526.                 str += 2, *cp++ = '@';
  527.             else
  528.                 lastsp = 1;
  529.             if (ncp > name)
  530.                 *ncp++ = ' ';
  531.             break;
  532.         case '<':
  533.             cp = addr;
  534.             gotlt++;
  535.             lastsp = 0;
  536.             break;
  537.         case '>':
  538.             if (gotlt)
  539.                 goto done;
  540.             /* FALL THROUGH CASE */
  541.         default:
  542.             if (lastsp) {
  543.                 lastsp = 0;
  544.                 *cp++ = ' ';
  545.             }
  546.             *cp++ = c;
  547.             if (! gotlt)
  548.                 *ncp++ = c;
  549.             break;
  550.         }
  551. done:
  552.     *cp = 0;
  553.     while (ncp>name && ncp[-1]==' ')
  554.         --ncp;
  555.     *ncp = 0;
  556.     if (*addr == '@') {
  557.         char buf [512];
  558.  
  559.         strcpy (buf, addr);
  560.         strcpy (addr, "root");
  561.         strcat (addr, buf);
  562.     }
  563. }
  564.  
  565. /*
  566.  *  Convert a string to a long, only look at first n characters
  567.  */
  568.  
  569. long my_atol (s, n)
  570.     char *s;
  571.     int n;
  572. {
  573.     long ret = 0;
  574.  
  575.     while (*s && n--) {
  576.         if (*s >= '0' && *s <= '9')
  577.             ret = ret * 10 + (*s - '0');
  578.         else
  579.             return -1;
  580.         s++;
  581.     }
  582.  
  583.     return ret;
  584. }
  585.  
  586. /*
  587.  *  strcmp that ignores case
  588.  */
  589.  
  590. #define FOLD_TO_UPPER(a)    (islower ((int) (a)) ? toupper ((int) (a)) : (a))
  591.  
  592. int my_stricmp (p, q)
  593.     char *p;
  594.     char *q;
  595. {
  596.     for (; FOLD_TO_UPPER (*p) == FOLD_TO_UPPER (*q); ++p, ++q) {
  597.         if (*p == '\0') {
  598.             return (0);
  599.         }
  600.     }        
  601.  
  602.     return (FOLD_TO_UPPER (*p) - FOLD_TO_UPPER (*q));
  603. }
  604.  
  605. /*
  606.  *  Return a pointer into s eliminating any leading Re:'s.  Example:
  607.  *
  608.  *      Re: Reorganization of misc.jobs
  609.  *      ^   ^
  610.  */
  611.  
  612. char *eat_re (s)
  613.     char *s;
  614. {
  615.  
  616.     while (*s == 'r' || *s == 'R') {
  617.         if ((*(s+1) == 'e' || *(s+1) == 'E')) {
  618.             if (*(s+2) == ':')
  619.                 s += 3;
  620.             else if (*(s+2) == '^' && isdigit(*(s+3)) && *(s+4) == ':')
  621.                 s += 5;            /* hurray nn */
  622.             else
  623.                 break;
  624.         } else
  625.             break;
  626.         while (*s == ' ')
  627.             s++;
  628.     }
  629.  
  630.     return s;
  631. }
  632.  
  633. /*
  634.  *  Hash the subjects (after eating the Re's off) for a quicker
  635.  *  thread search later.  We store the hashes for subjects in the
  636.  *  index file for speed.
  637.  */
  638.  
  639. long hash_s (s)
  640.     char *s;
  641. {
  642.     long h = 0;
  643.     unsigned char *t = (unsigned char *) s;
  644.  
  645.     while (*t)
  646.         h = h * 64 + *t++;
  647.  
  648.     return h;
  649. }
  650.  
  651. /*
  652.  *  strncpy that stops at a newline and null terminates
  653.  */
  654.  
  655. void my_strncpy (p, q, n)
  656.     char *p;
  657.     char *q;
  658.     int n;
  659. {
  660.     while (n--) {
  661.         if (! *q || *q == '\n')
  662.             break;
  663.         *p++ = *q++;
  664.     }
  665.     *p = '\0';
  666. }
  667.  
  668.  
  669. int untag_all_articles ()
  670. {
  671.     int untagged = FALSE;
  672.     register int i;
  673.  
  674.     for (i=0 ; i < top ; i++) {
  675.         if (arts[i].tagged) {
  676.             arts[i].tagged = FALSE;
  677.             untagged = TRUE;
  678.         }
  679.     }
  680.     num_of_tagged_arts = 0;
  681.  
  682.     return (untagged);
  683. }
  684.  
  685.  
  686. /*
  687.  * ANSI C strstr () - Uses Boyer-Moore algorithm.
  688.  */
  689.  
  690. char *str_str (text, pattern, patlen)
  691.     char *text;
  692.     char *pattern;
  693.     int patlen;
  694. {
  695.     register unsigned char *p, *t;
  696.     register int i, p1, j, *delta;
  697.     int deltaspace[256];
  698.     int textlen;
  699.  
  700.     textlen = strlen (text);
  701.  
  702.     /* algorithm fails if pattern is empty */
  703.     if ((p1 = patlen) == 0)
  704.         return (text);
  705.  
  706.     /* code below fails (whenever i is unsigned) if pattern too long */
  707.     if (p1 > textlen)
  708.         return (NULL);
  709.  
  710.     /* set up deltas */
  711.     delta = deltaspace;
  712.     for (i = 0; i <= 255; i++)
  713.         delta[i] = p1;
  714.     for (p = (unsigned char *) pattern, i = p1; --i > 0;)
  715.         delta[*p++] = i;
  716.  
  717.     /*
  718.      * From now on, we want patlen - 1.
  719.      * In the loop below, p points to the end of the pattern,
  720.      * t points to the end of the text to be tested against the
  721.      * pattern, and i counts the amount of text remaining, not
  722.      * including the part to be tested.
  723.      */
  724.     p1--;
  725.     p = (unsigned char *) pattern + p1;
  726.     t = (unsigned char *) text + p1;
  727.     i = textlen - patlen;
  728.     for (;;) {
  729.         if (*p == *t && memcmp ((p - p1), (t - p1), p1) == 0)
  730.             return ((char *)t - p1);
  731.         j = delta[*t];
  732.         if (i < j)
  733.             break;
  734.         i -= j;
  735.         t += j;
  736.     }
  737.     return (NULL);
  738. }
  739.  
  740.  
  741.  
  742. void get_author (thread, respnum, str)
  743.     int thread;
  744.     int respnum;
  745.     char *str;
  746. {    
  747.     extern int threaded_on_subject;
  748.     int author;
  749. /*
  750.     int len_from = max_from;
  751.  
  752.     if (thread) {
  753.         if (threaded_on_subject) {
  754.             len_from = max_subj+max_from;
  755.         } else {
  756.             len_from = max_from;
  757.         }
  758.         author = SHOW_FROM_BOTH;
  759.     } else {
  760.         author = show_author;
  761.     } 
  762. */
  763.     if (thread) {
  764.         if (threaded_on_subject) {
  765.             author = SHOW_FROM_BOTH;
  766.         } else {
  767.             author = show_author;
  768.         }
  769.     } else {
  770.         author = show_author;
  771.     } 
  772.     
  773.     switch (author) { 
  774.         case SHOW_FROM_NONE:
  775.             str[0] = '\0';
  776.             break;
  777.         case SHOW_FROM_ADDR:
  778.             strcpy (str, arts[respnum].from);
  779.             break;
  780.         case SHOW_FROM_NAME:
  781.             strcpy (str, arts[respnum].name);
  782.             break;
  783.         case SHOW_FROM_BOTH:
  784.             if (arts[respnum].name != arts[respnum].from) { 
  785.                 sprintf (str, "%s (%s)", arts[respnum].name, arts[respnum].from);
  786.             } else { 
  787.                 strcpy (str, arts[respnum].from);
  788.             }
  789.             break;
  790.     }
  791. }
  792.  
  793.  
  794. void toggle_inverse_video ()
  795. {
  796.     inverse_okay = !inverse_okay;
  797.     if (inverse_okay) {
  798. #ifndef USE_INVERSE_HACK    
  799.         draw_arrow_mark = FALSE;
  800. #endif        
  801.         info_message (txt_inverse_on);
  802.     } else {
  803.         draw_arrow_mark = TRUE;
  804.         info_message (txt_inverse_off);
  805.     }
  806. }
  807.  
  808.  
  809. int get_arrow_key ()
  810. {
  811.     int ch;
  812.     
  813.     ch = ReadCh ();
  814.     if (ch == '[' || ch == 'O')
  815.         ch = ReadCh();
  816.     switch (ch) {
  817.         case 'A':
  818.         case 'D':
  819.         case 'i':
  820.             return KEYMAP_UP;
  821.  
  822.         case 'B':
  823.         case 'C':
  824.             return KEYMAP_DOWN;
  825.  
  826.         case 'I':        /* ansi  PgUp */
  827.         case 'V':        /* at386 PgUp */
  828.         case 'S':        /* 97801 PgUp */
  829.         case 'v':        /* emacs style */
  830.             return KEYMAP_PAGE_UP;
  831.  
  832.         case 'G':        /* ansi  PgDn */
  833.         case 'U':        /* at386 PgDn */
  834.         case 'T':        /* 97801 PgDn */
  835.             return KEYMAP_PAGE_DOWN;
  836.  
  837.         case 'H':        /* at386  Home */
  838.             return KEYMAP_HOME;
  839.                     
  840.         case 'F':        /* ansi   End */
  841.         case 'Y':        /* at386  End */
  842.             return KEYMAP_END;
  843.  
  844.         case '5':        /* vt200 PgUp */
  845.             ch = ReadCh ();    /* eat the ~  */
  846.             return KEYMAP_PAGE_UP;
  847.  
  848.         case '6':        /* vt200 PgUp */
  849.             ch = ReadCh ();    /* eat the ~  */
  850.             return KEYMAP_PAGE_DOWN;
  851.  
  852.         case '1':        /* vt200 PgUp */
  853.             ch = ReadCh ();    /* eat the ~  */
  854.             return KEYMAP_HOME;
  855.                     
  856.         case '4':        /* vt200 PgUp */
  857.             ch = ReadCh ();    /* eat the ~  */
  858.             return KEYMAP_END;
  859.  
  860.         default:
  861.             return KEYMAP_UNKNOWN;
  862.     }
  863. }
  864.