home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume15 / kbmap / part01 / kbmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-10-14  |  18.3 KB  |  633 lines

  1. /* ta=4     tabs set at 4*/
  2. /*
  3.         kbmap.c
  4.         
  5.     Kbmap reads a text file containg keyboard mapping information and
  6.     set the keyboard to the selected mapping.  It can also create
  7.     a map file with the -g option.
  8.  
  9.     Only root may use this programme from the console.
  10.     It cannot be run from an rc2.d/xxx file or cron.
  11.  
  12.     Then true-meta keys cannot be used with X11R2 - which uses its own map.
  13.     VTLMGR tends to modify a couple of keys.  The -q option (query_map())
  14.     tries to detect a vtlmgr modification.
  15.  
  16.     This works for AT&T Unix 3.2.2 - other systems not tested.
  17.  
  18. AUTHOR:    Tony Field    (tony%ajfcal@cpsc.ucalgary.ca)
  19.  
  20. NOTES:
  21.  
  22.   Structure of keyboard translation table (from /usr/include/sys/kd.h)
  23.  
  24.     #define NUM_KEYS    256                    Maximum number of keys
  25.     #define NUM_STATES    8                    Number of key states
  26.     #pragma pack(2)
  27.     typedef struct {
  28.         short  n_keys ;                        Number of entries in table
  29.         struct key_t {
  30.             unsigned char map[NUM_STATES];    Key code for each state
  31.             unsigned char spcl;                Bits marking states as special
  32.             unsigned char flgs;                Flags
  33.         } key[NUM_KEYS+1];                    One entry for each key
  34.     } keymap_t;
  35.  
  36.     (note: NUM_KEYS is specified as 256, however n_keys only
  37.            describes 128 keys...  kbmap only updates the first
  38.            128 keys.  The remainder are unmodified.)
  39.  
  40.     Each key has 8 (NUM_STATES) possible scan states honoured if
  41.     set in the "spcl" field:
  42.  
  43.         spcl    map[i]
  44.         bit 7     i=0        = normal
  45.             6       1        = shifted
  46.             5       2        = control
  47.             4      3        = shift-control
  48.             3       4        = alt
  49.             2       5        = alt-shift
  50.             1       6        = alt-control
  51.             0       7        = alt-shift-control
  52.     
  53.     If the corresponding bit is set, then the feature is enabled. For
  54.     example, if bit 3 is set, then the keyboard driver will translate
  55.     the scan code into the "<esc>Nx" escape sequence. If the 3ed bit is
  56.     NOT set, then the driver will use the character as specified in
  57.     map[4] as the returned value.
  58.  
  59.     The "flgs" field needs no modification: it allows the "numlok",
  60.     "caploc" and "control" keys to be used with specific keys:
  61.     
  62.             0x8000        allow numlock
  63.             0x4000        allow caps lock
  64.             0x2000        allow control
  65.             0x1000        locking is off
  66.     
  67.     At leaset that is what <sys/kd.h> indicates.  But that is not
  68.     what is indicated in the actual dump of the tables...  Alphabetic
  69.     characters contain 0x01, the numeric keypad contains 0x02, and
  70.     verything else contains 0x00.  Oh well...  A more reasonable
  71.     interpretation is that these meanings are assigned to the
  72.     high order 4 bits of "spcl", but that is only a guess.
  73.  
  74.     In addition, the default value for the map[4] entry for most codes
  75.     that can be translated into the <esc>Nx sequence is 0x7d.
  76.     The 7x numbers are used for function key translation.  They mean
  77.     (of course i am guessing):
  78.     
  79.             7d    = use <esc>Nx        where 'x' is the un-alted value
  80.             7e    = use <esc>Ox        of the scan code (funny that 7e
  81.             7f    = use <esc>Lx        and 7f do not appear in the table
  82.                                     nor are visible in keyboard(7))
  83.     
  84.     Conversion of the table to emacs "meta" bits is done as follows:
  85.  
  86.         1.    read the entire keyboard mapping structure with ioctl().    
  87.         2.    if the base key (map[0]) is between ' ' & 0x7f and not uppercase
  88.                 then remove bit 3 from the spcl field and
  89.                 set map[4] = map[0] | 0x80.  The creates the
  90.                 meta-mapping of the keys for lower case letters.
  91.         3.    if the shifted key (map[1]) is between ' ' & 0x7f and the
  92.                 map[0] value is not an upper case character,
  93.                 then remove bit 2 from the spcl field and
  94.                 set map[5] = map[1] | 0x80.  The creates the
  95.                 meta-mapping of the keys for upper case letters.
  96.         4.    write the new keyboard mapping with ioctl().
  97.  
  98.     Similar conversion is make for the "normal" emacs <esc>N prefix
  99.     sequence.  This requires forcing the 0x7d code into all <alt>x slots.
  100.     
  101.     The map structure contains map[0] entries for both lower and upper
  102.     case letters.  The lower case entries "seem" to be the only ones
  103.     used.  No explanation is offered for the upper case entries.
  104. */
  105.  
  106.  
  107. #include <stdio.h>
  108. #include <sys/types.h>
  109. #include <sys/at_ansi.h>
  110. #include <sys/kd.h>
  111. #include <sys/ioctl.h>
  112. #include <fcntl.h>
  113.  
  114. /*    where does kbmap expect to find the default map table    */
  115.  
  116. #ifndef DEFAULTMAP
  117. #define DEFAULTMAP    "/local/lib/kbmap.table"
  118. #endif
  119.  
  120. char    progname[150];
  121. int        vtlmgr;
  122.  
  123. main (argc, argv)
  124. int        argc;
  125. char    *argv[];
  126. {
  127.     extern char *optarg;
  128.     extern int    optind;
  129.     int        c;
  130.     int        select_map = -1;
  131.     char    use_file[200];
  132.     int        generate_file = 0;
  133.     FILE    *use_fp, *open_file();
  134.     char    tfile[100];
  135.     int        tn = -1;
  136.     int        index_only = 0;
  137.     char    line[200];
  138.     int        query_only = 0;
  139.     int        option_count = 0;
  140.     int        also_alt_ctl = 1;
  141.         
  142.     strcpy (progname, argv[0]);
  143.     use_fp = NULL;
  144.     use_file[0] = '\0';
  145.     if (argc == 1  ||  strcmp (argv[1], "-") == 0  || strcmp (argv[1], "--") == 0)
  146.         usage();
  147.  
  148.     while ((c = getopt(argc, argv, "aqgin:dmet:-?")) != -1)
  149.     {    option_count++;
  150.         switch (c)
  151.         {
  152.         case 'a':    also_alt_ctl = 0;                    /*    disable  alt+ctl expansion */
  153.                     break;
  154.         case 'i':    index_only = 1;
  155.                     break;
  156.         case 'n':    select_map = atoi (optarg);            /*    select by number    */
  157.                     break;
  158.         case 'd':    select_map = 0;                        /*    select default = 0    */
  159.                     if (use_file[0] == '\0')
  160.                         strcpy (use_file, DEFAULTMAP);
  161.                     break;
  162.         case 'e':    select_map = 2;                        /*    select emacs = 2    */
  163.                     if (use_file[0] == '\0')
  164.                         strcpy (use_file, DEFAULTMAP);
  165.                     break;
  166.         case 'm':    select_map = 1;                        /*    select emacs = 1 (meta) */
  167.                     if (use_file[0] == '\0')
  168.                         strcpy (use_file, DEFAULTMAP);
  169.                     break;
  170.         case 't':    strcpy (tfile, optarg);                /*    use terminal at /dev/xxxx */
  171.                     if ((tn = open (tfile, O_RDWR)) < 0)
  172.                     {    fprintf (stderr, "%s: Cannot open %s\n", progname, tfile);
  173.                         exit (1);
  174.                     }
  175.                     break;
  176.         case 'q':    query_only = 1;
  177.                     break;
  178.         case 'g':    generate_file = 1;                    /*    generate map file    */
  179.                     if (use_file[0] == '\0')
  180.                         strcpy (use_file, DEFAULTMAP);
  181.                     break;
  182.  
  183.         default:    usage ();
  184.         }
  185.     }
  186.     if (optind < argc)
  187.     {    strcpy (use_file, argv[optind]);            /*    specify map file    */
  188.         if (option_count == 0)
  189.             index_only = 1;
  190.     }
  191.  
  192.     if (tn < 1)
  193.         tn = 0;
  194.  
  195.     if (index_only)                                    /*    show index of maps    */
  196.     {    use_fp = open_file (use_file, "r");
  197.         c = 0;
  198.         while (fgets (line, 190, use_fp) != NULL)
  199.             if (strncmp (line, "...", 3) == 0)
  200.                 printf ("map %d = %s", c++, line + 3);
  201.         fclose (use_fp);
  202.         exit (0);
  203.     }        
  204.     
  205.     if (query_only)                                    /*    which map is in use    */
  206.     {    use_fp = open_file (use_file, "r");
  207.         if (query_map (use_fp) == 0)
  208.             printf ("current map is not in %s\n", use_file);
  209.         exit (0);
  210.     }
  211.  
  212.     if (generate_file)                                /*    create new kbmap.table file */
  213.     {    if (use_file[0])
  214.         {    use_fp = open_file (use_file, "w");
  215.             create_table (use_fp, tn, also_alt_ctl);
  216.             fclose (use_fp);
  217.         }
  218.         else
  219.             create_table (stdout, tn, also_alt_ctl);
  220.     }        
  221.  
  222.     if (select_map >= 0)
  223.     {    use_fp = open_file (use_file, "r");
  224.         update_map (use_fp, select_map);
  225.         fclose (use_fp);
  226.     }        
  227.  
  228.     exit (0);
  229. }
  230.  
  231. /****************************************************************************
  232. *    create_table (fp)                                                        *
  233. *    Get the existing keyboard mapping structure and write to file.            *
  234. *    Translate all alt and alt-shift keys to the meta-mapping.                *
  235. *    Write the meta-mapping structure to disk file.                            *
  236. ****************************************************************************/
  237.  
  238. create_table (fp, tn, also_alt_ctl)
  239. FILE *fp;            /*    file containing the keyboard maps                */
  240. int     tn;
  241. int     also_alt_ctl;    /*    convert ALT/CTL and ALT/SHIFT/CTL as well?        */
  242. {
  243.     int    i, j, cb, cs;
  244.     keymap_t kt;
  245.     char    title[200];
  246.  
  247.     /*    get existing mapping    */
  248.         
  249.     if (ioctl (tn, GIO_KEYMAP, &kt))
  250.         ioctl_failure ('r');
  251.  
  252.     /*     write the existing mapping to the disk file
  253.  
  254.         some potentiall useful keyboard scan numbers:
  255.     
  256.             1    esc
  257.             14    bs
  258.             15    tab
  259.             28    cr
  260.             83    del
  261.             116    cr
  262.             119    break
  263.             121    del
  264.  
  265.         For example, if scan code 1 (esc) is specifically selected,
  266.         then the <ALT><ESC> combination becomes available.  This is
  267.         not done because double-striking <esc> is quite easy.
  268.  
  269.         It might be useful to force full alt-decoding for cr and tab.
  270.         Emacs would recognize such sequences by default (see comments
  271.         in the code to make this modification)
  272.         
  273.         The variable sequence is:
  274.       char scan scpl flgs NORMAL SHIFT CTRL SHFCTL ALT ALTSHF ALTCTL ALTSHFCTL
  275.     */
  276.  
  277.     header (fp, "system default keyboard mapping", -1);
  278.     for (i = 0;  i < kt.n_keys;  i++)
  279.     {
  280.         cb = kt.key[i].map[0];
  281.         cs = kt.key[i].map[1];
  282.         fprintf (fp, "%c%c %3d   %02x   %02x", 
  283.                 cb > ' ' &&  cb < 127 ? cb : ' ',
  284.                 cs > ' ' &&  cs < 127 &&  cs != cb ? cs : ' ',
  285.                 i, 
  286.                 kt.key[i].spcl & 0x0ff, 
  287.                 kt.key[i].flgs & 0x0ff);
  288.         for (j = 0;  j < NUM_STATES;  j++)
  289.             fprintf (fp, "   %02x", kt.key[i].map[j]);
  290.         fprintf (fp, "\n");
  291.     }
  292.     
  293.     /*    convert the existing mapping to emacs-meta (8th bit set) conventions
  294.         and write to file
  295.     */    
  296.     
  297.     fprintf (fp, "\n\n");
  298.     strcpy (title, "emacs 8th bit set (<letter>|0x080) meta mapping");
  299.     header (fp, title, also_alt_ctl);
  300.     for (i = 0;  i < kt.n_keys;  i++)
  301.     {
  302.         cb = kt.key[i].map[NORMAL];            /*    base char        */
  303.         cs = kt.key[i].map[SHIFT];            /*    shifted char    */
  304.  
  305.         if (1)                                /*    things to ignore e,g,  (i == 121) */
  306.         {
  307.             /*    convert ALT key to meta. */
  308.  
  309.             /*    add the following the various "if" statements below
  310.                 to enable full conversion of \t and \n:
  311.             
  312.                     ||  (i == 15)  ||  (i == 28)
  313.             */
  314.             if ((cb >= ' '  &&  cb < 'A')  || (cb > 'Z'  &&  cb <= 127))
  315.             {    kt.key[i].map[ALT] = (kt.key[i].map[NORMAL] | 0x080);
  316.                 kt.key[i].spcl &= 0x0f7;
  317.             }
  318.  
  319.             /*    convert ALT-CTRL key to meta. (dont include <alt><ctl><del> */
  320.     
  321.             if (also_alt_ctl  
  322.                     &&  ((cb >= ' '  &&  cb < 'A')  || (cb > 'Z'  &&  cb < 127)))
  323.             {    kt.key[i].map[ALTCTL] = (kt.key[i].map[CTRL] | 0x080);
  324.                 kt.key[i].spcl &= 0x0fd;
  325.             }
  326.  
  327.             /* convert ALT-SHIFT to meta */
  328.  
  329.             if (((cb >= ' '  &&  cb < 'A')  || (cb > 'Z'  &&  cb <= 127))
  330.                     &&  (cs >= ' '  &&  cs <= 127))
  331.             {    kt.key[i].map[ALTSHF] = (kt.key[i].map[SHIFT] | 0x080);
  332.                 kt.key[i].spcl &= 0x0fb;
  333.             }
  334.         
  335.             /* convert ALT-SHIFT-CTL to meta */
  336.  
  337.             if (also_alt_ctl
  338.                     &&   ((cb >= ' '  &&  cb < 'A')  || (cb > 'Z'  &&  cb <= 127))
  339.                     &&  (cs >= ' '  &&  cs <= 127))
  340.             {    kt.key[i].map[ALTSHFCTL] = (kt.key[i].map[SHFCTL] | 0x080);
  341.                 kt.key[i].spcl &= 0x0fe;
  342.             }
  343.         }
  344.         fprintf (fp, "%c%c %3d   %02x   %02x", 
  345.                 cb > ' ' &&  cb < 127 ? cb : ' ',
  346.                 cs > ' ' &&  cs < 127 &&  cs != cb ? cs : ' ',
  347.                 i, 
  348.                 kt.key[i].spcl & 0x0ff, 
  349.                 kt.key[i].flgs & 0x0ff);
  350.         for (j = 0;  j < NUM_STATES;  j++)
  351.             fprintf (fp, "   %02x", kt.key[i].map[j]);
  352.         fprintf (fp, "\n");
  353.     }
  354.  
  355.     /*    re-get existing mapping    to remove the above meta-conversion
  356.     
  357.         Set the k.key[i].map[xx] values to 0x7d.  This seems to be
  358.         the code that forces the <esc>N sequence durning translation
  359.     */
  360.         
  361.     if (ioctl (tn, GIO_KEYMAP, &kt))
  362.         ioctl_failure('r');
  363.  
  364.     fprintf (fp, "\n\n");
  365.     strcpy (title, "emacs normal (<esc>N<letter>) meta mapping");
  366.     header (fp, title, also_alt_ctl);
  367.     for (i = 0;  i < kt.n_keys;  i++)
  368.     {
  369.         cb = kt.key[i].map[NORMAL];            /*    base char        */
  370.         cs = kt.key[i].map[SHIFT];            /*    shifted char    */
  371.  
  372.         if (1)                                /*    things to ignore */
  373.         {        /*    make ALT converssion available */
  374.  
  375.             if ((cb >= ' '  &&  cb < 'A')  ||  (cb > 'Z'  &&  cb <= 127))
  376.             {    kt.key[i].map[ALT] = 0x7d;
  377.                 kt.key[i].spcl |= 0x08;
  378.             }
  379.  
  380.             /*    make ALT-CTL conversion available  (dont include <alt><ctl><del> */
  381.  
  382.             if (also_alt_ctl
  383.                     &&  ((cb >= ' '  &&  cb < 'A')  || (cb > 'Z'  &&  cb < 127)))
  384.             {    kt.key[i].map[ALTCTL] = 0x7d;
  385.                 kt.key[i].spcl |= 0x02;
  386.             }
  387.  
  388.             /* make  ALT-SHIFT available */
  389.  
  390.             if (((cb >= ' '  &&  cb < 'A')  || (cb > 'Z'  &&  cb <= 127))
  391.                     &&  (cs >= ' '  &&  cs <= 127))
  392.             {    kt.key[i].map[ALTSHF] = 0x7d;
  393.                 kt.key[i].spcl |= 0x04;
  394.             }
  395.         
  396.             /* make  ALT-SHIFT-CTL available */
  397.  
  398.             if (also_alt_ctl
  399.                     &&    ((cb >= ' '  &&  cb < 'A')  || (cb > 'Z'  &&  cb <= 127))
  400.                     &&  (cs >= ' '  &&  cs <= 127))
  401.             {    kt.key[i].map[ALTSHFCTL] = 0x7d;
  402.                 kt.key[i].spcl |= 0x01;
  403.             }
  404.         }
  405.         fprintf (fp, "%c%c %3d   %02x   %02x", 
  406.                 cb > ' ' &&  cb < 127 ? cb : ' ',
  407.                 cs > ' ' &&  cs < 127 &&  cs != cb ? cs : ' ',
  408.                 i, 
  409.                 kt.key[i].spcl & 0x0ff, 
  410.                 kt.key[i].flgs & 0x0ff);
  411.         for (j = 0;  j < NUM_STATES;  j++)
  412.             fprintf (fp, "   %02x", kt.key[i].map[j]);
  413.         fprintf (fp, "\n");
  414.     }
  415.  
  416. }
  417.  
  418. /****************************************************************************
  419. *    header ()                                                                *
  420. *    Standard table header generation                                        *
  421. ****************************************************************************/
  422.  
  423. header (fp, title, also_alt_ctl)
  424. FILE *fp;
  425. char    *title;
  426. {    fprintf (fp, "...%s", title);
  427.     if (also_alt_ctl == -1)
  428.         fprintf (fp, "\n");
  429.     else if (also_alt_ctl)
  430.         fprintf (fp, " -- full alt/ctl\n");
  431.     else
  432.         fprintf (fp, " -- no alt/ctl\n");
  433.     fprintf (fp, "                                                     alt\n");
  434.     fprintf (fp, "                                 shif      alt  alt  shif\n");
  435.     fprintf (fp, "  key   spcl flgs norm shif ctrl ctrl alt  shif ctrl ctrl\n");
  436.     fprintf (fp, "------  ---- ---- ---- ---- ---- ---- ---- ---- ---- ----\n");
  437. }
  438.  
  439.  
  440. /****************************************************************************
  441. *    update_map (fp, which_map)                                                *
  442. *    Read the specified mapping table from the map file.  Send the new map    *
  443. *    to key keyboard driver.                                                    *
  444. ****************************************************************************/
  445.  
  446. update_map (fp, which_map)
  447. FILE *fp;                /*    file containing keyboard maps                    */
  448. int     which_map;            /*    select this table from the file  (0..n)            */
  449. {
  450.     int    i, j, how;
  451.     keymap_t kt;
  452.  
  453.     /*    find the desired map in the file and read it into the keytable */
  454.     
  455.     if (ioctl (1, GIO_KEYMAP, &kt))                        /*    read current map        */
  456.         ioctl_failure ('r');
  457.  
  458.     for (i = 0;  i <= which_map;  i++)
  459.         how = read_map (i == which_map, fp, &kt, NULL);
  460.     if (how)
  461.     {    fprintf (stderr, "%s: map %d not found\n", progname, which_map);
  462.         exit (1);
  463.     }
  464.     if (ioctl (1, PIO_KEYMAP, &kt))                        /*    send found map to driver */
  465.         ioctl_failure ('w');
  466. }
  467.  
  468. /****************************************************************************
  469. *    query_map (fp)                                                            *
  470. *    Identifiy which table file map matches the keyboard map in use.            *
  471. ****************************************************************************/
  472.  
  473. query_map (fp)
  474. FILE *fp;                /*    file containing keyboard maps                    */
  475. {
  476.     int    i, j, k;
  477.     char    text[200];
  478.     keymap_t kt, inuse;
  479.     int        found;
  480.     int        vtlmgr;
  481.  
  482.     if (ioctl (1, GIO_KEYMAP, &inuse))                    /*    read current map        */
  483.         ioctl_failure ('r');
  484.  
  485.     vtlmgr = 0;
  486.     found = 0;
  487.     kt = inuse;
  488.     for (k = 0;  ;  k++)
  489.     {    if (read_map (1, fp, &kt, text))
  490.             return (found);
  491.         for (i = 0;  i < inuse.n_keys;  i++)
  492.         {    for (j = 0;  j < NUM_STATES;  j++)        /*    compare all keys    */
  493.             {    if (inuse.key[i].map[j] != kt.key[i].map[j])
  494.                 {    /* detect minor mod made by vtlmgr  in line 3 for  "1!" */
  495.                     if (i == 2  &&  (j == ALTSHF  ||  j == ALTSHFCTL))
  496.                         vtlmgr = 1;
  497.                     else
  498.                         goto next_map;
  499.                 }
  500.             }
  501.         }
  502.         printf ("using map %d: %s\n", k, text);
  503.         if (vtlmgr)
  504.             printf ("             (modified by vtlmgr)\n");
  505.         found = 1;
  506.         break;
  507. next_map:    ;
  508.     }
  509.     return (found);
  510. }
  511.  
  512. /****************************************************************************
  513. *    read_map (fp, kt, title)                                                *
  514. *    Read the nextd mapping table from the map file.                            *
  515. ****************************************************************************/
  516.  
  517. read_map (getit, fp, kt, title)
  518. int            getit;        /*    1 = update kt, 0 = get title only            */
  519. FILE         *fp;        /*    file containing keyboard maps                */
  520. keymap_t    *kt;        /*    read structure into this                    */
  521. char        *title;        /*    read title line into this buffer            */
  522. {
  523.     int    i, j, cc;
  524.     char    key_line[200], *c;
  525.     int        a0,a1,a2,a3,a4,a5,a6,a7,a8,a9;
  526.     int        good_read;
  527.     
  528.     /*    find the next map in the file and read it into the keytable */
  529.     
  530.     while (good_read = (fgets (key_line, 199, fp) != NULL))
  531.     {    if (title != NULL  &&  strncmp (key_line, "...", 3) == 0)
  532.         {    strcpy (title, key_line + 3);
  533.             c = title;
  534.             while (*c)
  535.             {    if (*c < ' ')
  536.                 {    *c = '\0';
  537.                     break;
  538.                 }
  539.                 c++;
  540.             }
  541.         }
  542.         else if (strncmp (key_line, "------  -", 8) == 0)
  543.             break;
  544.     }
  545.     if (good_read == 0)
  546.         return (-1);
  547.     if (strncmp (key_line, "------  -", 8) != 0)
  548.         bad_file ();
  549.  
  550.     if (getit == 0)
  551.         return (1);
  552.     for (i = 0;  i < kt->n_keys;  i++)
  553.     {    if (fgets (key_line, 199, fp) == NULL)
  554.             bad_file ();
  555.         if (atoi (key_line + 2) != i)
  556.             bad_file ();
  557.         sscanf (key_line + 7, "%x %x %x %x %x %x %x %x %x %x",
  558.                 &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9);
  559.         kt->key[i].spcl        = a0;
  560.         kt->key[i].flgs        = a1;
  561.         kt->key[i].map[0]    = a2;
  562.         kt->key[i].map[1]    = a3;
  563.         kt->key[i].map[2]    = a4;
  564.         kt->key[i].map[3]    = a5;
  565.         kt->key[i].map[4]    = a6;
  566.         kt->key[i].map[5]    = a7;
  567.         kt->key[i].map[6]    = a8;
  568.         kt->key[i].map[7]    = a9;
  569.          
  570.     }
  571.     return (0);
  572. }
  573.  
  574. /****************************************************************************
  575. *    open_file (use_file, how)                                                *
  576. *    Open a table file.  If there is a problem, quit now.                    *
  577. ****************************************************************************/
  578.  
  579. FILE *open_file (use_file, how)
  580. char    *use_file;
  581. char    *how;
  582. {    FILE    *use_fp;
  583.     char    *strchr();
  584.  
  585.     if (*use_file == '\0')
  586.         strcpy (use_file, DEFAULTMAP);
  587.  
  588.     if ((use_fp = fopen (use_file, how)) == NULL)
  589.     {    fprintf (stderr, "%s: cannot open file %s\n", progname, use_file);
  590.         exit (1);
  591.     }
  592.     return (use_fp);
  593. }
  594.  
  595. /****************************************************************************
  596. *    bad_file ()                                                                *
  597. ****************************************************************************/
  598.  
  599. bad_file ()
  600. {
  601.     fprintf (stderr, "%s: invalid key map file format\n", progname);
  602.     exit (2);
  603. }
  604.  
  605. ioctl_failure (how)
  606. int        how;
  607. {
  608.     fprintf (stderr, "%s: ioctl failure, %s\n", 
  609.         progname, how == 'r' ? "cannot read, possibly using X11???" : "must be root?");
  610.     exit (2);
  611. }
  612.  
  613. /****************************************************************************
  614. *    usage ()                                                                *
  615. ****************************************************************************/
  616.  
  617. usage ()
  618. {
  619.     printf ("Usage:     kbmap [-i] [-q] [-g] [-n n] [-d] [-e] [-m] [-1] [-t /dev/xxx] [file]\n");
  620.     printf ("    where:        -i      = show index of available maps\n");
  621.     printf ("                  -q      = identify map currenly in use\n");
  622.     printf ("                  -g      = generate a key map table\n");
  623.     printf ("                  -n n    = set keyboard to map 'n' mapping\n");
  624.     printf ("                  -d      = set keyboard to default mapping\n");
  625.     printf ("                  -e      = set keyboard to emacs mapping (<esc>N)\n");
  626.     printf ("                  -m      = set keyboard to emacs meta-mapping (8bit)\n");
  627.     printf ("                  -a      = disable <alt><ctl> & <alt><shf><ctl>\n");
  628.     printf ("                  -t /dev/xxx = apply map to this device (default stdin)\n");
  629.     printf ("                  file    = use specified key map file\n");
  630.     printf ("                            default = %s\n", DEFAULTMAP);
  631.     exit (0);
  632. }
  633.