ftp.nice.ch/pub/next/unix/developer/slang0.99-34.s.tar.gz#/slang/src/slkeymap.c

This is slkeymap.c in view mode; [Download] [Up]

/* Keymap routines for SLang.  The role of these keymap routines is simple:
 * Just read keys from the tty and return a pointer to a keymap structure.  
 * That is, a keymap is simple a mapping of strings (keys from tty) to 
 * structures.  Also included are routines for managing the keymaps. 
 */
/* Copyright (c) 1992, 1995 John E. Davis
 * All rights reserved.
 * 
 * You may distribute under the terms of either the GNU General Public
 * License or the Perl Artistic License.
 */


#include "config.h"

#include <stdio.h>
#include <string.h>


#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif

#include "slang.h"
#include "_slang.h"

/* We need a define a rule for upperand lower case chars that user cannot
   change!  This could be a problem for international chars! */

#define UPPER_CASE_KEY(x) (((x) >= 'a') && ((x) <= 'z') ? (x) - 32 : (x))
#define LOWER_CASE_KEY(x) (((x) >= 'A') && ((x) <= 'Z') ? (x) + 32 : (x))

int SLang_Key_TimeOut_Flag = 0;	       /* true if more than 1 sec has elapsed
                                          without key in multikey sequence */

int SLang_Last_Key_Char;




SLKeyMap_List_Type SLKeyMap_List[SLANG_MAX_KEYMAPS];   /* these better be inited to 0! */

static SLang_Key_Type *malloc_key(unsigned char *str)
{
   SLang_Key_Type *neew;

   if (NULL == (neew = (SLang_Key_Type *) SLMALLOC(sizeof(SLang_Key_Type))))
     {
	SLang_Error = SL_MALLOC_ERROR;
	return NULL;
     }
   SLMEMCPY((char *) neew->str, (char *) str, (unsigned int) *str);
   return(neew);
}


static SLKeyMap_List_Type *add_keymap(char *name, SLang_Key_Type *map)
{
   int i;

   for (i = 0; i < SLANG_MAX_KEYMAPS; i++)
     {
	if (SLKeyMap_List[i].keymap == NULL)
	  {
	     SLKeyMap_List[i].keymap = map;
	     strncpy((char *) SLKeyMap_List[i].name, (char *) name, MAX_KEYMAP_NAME_LEN);
	     SLKeyMap_List[i].name[MAX_KEYMAP_NAME_LEN] = 0; 
	     return &SLKeyMap_List[i];
	  }
     }
   SLang_Error = UNKNOWN_ERROR;
   /* SLang_doerror ("Keymap quota exceeded."); */
   return NULL;
}

#ifdef SLKEYMAP_OBSOLETE
VOID_STAR 
#else
FVOID_STAR
#endif
SLang_find_key_function(char *name, SLKeyMap_List_Type *keymap)
{
   SLKeymap_Function_Type *fp = keymap -> functions;
   
   while ((fp != NULL) && (fp->name != NULL))
     {
	if ((*fp->name == *name) && !strcmp(fp->name, name)) 
	  {
#ifdef SLKEYMAP_OBSOLETE
	     return (VOID_STAR) fp->f;
#else
	     return (FVOID_STAR) fp->f;
#endif
	  }
	fp++;
     }
   return(NULL);
}

/* convert things like "^A" to 1 etc... The 0th char is the strlen INCLUDING
 * the length character itself.
 */
char *SLang_process_keystring(char *s)
{
   static char str[30];
   unsigned char ch;
   int i;

   i = 1;
   while (*s != 0)
     {
	ch = (unsigned char) *s++;
	if (*s) ch = UPPER_CASE_KEY(ch);
	if (ch == '^')
	  {
	     ch = *s++;
	     if (ch == 0)
	       {
		  str[i++] = '^';
		  break;
	       }
	     if (ch == '?') ch = 127; else ch = ch - 'A' + 1;
	  }
	
	str[i++] = ch;
     }
   str[0] = i;
   return(str);
}


static char *Define_Key_Error = "Inconsistency in define key.";

static int find_the_key (char *s, SLKeyMap_List_Type *kml, SLang_Key_Type **keyp)
{
   int cmp, i, m, n, len;
   SLang_Key_Type *key, *last, *neew;
   unsigned char *str;

   *keyp = NULL;
   str = (unsigned char *) SLang_process_keystring(s);
   if (1 == (n = str[0])) return 0;

   i = *(str + 1);
   key = &((kml->keymap)[i]);

   if (n == 2)
     {
	if (key->next != NULL)
	  {
	     SLang_doerror (Define_Key_Error);
	     return -2;
	  }
	
	/* copy keymap uses the pointers so do not free these if copied */
	if ((SLKeyMap_List[1].keymap == NULL)
	    && (key->type == SLKEY_F_INTERPRET))
	  {
#ifdef SLKEYMAP_OBSOLETE
	     SLFREE(key->f);
#else
	     SLFREE (key->f.s);
#endif
	  }

	SLMEMCPY((char *) key->str, (char *) str, 2);
	*keyp = key;
	return 0;
     }

   /* insert the key definition */
   while(1)
     {
	last = key;
	key = key->next;
	if ((key == NULL) || (key->str == NULL)) cmp = -1;
	else
	  {
	     m = key->str[0];
	     len = m;
	     if (m > n) len = n;
	     cmp = SLMEMCMP((char *) (str + 1), (char *)(key->str + 1), len - 1);
	     if ((m != n) && !cmp)
	       {
		  SLang_doerror (Define_Key_Error); 
		  return -2;
	       }
	     if ((m == n) && (!cmp)) cmp = SLMEMCMP((char *) str, (char *) key->str, n);
	  }

	if (cmp == 0)
	  {
	       /* copy keymap uses the pointers so do not free these if copied */
	     if ((SLKeyMap_List[1].keymap == NULL)
		 && (key->type == SLKEY_F_INTERPRET))
	       {
#ifdef SLKEYMAP_OBSOLETE	
		  SLFREE(key->f);
#else
		  SLFREE(key->f.s);
#endif
	       }
	     
	     *keyp = key;
	     return 0;
	  }
	else if (cmp < 0)
	  {
	     if (NULL == (neew = malloc_key(str))) return -1;
	     
	     neew -> next = key;
	     last -> next = neew;
	     
	     *keyp = neew;
	     return 0;
	  } /* else cmp > 0 */
      }
}

/* returns -2 if inconsistent, -1 if malloc error, 0 upon success */
#ifdef SLKEYMAP_OBSOLETE
int SLang_define_key1 (char *s, VOID_STAR f, unsigned int type, SLKeyMap_List_Type *kml)
#else
int SLkm_define_key (char *s, FVOID_STAR f, SLKeyMap_List_Type *kml)
#endif
{
   SLang_Key_Type *key;
#ifndef SLKEYMAP_OBSOLETE
   unsigned int type = SLKEY_F_INTRINSIC;
#endif
   int ret;
   
   ret = find_the_key (s, kml, &key);
   if ((ret != 0) || (key == NULL))
     return ret;

   key->type = type;
#ifdef SLKEYMAP_OBSOLETE
   key->f = f;
#else
   key->f.f = f;
#endif
   return 0;
}

int SLang_define_key(char *s, char *funct, SLKeyMap_List_Type *kml)
{
   SLang_Key_Type *key;
#ifdef SLKEYMAP_OBSOLETE
   VOID_STAR f;
#else
   FVOID_STAR f;
#endif
   int ret;
   
   ret = find_the_key (s, kml, &key);
   if ((ret != 0) || (key == NULL))
     return ret;

   f = SLang_find_key_function(funct, kml);

   if (f == NULL)                      /* assume interpreted */
     {
	char *str = SLmake_string (funct);
	if (str == NULL) return -1;
	key->type = SLKEY_F_INTERPRET;
#ifdef SLKEYMAP_OBSOLETE
	key->f = (VOID_STAR) str;
#else
	key->f.s = str;
#endif
     }
   else 
     {
	key->type = SLKEY_F_INTRINSIC;
#ifdef SLKEYMAP_OBSOLETE
	key->f = f;
#else
	key->f.f = f;
#endif
     }
   return 0;
}


SLang_Key_Type *SLang_do_key(SLKeyMap_List_Type *kml, int (*getkey)(void))
{
   register SLang_Key_Type *key, *next;
   int i;
   unsigned char ch1, ch;
   register unsigned char chi, chup, chlow;
   
   ch = (unsigned char) (*getkey)();
   
   SLang_Last_Key_Char = (int) ch;

   i = ch1 = (unsigned char) ch;

   key = (SLang_Key_Type *) &((kml->keymap)[i]);

   /* if the next one is null, then we know this is it. */
   if (key->next == NULL) 
     {
	/* check its uppercase counterpart if null and return it */
	if (
#ifdef SLKEYMAP_OBSOLETE
	    (key->f == NULL)
#else
	    (key->f.f == NULL)
#endif
	    && (i >= 'a') && (i <= 'z')) 
	  key = (SLang_Key_Type *) &((kml->keymap)[i - 32]);
	SLang_Key_TimeOut_Flag = 0;
	return(key);
     }
   
   key = key->next;
   SLang_Key_TimeOut_Flag = 1;
   SLang_Last_Key_Char = (*getkey)();
   
   i = 2;			       /* 0 is keylen, 1 matches, so 2 */
   ch1 = (unsigned char) SLang_Last_Key_Char;
   chup = UPPER_CASE_KEY(ch1); chlow = LOWER_CASE_KEY(ch1);

   while(key != NULL)
     {
	if (SLKeyBoard_Quit) break;
	chi = key->str[i];
	if ((chup == chi) || (chlow == chi))
	  {
	     if (*key->str == i + 1)
	       {
		  /* look for exact match if possible */
		  if (ch1 != chi)
		    {
		       next = key->next;
		       while (next != NULL)
			 {
			    if (next->str[i] == ch1)
			      {
				 if (next->str[0] == i + 1) 
				   {
				      SLang_Key_TimeOut_Flag = 0;
				      return(next);
				   }
				 break;
			      }
			    next = next->next;
			 }
		    }
		  SLang_Key_TimeOut_Flag = 0;
		  return(key);
	       }

	     /* before reading a new key, check to see if it is lowercase
	      * and try to find a match for it.  Note that this works because
	      * only the LAST character in a key sequence can be lowercase */

	     else if ((ch1 == chlow) && (ch1 != chup))
	       {
		  next = key->next;
		  /* look for the lowercase one */
		  while (next != NULL)
		    {
                        if ((next->str[i] == chlow) &&
                            (next->str[0] == i + 1)) 
		       	 {
			    SLang_Key_TimeOut_Flag = 0;
			    return(next);
			 }
		       next = next->next;
		    }
	       }

	     SLang_Last_Key_Char = ch1 = (*getkey)();
	     i++;
	     chup = UPPER_CASE_KEY(ch1);
	     chlow = LOWER_CASE_KEY(ch1);
	     continue;
	  }
	else if (chlow < chi) break;  /* not found */

	/* else */
	key = key->next;
     }
   /* not found */
   SLang_Key_TimeOut_Flag = 0;
   return(NULL);
}



void SLang_undefine_key(char *s, SLKeyMap_List_Type *kml)
{
   int n, i;
   SLang_Key_Type *key, *next, *last, *key_root, *keymap;
   unsigned char *str;

   keymap = kml -> keymap;
   str = (unsigned char *) SLang_process_keystring(s);

   if (0 == (n = *str++ - 1)) return;
   i = *str;
   key = key_root = (SLang_Key_Type *) &(keymap[i]);

   last = key_root;
   key = key_root->next;
   while (key != NULL)
     {
	next = key->next;
	if (!SLMEMCMP((char *)(key->str + 1), (char *) str, n))
	  {
	     if ((SLKeyMap_List[1].keymap == NULL)
		 && (key->type == SLKEY_F_INTERPRET))
	       {
#ifdef SLKEYMAP_OBSOLETE
		  SLFREE(key->f);
#else
		  SLFREE (key->f.s);
#endif
	       }
	     SLFREE(key);
	     last->next = next;
	  }
	else last = key;
	key = next;
     }

   if (n == 1)
     {
	*key_root->str = 0;
#ifdef SLKEYMAP_OBSOLETE
	key_root->f = NULL;
#else
	key_root->f.f = NULL;
#endif
	key_root->type = 0;
     }
}

char *SLang_make_keystring(unsigned char *s)
{
   static char buf[40];
   char *b;
   int n;

   b = buf;
   n = *s++ - 1;
   while (n--)
     {
	if (*s < 32)
	  {
	     *b++ = '^';
	     *b++ = *s + 'A' - 1;
	  }
	else *b++ = *s;
	s++;
     }
   *b = 0;
   return(buf);
}




static SLang_Key_Type *copy_keymap(SLKeyMap_List_Type *kml)
{
   int i;
   SLang_Key_Type *neew, *old, *new_root, *km;

   if (NULL == (new_root = (SLang_Key_Type *) SLCALLOC(256, sizeof(SLang_Key_Type))))
     {
	SLang_Error = SL_MALLOC_ERROR;
	return NULL;
     }

   if (kml == NULL) return new_root;
   km = kml->keymap;

   
   for (i = 0; i < 256; i++)
     {
	old = &(km[i]);
	neew = &(new_root[i]);
#ifdef SLKEYMAP_OBSOLETE
	neew->f = old->f;
#else
	if (old->type == SLKEY_F_INTERPRET)
	  neew->f.s = old->f.s;
	else
	  neew->f.f = old->f.f;
#endif
	neew->type = old->type;
	SLMEMCPY((char *) neew->str, (char *) old->str, (unsigned int) *old->str);

	old = old->next;
	while (old != NULL)
	  {
	     neew->next = malloc_key((unsigned char *) old->str);
	     neew = neew->next;
#ifdef SLKEYMAP_OBSOLETE
	     neew->f = old->f;
#else
	     if (old->type == SLKEY_F_INTERPRET)
	       neew->f.s = old->f.s;
	     else
	       neew->f.f = old->f.f;
#endif
	     neew->type = old->type;
	     old = old->next;
	  }
	neew->next = NULL;
     }
   return(new_root);
}


SLKeyMap_List_Type *SLang_create_keymap(char *name, SLKeyMap_List_Type *map)
{
   SLang_Key_Type *neew;
   SLKeyMap_List_Type *new_map;
   
   if ((NULL == (neew = copy_keymap(map)))
       || (NULL == (new_map = add_keymap(name, neew)))) return NULL;
   
   if (map != NULL) new_map -> functions = map -> functions;
   
   return new_map;
}

SLKeyMap_List_Type *SLang_find_keymap(char *name)
{
   int i;

   for (i = 0; i < SLANG_MAX_KEYMAPS; i++)
     {
	if (!strncmp(SLKeyMap_List[i].name, name, 8)) return &SLKeyMap_List[i];
     }
   return(NULL);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.