/* Merged parser stuff for keyboard plugin
 */

%{

	/* for unicode keyboard plugin */
static void keyb_mod(int wich, t_keysym keynum, int unicode);
static void dump_keytable_part(FILE *f, t_keysym *map, int size);
void dump_keytable(FILE *f, struct keytable_entry *kt);

%}
	/* special bison declaration */
%token <i_value> UNICODE
%token SHIFT_ALT_MAP CTRL_MAP CTRL_ALT_MAP

%%


keyboard_mod	: CTRL_MAP expression '=' { keyb_mod('C', $2, 0); } keyboard_modvals
		| SHIFT_ALT_MAP expression '=' { keyb_mod('a', $2, 0); } keyboard_modvals
		| CTRL_ALT_MAP expression '=' { keyb_mod('c', $2, 0); } keyboard_modvals
		;

keyboard_modval : UNICODE { keyb_mod(0, $1, 1); }
		| DGRAVE { keyb_mod(0, KEY_DEAD_GRAVE, 1); }
		| DACUTE { keyb_mod(0, KEY_DEAD_ACUTE, 1); }
		| DCIRCUM { keyb_mod(0, KEY_DEAD_CIRCUMFLEX, 1); }
		| DTILDE { keyb_mod(0, KEY_DEAD_TILDE, 1); }
		| DBREVE { keyb_mod(0, KEY_DEAD_BREVE, 1); }
		| DABOVED { keyb_mod(0, KEY_DEAD_ABOVEDOT, 1); }
		| DDIARES { keyb_mod(0, KEY_DEAD_DIAERESIS, 1); }
		| DABOVER { keyb_mod(0, KEY_DEAD_ABOVERING, 1); }
		| DDACUTE { keyb_mod(0, KEY_DEAD_DOUBLEACUTE, 1); }
		| DCEDILLA { keyb_mod(0, KEY_DEAD_CEDILLA, 1); }
		| DIOTA { keyb_mod(0, KEY_VOID, 1); } /* no dead iotas exist */
		| DOGONEK { keyb_mod(0,KEY_DEAD_OGONEK, 1); }
		| DCARON { keyb_mod(0, KEY_DEAD_CARON, 1); }
		;
%%

/* for keyboard plugin */



static void keyb_mod(int wich, t_keysym keynum, int unicode)
{
	static t_keysym *table = 0;
	static int count = 0;
	
	if (wich == ' ') {
		switch (keynum & 0xFF00) {
		case 0x000: wich = ' '; break;
		case 0x100: wich = 'S'; break;
		case 0x200: wich = 'A'; break;
		case 0x300: wich = 'N'; break;
		case 0x400: wich = 'C'; break;
		case 0x500: wich = 'a'; break;
		case 0x600: wich = 'c'; break;
		default: 
			/* It's a bad value ditch it */
			wich ='X'; table = 0; count = 0; break;
		}
		keynum &= 0xFF;
	}

	switch (wich) {
	case ' ': table = config.keytable->key_map;
		count=config.keytable->sizemap;
		break;
	case 'S': table = config.keytable->shift_map;
		count=config.keytable->sizemap;
		break;
	case 'A': table = config.keytable->alt_map;
		count=config.keytable->sizemap;
		break;
	case 'C': table = config.keytable->ctrl_map;
		count=config.keytable->sizemap;
		break;
	case 'a': table = config.keytable->shift_alt_map;
		count=config.keytable->sizemap;
		break;
	case 'c': table = config.keytable->ctrl_alt_map;
		count=config.keytable->sizemap;
		break;
	case 'N': table = config.keytable->num_table;
		count=config.keytable->sizepad;
		break;
	}


	if (!table || (count == 0) || (keynum >= count)) {
		count = 0;
		table = 0;
		return;
	}
	if (wich != 0) {
		table += keynum;
		count -= keynum;
		return;
	}
	if (!unicode) {
		if (keynum == 0) {
			keynum = KEY_VOID;
		} else {
			keynum = keynum + 0xEF00;
		}
	}
	if (count > 0) {
		*table++ = keynum;
		count--;
	}
}


static char *get_key_name(t_keysym key)
{
	struct key_names {
		t_keysym key;
		char *name;
	};
	static struct key_names names[] =
	{
		{ KEY_DEAD_GRAVE,	"dgrave"},
		{ KEY_DEAD_ACUTE,	"dacute"},
		{ KEY_DEAD_CIRCUMFLEX,	"dcircum"},
		{ KEY_DEAD_TILDE,	"dtilde"},
		{ KEY_DEAD_BREVE,	"dbreve"},
		{ KEY_DEAD_ABOVEDOT,	"daboved"},
		{ KEY_DEAD_DIAERESIS,	"ddiares"},
		{ KEY_DEAD_ABOVERING,	"dabover"},
		{ KEY_DEAD_DOUBLEACUTE,	"ddacute"},
		{ KEY_DEAD_CEDILLA,	"dcedilla"},
		{ KEY_DEAD_OGONEK,	"dogonek"},
		{ KEY_DEAD_CARON,	"dcaron"},
	};
	int i;
	for(i = 0; i < sizeof(names)/sizeof(names[0]); i++) {
		if (names[i].key == key) {
			return names[i].name;
		}
	}
	return 0;
}

static void dump_keytable_part(FILE *f, t_keysym *map, int size)
{
  int i, in_string=0;
  t_keysym c;
  unsigned char *cc, comma=' ', buf[16];

  /* Note: This code assumes every font is a superset of ascii */
  if (!map) {
	  return;
  }
  size--;
  for (i=0; i<=size; i++) {
    c = map[i];
    if (!(i & 15)) fprintf(f,"    ");
    cc = get_key_name(c);
    if (!cc && (c < 128) && isprint(c) && !strchr("\\\"\'`", c)) {
      if (in_string) fputc(c,f);
      else {
        fprintf(f, "%c\"%c", comma, c);
        in_string = 1;
      }
    }
    else {
      if (!cc) {
	if (((c > 0) && (c < 128)) || ((c >= 0xEF00) && (c <= 0xEFFF))) {
	  sprintf(buf, "%d", c & 0xFF);
	} else if (c == KEY_VOID) {
	  strcpy(buf, "0");
	} else {
	  sprintf(buf, "\\u%04x", c);
	}
	cc = buf;
      }
      if (!in_string) fprintf(f, "%c%s", comma, cc);
      else {
        fprintf(f, "\",%s", cc);
        in_string = 0;
      }
    }
    if ((i & 15) == 15) {
      if (in_string) fputc('"', f);
      if (i < size) fputc(',', f);
      fputc('\n', f);
      in_string = 0;
      comma = ' ';
    }
    else comma = ',';
  }
  if (in_string) fputc('"', f);
  fputc('\n', f);
}


void dump_keytable(FILE *f, struct keytable_entry *kt)
{
    fprintf(f, "keytable %s {\n", kt->name);
    fprintf(f, "  0=\n");
    dump_keytable_part(f, kt->key_map, kt->sizemap);
    fprintf(f, "  shift 0=\n");
    dump_keytable_part(f, kt->shift_map, kt->sizemap);
    fprintf(f, "  alt 0=\n");
    dump_keytable_part(f, kt->alt_map, kt->sizemap);
    fprintf(f, "  numpad 0=\n");
    dump_keytable_part(f, kt->num_table, kt->sizepad-1);
    fprintf(f, "  ctrl 0=\n");
    dump_keytable_part(f, kt->ctrl_map, kt->sizemap);
    fprintf(f, "  shift-alt 0=\n");
    dump_keytable_part(f, kt->shift_alt_map, kt->sizemap);
    fprintf(f, "  ctrl-alt 0=\n");
    dump_keytable_part(f, kt->ctrl_alt_map, kt->sizemap);
    fprintf(f, "}\n\n\n");
}


