/* EDIMAP Un éditeur de table de clavier
 *
 *	Version 1.0 de Septembre 1988 par Gilles Gamesh
 *
 *
 * Ce programme se compile sous Aztec 3.6 avec le makefile suivant :
 *
 * CFLAGS = +Iedimap.inc +l +x3
 *
 * OBJS	= edimap.o lit_map.o
 * # ----------------------------------------------------------------
 * edimap			: $(OBJS)
 * 	ln -o $@ $(OBJS) -lc32
 *
 * edimap.inc			: edimap.h
 * 	cc -A +Hedimap.inc edimap.h +l +x3
 * 
 * edimap.o			: edimap.c gadgets.h func.h edimap.inc
 *
 * lit_map.o			: lit_map.c func.h edimap.inc
 *
 *
 * Le code n'est peut-être pas du meilleur C mais il marche, certaines
 * étrangetées peuvent être du à mon incompréhension de certains points
 * de la table ou à certains bugs du système.
 *
 *
 */


#include "edimap.h"
#include "gadgets.h"
#include "func.h"

char usage[] = "\tEdimap v1.0\nUsage: Edimap keymap_name";

/*-----------------------------------------------------------------*/
void main(argc, argv)
int argc;
UBYTE *argv[];
{

  struct FileHandle *f_in;
  UWORD *pword;
  int taille, i;
  ULONG longtab, nb_str;
  ULONG *pnb_str, *deb_p_str;
  ULONG Class;
  USHORT Code, Qualifier;
  BOOL encore = TRUE, flgraw = TRUE, flgsave = FALSE;
  struct Gadget   *pMGad;
  USHORT pMGadID;

	if (argc == 2)
	{   if (argv[1][0] == '?') { puts(usage); exit(); }
	    else
	        strncpy(nom,argv[1],31);
	}
	else { puts(usage); exit(); }

    if ((buf_p = (struct P_String *)AllocMem(sizeof(struct P_String)*P_SIZE,
						MEMF_CLEAR)) == NULL)
    {   printf(pas_de_place);
        exit(1);
    }
    if ((buffer = (struct P_String *)AllocMem(sizeof(struct P_String)*P_SIZE,
						MEMF_CLEAR)) == NULL)
    {   printf(pas_de_place);
        goto error1;
    }
    if ((alstrflag = (UBYTE *)AllocMem(sizeof(UBYTE)*P_SIZE,
						MEMF_CLEAR)) == NULL)
    {   printf(pas_de_place);
        goto error2;
    }

/*printf("filebuf %lx\n",filebuf);*/
    if ((f_in = Open(nom,MODE_OLDFILE)) == NULL)
    {  printf("Je ne peux trouver le fichier %s\n",nom); 
       goto error3;
    }

    taille = Seek(f_in,0L,OFFSET_END);
    taille = Seek(f_in,0L,OFFSET_BEGINNING);
/*	printf("taille %d\n",taille);*/
    if (taille == 0L)
    {   printf("Fichier vide\n");
	goto error3bis;
    }

    if ((filebuf = (UBYTE *)AllocMem(taille+1,0L)) == NULL)
    {   printf(pas_de_place);
	goto error3bis;
    }

    if (Read(f_in,filebuf,taille) <= NULL)
    {  printf("Je ne peux lire ce fichier\n"); 
	goto error4;
    }

    if ((IntuitionBase = (struct IntuitionBase *)
		OpenLibrary("intuition.library", 0L)) == NULL) goto error4;
    if ((GfxBase = (struct GfxBase *)
		OpenLibrary("graphics.library", 0L)) == NULL) goto error5;

    if (!(window = (struct Window *)OpenWindow(&newWindow)))
    {  printf("Je ne peux ouvrir la fenètre\n"); 
	goto error6;
    }
    wRPort = window->RPort;
/*printf("taille %x,1er %lx\n",taille,*((LONG *)filebuf));*/
    if (lit_table())
    { printf("Ce n'est pas une table de clavier\n");
      goto error7;
    }
    question.IText =(UBYTE *)MTapez;
    PrintIText(wRPort,&question,0L,0L);

    while (encore == TRUE)
    {  Wait(1 << window->UserPort->mp_SigBit);
       while (Message = (struct IntuiMessage *)GetMsg(window->UserPort))
       {  Class = Message->Class;
          Code = Message->Code;
	  Qualifier = Message->Qualifier;
          ReplyMsg(Message);
          pMGad   = (struct Gadget *)Message->IAddress;
          pMGadID = pMGad->GadgetID;
  
	  if (!(flgraw) && !(flgsave))
	  { question.IText =(UBYTE *)BlancLigne;
	    PrintIText(wRPort,&question,0L,0L);
	  }
	  switch (Class)
	  {  case RAWKEY :
		if ((Code < 0x60) && flgraw)
		{   flgraw = FALSE; flgsave = FALSE;
		    question.IText =(UBYTE *)BlancLigne;
		    PrintIText(wRPort,&question,0L,0L);
		    if (etape == MAL_FINI)
		    {  etape = 0;
		       question.IText =(UBYTE *)BlancLigne;
		       PrintIText(wRPort,&question,100L,100L);
		    }
		    affichegad(ON);

		    LoType = (Code<0x40) ? TRUE : FALSE;
		    key_rel = (Code<0x40) ? Code : Code-0x40;
		    key_abs = Code;
		    initkey();
		    decodekey();
		    ajustgad(qual);
		}
		break;

             case GADGETUP:
		switch (pMGadID)
     		{
                  case G_SHIFT:
		     modifyGad(KCF_SHIFT,G_SHIFT);
                     break;

                  case G_CTRL:
		     modifyGad(KCF_CONTROL,G_CTRL);
                     break;

                  case G_ALT:
		     modifyGad(KCF_ALT,G_ALT);
                     break;

                  case G_DEAD:
		     priorGad(KCF_DEAD,KCF_STRING);
                     break;

                  case G_STRING:
		     priorGad(KCF_STRING,KCF_DEAD);
                     break;

                  case G_OK:        /* OK */
	             ajustkey();
		     if (invalide)
		     {  CopyMem(txt_err[-invalide-1],MErreur+POS_ERR,3L);
			question.IText =(UBYTE *)MErreur;
			PrintIText(wRPort,&question,0L,0L);
			invalide = FAUX;
			break;
		     }
		     modifie = TRUE;
                  case G_ABORT:      /* RESET */
		     question.IText =(UBYTE *)MTapez;
		     PrintIText(wRPort,&question,0L,0L);
		     flgraw = TRUE;
		     affichegad(OFF);
                     break;

                  case G_SAVE:
		     flgraw = FALSE; flgsave = TRUE;
		     etape=NOM_DU_FICHIER; quel_noms();
		     break;

                  case G_NOM:
		     PrintIText(wRPort,&Blanc_Txt,0L,TNSTRG);
		     if (etape == NOM_DU_FICHIER)
		     {  etape=NOM_DE_LA_TABLE;
			quel_noms();
		     }
		     else if (etape == NOM_DE_LA_TABLE)
		     {	etape=ECRITURE;
			quel_noms();
		     }
		     if (etape >= FINI)
		     {  if (etape == FINI) etape = 0;
			question.IText =(UBYTE *)MFClose;
			PrintIText(wRPort,&question,0L,0L);
			flgraw = TRUE;
			OnGadget(&SaveGad,window,0L);
			OffGadget(&OkGad,window,0L); /* pour rafraichir */
		     }
		     break;
		}
		break;

	     case CLOSEWINDOW :
		if (modifie) 
		{ question.IText =(UBYTE *)MSortie;
		  PrintIText(wRPort,&question,0L,0L);
		  modifie = FALSE;
		}
		else
		  encore = FALSE;
	    }
	}
    }

error7:
    CloseWindow(window); 
error6:
    CloseLibrary(GfxBase);
error5:
    CloseLibrary(IntuitionBase);
error4:
    FreeMem(filebuf,taille+1);
error3bis:
    Close(f_in);
error3: 
    FreeMem((char *)alstrflag,(long)sizeof(UBYTE)*P_SIZE);
error2: 
    FreeMem((char *)buffer,(long)sizeof(struct P_String)*P_SIZE);
error1: 
    FreeMem((char *)buf_p,(long)sizeof(struct P_String)*P_SIZE);
}
/*----------------------------------------*/
/* Cette fonction sélecte les 'qualifier gadgets' et ajoute les
 * 'string gadgets' conormément aux flags passés en argument
 */
void ajustgad(flg)
UBYTE flg;
{
    UBYTE vanille = (flg == KC_VANILLA);

    strdead = qual & (KCF_DEAD | KCF_STRING);

    AddGadget(window,&StringGad[b_N],-1L);

    if (flg & KCF_SHIFT)
    {   selectGad(&TogGad[G_SHIFT],G_SHIFT,ON);
	AddGadget(window,&StringGad[b_S],-1L);
    }
    else if (flg & KCF_CONTROL && flg & KCF_ALT) AddGadget(window,&StringGad[b_CA],-1L);

    if (flg & KCF_ALT)
    {   selectGad(&TogGad[G_ALT],G_ALT,ON);
	AddGadget(window,&StringGad[b_A],-1L);
    }
    if (flg & KCF_CONTROL)
    {   selectGad(&TogGad[G_CTRL],G_CTRL,ON);
	if (!(vanille)) AddGadget(window,&StringGad[b_C],-1L);
    }
    if (flg & KCF_SHIFT && flg & KCF_ALT) AddGadget(window,&StringGad[b_SA],-1L);
    if (flg & KCF_CONTROL && flg & KCF_SHIFT && !(vanille))
    {   AddGadget(window,&StringGad[b_CS],-1L);
    }

    if ((flg & KC_VANILLA)==KC_VANILLA) 
    {   if (strdead)
	{ AddGadget(window,&StringGad[b_CSA],-1L);
          AddGadget(window,&StringGad[b_CA],-1L);
	}
	else
	{ AffGadget(&StringGad[b_C],b_C);
	  AffGadget(&StringGad[b_CS],b_CS);
	}
    }
    RefreshGadgets(&StringGad[b_N],window,0L);
    if (flg & KCF_DEAD)
    {   selectGad(&TogGad[G_DEAD],G_DEAD,ON);
	selectGad(&TogGad[G_STRING],G_STRING,OFF);
    }
    if (flg & KCF_STRING)
    {   selectGad(&TogGad[G_STRING],G_STRING,ON);
	selectGad(&TogGad[G_DEAD],G_DEAD,OFF);
    }

}
/*----------------------------------------*/
/* Cette fonction affiche l'image d'un pseudo 'string gadget' */

AffGadget(unGadget,code)
struct Gadget *unGadget;
int code;
{
    static struct IntuiText unText =  {3,0,JAM1,LSTRG};/* init debut */

	unText.TopEdge = unGadget->TopEdge;
	unText.IText = unGadget->GadgetText->IText;
	PrintIText(wRPort,&unText,-LSTRG+4L,0L);
	unText.IText = StrBuf[code];
	PrintIText(wRPort,&unText,0L,0L);
}
/*----------------------------------------*/
/* Cette fonction effaces tous les 'string gadgets' */

void deleteSgadgets(onoff)
BOOL onoff;
{
   int i;
	for (i=b_N; i<=b_CSA; i++) RemoveGadget(window,&StringGad[i]);
	if (!(onoff))
	{  for (i=b_N; i<=b_CSA; i++)
	   	StrBuf[i][0] = '\0';
	}
	for (i=b_N; i<=b_CSA; i++)
	    PrintIText(wRPort,&Blanc_Txt,0L,TSTRG+HSTRG*i);
}
/*----------------------------------------*/
/* Change les selections de gadgets entre le mode édition et commande */

affichegad(onoff)
BOOL onoff;
{
   int i;
	if (onoff)
	{ cleargadgets();
	  OnGadget(&AbortGad,window,0L);
	  OffGadget(&SaveGad,window,0L);
	  OnGadget(&OkGad,window,0L);
/*	  RefreshGadgets(&OkGad,window,0L);*/
	}
	else
	{ cleargadgets();
	  deleteSgadgets(OFF);
	  OffGadget(&AbortGad,window,0L);
	  OnGadget(&SaveGad,window,0L);
	  OffGadget(&OkGad,window,0L);
	  for (i=G_SHIFT; i<=G_DEAD; i++) selectGad(&TogGad[i],i,OFF);
/*	  RefreshGadgets(&OkGad,window,0L);*/
	}
	  
}
/*----------------------------------------*/
/* efface les gadgets de l'écran */

cleargadgets()
{	SetAPen(window->RPort,0L);
	RectFill(window->RPort,LGAD-10L,HEIGHT+BGAD-2L,WIDTH-20L,HEIGHT-2L);
	SetAPen(window->RPort,1L);
}
/*----------------------------------------*/
/* sélecte ou déselecte un gadget, un certaine gymnastique a été
 * nécessaire à cause d'un bug qui bascule l'affichage du fond d'un
 * 'toggle gadget' à chaque refresh
 */

void selectGad(pGad,pos,onoff)
struct Gadget *pGad;
BOOL onoff;
int pos;
{
   int deja_selecte = 0;
	RemoveGadget(window,pGad);
	deja_selecte = pGad->Flags & SELECTED;
	if (onoff)
	{ if (!(deja_selecte))
	  { pGad->Flags |= SELECTED;
	    RefreshGList(pGad,window,0L,1L);
	  }
 	}
	else
	{ if (deja_selecte)
	  { RefreshGList(pGad,window,0L,1L);/* eteint centre */
	    pGad->Flags &= ~SELECTED;
	    RefreshGList(pGad,window,0L,1L);/* eteint bordure */
	  }
	}
	AddGadget(window,pGad,(long)(pos+3));
}
/*----------------------------------------*/
/* Si STRING pas DEAD et vice versa */

void priorGad(gadoui,gadnon)
ULONG gadoui, gadnon;
{   UWORD i;
	qual &= ~(gadnon);
	if (qual & gadoui)
	   qual &= ~(gadoui);
	else
	   qual |= gadoui;

	deleteSgadgets(OFF);
/*	for (i=b_N; i<=b_CSA; ++i) StrBuf[i][0] = 0;*/
	ajustgad(qual);
}
/*----------------------------------------*/
/* on a cliqué et sélecté le gadget du type 'type' */

void modifyGad(un_qual,type)
ULONG un_qual;
int type;
{
    int flg;

	deleteSgadgets(ON);
	flg = TogGad[type].Flags;
	qual &= ~(un_qual);
	if (flg == SELECTED) qual |= un_qual;
	StrBuf[b_CSA][0] = 0;
	switch(un_qual)
	{ case KCF_SHIFT:
		StrBuf[b_S][0] = 0;
		StrBuf[b_CS][0] = 0;
		StrBuf[b_SA][0] = 0;
		break;

	  case KCF_CONTROL:
		StrBuf[b_C][0] = 0;
		StrBuf[b_CA][0] = 0;
		StrBuf[b_CS][0] = 0;
		break;

	  case KCF_ALT:
		StrBuf[b_A][0]= 0;
		StrBuf[b_SA][0] = 0;
		StrBuf[b_CA][0] = 0;
		break;
	}
	ajustgad(qual);
}
/*----------------------------------------*/
/* on ajuste le codage de la touche aux valeurs demandées */

void ajustkey()
{
  UBYTE strcode[257];	/*buffer où on encode la touche */
  int nb, i;

/*printf("j'ajuste la key %x\n",key_abs);*/
	nb = encodekey(strcode);
	if (invalide) return;

	if (alstrflag[key_abs]) /* si on a alloue un buffer a la touche */
	{   free(buf_p[key_abs].p); /* on le libere */
	    alstrflag[key_abs] = 0;
	}
	buf_p[key_abs].l = 0;
	buf_p[key_abs].p = NULL;

	if (nb)	/* c'est string ou dead */
	{   buf_p[key_abs].p = (UBYTE *)calloc(nb,1);
	    buf_p[key_abs].l = nb;
	    alstrflag[key_abs] = TRUE; /* marque buffer alloue */
	    CopyMem(strcode,buf_p[key_abs].p,(long)nb);
	}
	else
	{   for (i=0; i<4 ;++i) Tkey.trad[i] = strcode[i];
	    if (LoType)
	    {  keymap.km_LoKeyMap[key_rel] = Tkey.longtrad ;	
	    }
	    else
	    {  keymap.km_HiKeyMap[key_rel] = Tkey.longtrad ;	
	    }
	}
	if (LoType)
	{  keymap.km_LoKeyMapTypes[key_rel] = qual;
	   setbitqual(keymap.km_LoCapsable,key_rel,caps);
	   getbitqual(keymap.km_LoRepeatable,key_rel,repet);
	}
	else
	{  keymap.km_HiKeyMapTypes[key_rel] = qual;
	   setbitqual(keymap.km_HiCapsable,key_rel,caps);
	   getbitqual(keymap.km_HiRepeatable,key_rel,repet);
	}
}
/*----------------------------------------*/
/* on initialise le codage initial de la touche */

void initkey()
{
	if (LoType)
	{ qual = keymap.km_LoKeyMapTypes[key_rel] ;
	  strdead = qual & (KCF_DEAD | KCF_STRING);
	  if (strdead)
	      Tkey.str = (UBYTE *)(buf_p[key_abs].p);
	  else
	      Tkey.longtrad = keymap.km_LoKeyMap[key_rel] ;	
	  caps = getbitqual(keymap.km_LoCapsable,key_rel);
	  repet = getbitqual(keymap.km_LoRepeatable,key_rel);
	}
	else
	{ qual = keymap.km_HiKeyMapTypes[key_rel] ;
	  strdead = qual & (KCF_DEAD | KCF_STRING);
	  if (strdead)
	      Tkey.str = (UBYTE *)(buf_p[key_abs].p);
	  else
	      Tkey.longtrad = keymap.km_HiKeyMap[key_rel] ;
	  caps = getbitqual(keymap.km_HiCapsable,key_rel);
	  repet = getbitqual(keymap.km_HiRepeatable,key_rel);
	}
}
/*----------------------------------------*/
/* on retourne le qualifier de la touche k */

getbitqual(table,k)
UBYTE *table;
USHORT k;
{  UBYTE n;
	n = table[k/8];
	return(n & (1 << (k%8)));
}
/*----------------------------------------*/
/* on modifie le qualifier de la touche k */

void setbitqual(table,k,onoff)
UBYTE *table;
USHORT k;
BOOL onoff;
{  UBYTE n;
	n = table[k/8];
	table[k/8] = onoff ? (n | (1 << (k%8))) : (n & (~(1 << (k%8))));
}
/*----------------------------------------*/
/* on affiche le codage de la touche selectée */

void decodekey()
{
  UBYTE *p, *pi;
  USHORT i;

	p = pi = Tkey.str;

	if (!(qual)) decodele(b_N,Tkey.trad,0);
	else if (qual & KCF_DEAD)	/* dead */
	{ decodedead(pi,p,b_N); p += 2;
	  for (i=b_S; i<=b_CSA; i++)
	  { if ((qual & i) == i)
	      decodedead(pi,p,i); p += 2;
	  }
	}
	else if (qual & KCF_STRING)	/* string */
	{ decodestr(pi,p,b_N,KCF_STRING); p += 2;
	  for (i=b_S; i<=b_CSA; i++)
	  { if ((qual & i) == i)
	      decodestr(pi,p,i,KCF_STRING); p += 2;
	  }
	}
	else
	{ decodele(b_N,Tkey.trad,0);
	  if    (qual == KCF_SHIFT) decodele(b_S,Tkey.trad,1);	
	  else if (qual == KCF_ALT) decodele(b_A,Tkey.trad,1);
	  else if (qual == KCF_CONTROL) decodele(b_C,Tkey.trad,1);
	  else if (qual == (KCF_CONTROL+KCF_ALT))
	  {  decodele(b_A,Tkey.trad,1);
	     decodele(b_C,Tkey.trad,2);
	     decodele(b_CA,Tkey.trad,3);
	  }
	  else if (qual == (KCF_CONTROL+KCF_SHIFT))
	  {  decodele(b_S,Tkey.trad,1);
	     decodele(b_C,Tkey.trad,2);
	     decodele(b_CS,Tkey.trad,3);
	  }
	  else if ((qual & (KCF_SHIFT+KCF_ALT)) == (KCF_SHIFT+KCF_ALT))
	  {  decodele(b_S,Tkey.trad,1);
	     decodele(b_A,Tkey.trad,2);
	     decodele(b_SA,Tkey.trad,3);
	  }
	  if (qual == KC_VANILLA)
	  {  decodele(b_C,Tkey.trad,4);
	     decodele(b_CS,Tkey.trad,5);
	  }
	}
}
/*-------------------------------------------*/
/* on decode le contenu de la touche pour le qualifier 'cod' */

void decodele(cod,k,n)
UBYTE *k;
int cod,n;
{
   UBYTE b, *p;

	p = StrBuf[cod];
	b = k[3-n%4];
	if (n==7) b = *k;
	else if (n>3) b &= 0x9f;
	if (b & 0x60) {*p++ = '\''; *p++ = b; *p++ = '\''; *p = '\0';}
	else sprintf(p,"%02x",b);
}
/*-------------------------------------------*/
/* on decode le string de la touche pour le qualifier 'cod' pour une
 * chaine ou une dead(able) key (flag dans diag)
 */

void decodestr(deb,k,cod,diac)
UBYTE *deb, *k;
int cod;
ULONG diac;
{
  UBYTE *p, *s, n;
  char flgaff = '\0';
  USHORT i;

	s = StrBuf[cod];
	n = *k;
	p = deb + *(k+1);

	for (i=0; i<n; i++, p++)
	{ if (*p & 0x60) /* affichable */
	  { if (!(flgaff)) /* pas dans un string */
	    { if (*p != '"' && *p != '\'' ) /* si 1er car n'est pas " ou ' */
	        *s++ = flgaff = '\'';	    /* on met ' */
	      else	  
	        *s++ = flgaff = *p ^ 0x05;  /* sinon l'autre */
	    }
	    else if (*p == '"' || *p == '\'' )
	    { *s++ = flgaff; *s++ = ','; flgaff = *p ^ 0x05; *s++ = flgaff;
	    }
	    *s++ = *p;
	  }
	  else
	  { if (flgaff)
	    { *s++ = flgaff; *s++ = ',';
	      flgaff = '\0';
	    }
	    if (*p == 0x9b) { strcpy(s,"<CSI>,"); s += 6;}
	    else { sprintf(s,"%02x",*p); s += 2; *s++ = ',';}
	  }
	}

	if (flgaff) *s++ = flgaff;
	else --s;

	if (diac == KCF_DEAD)
	{ *s++ = ','; *s++ = '(';
	  for (i=0; i<5; i++) *s++ = *p++;
	  *s++ = ')';
	}
	*s = '\0';
}
/*-------------------------------------------*/
/* on decode une dead(able) key */

void decodedead(deb,p,cod)
UBYTE *deb, *p;
int cod;
{
	if (*p == 0) decodele(cod,++p,7);
	else if (*p == DPF_MOD) decodestr(deb,p,cod,KCF_DEAD);
	else if (*p == DPF_DEAD) decodeacc(deb,p,cod);
}
/*-------------------------------------------*/
/* on décode les accents des 'dead key' */

void decodeacc(deb,p,cod)
UBYTE *deb, *p;
int cod;
{
   UBYTE *s;
   static UBYTE accent[] = {0xb4, 0x60, 0x5e, 0x7e, 0xa8};

	s = StrBuf[cod];
	*s++ = '(';
	*s++ = accent[(*(p+1) & 7)-1];
	*s++ = ')'; *s = '\0';
}

/*----------------------------------------*/
/* on encode la touche conformément aux souhaits de l'utilisateur */

int encodekey(strcode)
UBYTE *strcode;
{
  UBYTE *pstr, *p;
  USHORT i;
  short n;
  UBYTE vanille;

	invalide = FAUX; /* a priori pas d'erreur */
	for (i = 0; i<256 ; ++i) strcode[i] = 0;
	pstr = strcode;
	vanille = qual & KC_VANILLA;
	if (!(qual)) encodele(b_N,pstr,0); /* si qual=0 touche Normale */
	else if (strdead = qual & (KCF_DEAD | KCF_STRING))	/* dead */
	{ for (n=1, i=b_S; i<=b_CSA; i++)
	      if ((qual & i) == i) n++;	/* calcule offset */
	  p = pstr + 2*n;
	  { for (i=b_N; i<=b_CSA; i++)
	    { if ((qual & i) == i)
	      encodestr(i,&pstr,&p,strcode);
	    }
	  }
	n = p - strcode;
	}
	else
	{ encodele(b_N,pstr,0);
	  if    (qual == KCF_SHIFT) encodele(b_S,pstr,1);	
	  else if (qual == KCF_ALT) encodele(b_A,pstr,1);
	  else if (qual == KCF_CONTROL) encodele(b_C,pstr,1);
	  else if (qual == (KCF_CONTROL+KCF_ALT))
	  {  encodele(b_A,pstr,1);
	     encodele(b_C,pstr,2);
	     encodele(b_CA,pstr,3);
	  }
	  else if (qual == (KCF_CONTROL+KCF_SHIFT))
	  {  encodele(b_S,pstr,1);
	     encodele(b_C,pstr,2);
	     encodele(b_CS,pstr,3);
	  }
	  else if ((qual & (KCF_SHIFT+KCF_ALT)) == (KCF_SHIFT+KCF_ALT))
	  {  encodele(b_S,pstr,1);
	     encodele(b_A,pstr,2);
	     encodele(b_SA,pstr,3);
	  }
/*	  if (qual == KC_VANILLA)
	  {  encodele(b_C,pstr,4);
	     encodele(b_CS,pstr,5);
	  }
*/
	}

	return (strdead ? n : 0);
}
/*-------------------------------------------*/
/* on encode le string demandé et vérifie sa validité */

void encodestr(cod,plong,ptexte,pdeb)
int cod;
UBYTE **plong,	/* la ou on va mettre la longueur du string */
      **ptexte,	/* la ou on met le texte du string */
      *pdeb;	/* buffer d'encodage */

{
    UBYTE *p, c;
    int nb=0 , off, invacode;
    int tampon;
    
	invacode = -(cod+1);
	p = StrBuf[cod]; /* string a coder */
	off = *ptexte - pdeb;

	if (strdead == KCF_STRING)
	{
	  nb = form(p,*ptexte,'s');
	  *(*plong)++ = nb; *(*plong)++ = off; 
	  *ptexte += nb;
	}
	else	/* dead or deadeable */
	{ if (*p == '(') /* dead */
	  { if (p[2] == ')') /* dead key */
	    { *(*plong)++ = DPF_DEAD;
	      if ((tampon = queldead(p[1])) == ERROR)
	      { invalide = invacode;
		return;
	      }
	      else
	      { *(*plong)++ = tampon;
		return;
	      }
	    }
	    else /* ne doit pas commencer par parenthese */
	    { invalide = invacode;
	      return;
	    }
	  }
	  else if (strlen(p) > 3) /* deadable */
	  { nb=form(p,*ptexte,'d') ; /* le code de reference */
	    *(*plong)++ = DPF_MOD; *(*plong)++ = off; 
	    *ptexte += nb;
	  }
	  else /* caractère normal */
	  { *(*plong)++ = 0; 
	    nb=form(p,*plong,'c'); ++(*plong);
	  }
	}
	if (nb < 0) invalide = invacode;
	return;
}
/*-------------------------------------------*/
/* on recherche le type d'accent demandé */

queldead(c)
UBYTE c;
{
	switch(c)
	{ case 0xB4:
	  case '\'':	return(1);
	  case '`':	return(2);
	  case '^':	return(3);
	  case '~':	return(4);
	  case 0xA8:
	  case '"':	return(5);
	  default:	return(ERROR);
	}
}
/*-------------------------------------------*/
/* on encode sur 4 bytes les codes demandés
 * on met en k le code traduit demande pour cod avec decalage n 
 * si n > 3 control (shift) pour vanilla (n'est plus utilisé)
 */  
void encodele(cod,k,n)
UBYTE *k;
int cod,n;
{
   UBYTE b, *p;
   int nb, invacode;

	invacode = -(cod+1);
	p = StrBuf[cod];
	if ((nb = form(p,&b,'c')) < 0) {invalide = invacode; return;}
/*	if (n>3) b &= 0x9f;
	k[3-n%4] = b;
*/
	k[3-n] = b;
	return;
}
/*-------------------------------------------*/
/* deformatte string s en d avec specifs f */
/* 'c' copie le car 'x' ou dont le code ascii hexa est donné 
 * 'd' copie le car et les 5 dead-codes suivants entre () ')'
 * 'a' parse un string de la forme  41,<CSI>,'m toto',0D,0A
 */
form(s,d,f)
UBYTE *s, *d;
char f;
{
    char strin = '\0';
    int b=0;
    UBYTE *memd;
    short i;

	memd = d;
	switch(f)
	{ case 'c':
	    if (*s == '\'')
	    { *d++ = *++s; ++s;
	      if (*s++ != '\'') return ERROR;
	    }
	    else
	    { b = axtoi(&s);
	      if (b < 256) *d++ = b;
	      else return ERROR;
	    }
	    while (*s == ' ') ++s; /* des blancs sont authorises a la fin */
	    if (*s) return ERROR;  /* mais rien d'autre */
	    break;

	  case 'd' :
	    if (*s == '\'')
	    { *d++ = *++s; ++s;
	      if (*s++ != '\'') return ERROR;
	    }
	    else
	    { b = axtoi(&s);
	      if (b < 256) *d++ = b;
	      else return ERROR;
	    }
	    while (*s == ' ') ++s;
	    if (*s++ != ',') return ERROR;

	    while (*s == ' ') ++s;
	    if (*s++ == '(')
	    { for (i=0; i<5; i++) *d++ = *s++;
	      if (*s++ != ')') return ERROR;
	    }
	    else return ERROR;
	    while (*s == ' ') ++s; /* des blancs sont authorises a la fin */
	    if (*s) return ERROR;  /* mais rien d'autre */
	    break;

	  case 'a':
	    break;

	  case 's':
	    --s;	/* predecremente pour pouvoir incrementer */
	    while (*(++s)) 
	      switch(*s)
	      { case '\'':
		case '"':
		  if (strin == *s) strin = '\0';
		  else if (!(strin)) strin = *s;
		  else *d++ = *s;
		  break;
	        case ',':
		  if (!(strin)) break;
		  else *d++ = *s;
		  break;
	        default:
		  if (strin)
		    *d++ = *s;
		  else
		  { if (!(strncmp(s,"<CSI>",4)))
		    {	*d++ = 0x9b;
			s += 4;
		    }
		    else
		    { b = axtoi(&s);
		      while (*s == ' ') ++s;
		      if (*s && (*s != ',')) return ERROR;
		      --s;	/* pour tester le 0 au coup suivant */
		      if (b < 256 && b >= 0) *d++ = b;
		      else return (ERROR);
		    }
		  }
		  break;
	      }
	}
	return (strin ? ERROR : d-memd);
}
/*------------------------------------------ */
/* traduit une chaine hexa en un entier */

axtoi(pp)
char **pp;
{
    char *p;
    int i = 0;

	p = *pp;
	while (isspace(*p)) p++;
	while (isxdigit(*p))
	{ i = i * 16 +(isdigit(*p) ? *p - '0' : (*p & 0x5f) - 55);
	  p++;
	}
	*pp = p;
	return i;
}
/*------------------------------------------ */
/* gère la demande des noms de fichier et de table */

quel_noms()
{
    UBYTE *p;
    int l;

	question.IText =(UBYTE *)BlancLigne;
	PrintIText(wRPort,&question,0L,0L);

      switch(etape)
      { case NOM_DU_FICHIER:
		OffGadget(&SaveGad,window,0L);
		cleargadgets();
 		question.IText =(UBYTE *)"Nom du fichier à sauver ?";
		PrintIText(wRPort,&question,0L,0L);
		if (p=index(nom,'.'))
		  l = p-nom;
		else
		  l = strlen(nom);

		strncpy(NomStrBuf,nom,l); NomStrBuf[l]='\0';
		strcat(NomStrBuf,".map");
		Nom_strinfo.BufferPos = l+4;
		AddGadget(window,&NomGad,-1L);
		RefreshGadgets(&NomGad,window,0L);
		ActivateGadget(&NomGad,window,0L);
		break;

	case NOM_DE_LA_TABLE:
		RemoveGadget(window,&NomGad);
		if (*NomStrBuf == 0) goto inval;

		strcpy(nom_fich,NomStrBuf);
 		question.IText =(UBYTE *)"Nom de la table de clavier ?";
		PrintIText(wRPort,&question,0L,0L);
		if (p=index(NomStrBuf,'.'))
		{ l = p-NomStrBuf;
		  *p = '\0';
		}
		else
		  l = strlen(NomStrBuf);

		Nom_strinfo.BufferPos = l;
		AddGadget(window,&NomGad,-1L);
		RefreshGadgets(&NomGad,window,0L);
		ActivateGadget(&NomGad,window,0L);
		break;

	case ECRITURE:
		RemoveGadget(window,&NomGad);
		if (*NomStrBuf == 0)
	        { question.IText =(UBYTE *)"Nom INVALIDE,";
		  goto inval;
		}

		if (ecr_table(nom_fich,NomStrBuf))
	        { question.IText =(UBYTE *)"Pb d'écriture,";
		  goto inval;
		}
		modifie = FALSE;
		etape = FINI;
		break;
	}
	return;

inval:
	PrintIText(wRPort,&question,100L,100L);
	question.IText =(UBYTE *)"le fichier N'est PAS sauvé";
	PrintIText(wRPort,&question,220L,100L);
	etape = MAL_FINI;
	return;
}

