code:
#ifndef charmaps_h
#define charmaps_h

void create_unicode_table();

void set_charmap(const Arg *a);

#define UNITABLE 0x2600

// assignments unicode->codepage
unsigned char uni_to_cp[UNITABLE];

// mappings of the codetables to unicode
// enable or disable them in config.in
// only used tables will be compiled into the binary
// Other codepages can be found e.g. at
// https://www.haible.de/bruno/charsets/conversion-tables/
// Currently, only the chars 0x80 - 0xff are mapped.
// This could be changed with the function convert in charmaps.c,
// and the macros "ISCONTROL" in termdraw would eventually
// need to changed (e.g. look for the current charmap, and return accordingly)

// CP1250 is nearly the same encoding, as the first page
// of unicode.
// Therefore using this encoding could work in many cases, without
// having to change configurations.
// At least with german umlauts, there wasn't any trouble anymore.
//
// CP437 has those box drawing characters, used
// by old tui interfaces.
//

// Another personal chartable.
// I name this cpalpha,
// since I guess I'm going to do further changes.
// It has two advantages,
// German Umlauts are at the places of CP850,
// boxdrawing characters and some other chars there of cp437.
// (marked below)
// I added further quotation marks, Euro sign, logical characters, long vocals,..
//
// I decided to put greek into it's own chartable,
// which is selected by textattributes.
// The conversion uses the betacode,
// so greek text will be displayed "correct" also in other tools.
// About hyphens and diacrytics I'm uncertain yet,
// but this could also be done by latex.

// dehnungs vokale
// spitze klammern

static const unsigned short cpe4002a[] = {
	//  euro ,   ue,    e acc,   a gr ,  ae   , a hyph, born  , death
/*80*/ 0x20ac,   0xfc,   0xe9,   0xe2,   0xe4,   0xe0, 0x2217, 0x2020,
       //                                          Aea, acc (quote)
       0x2200,0x2208,0x2209,0x2203,0x2204,0x27e8, 0xc4,0x2019,
       // Dbl quot low,up, single low,up, oe , double !,  ??,  !?
/*90*/ 0x201e, 0x201c, 0x201a, 0x2018,  0xf6,  0x203c, 0x2047, 0x2049,
	 // acc,    Oe,    Ue,    Cent,    Pound, Yen,   acc, F
       0x201d,   0xd6,   0xdc,   0xa2,   0xa3,   0xa5, 0xb4,  0x192,
	// accent a,i,o,u ,                  n N ,         Durchscbnitt, Paragr
/*A0*/   0xe1,   0xed,   0xf3,   0xfa,   0x2227,   0x2228, 0xd8  ,0xa7,
 // ques down, ungleich, not,
	      0xbf, 0x2260,   0xac,   0xbd,   0xbc,   0xb6,   0xab,   0xbb,

	// box drawing. same as cp437
/*B0*/ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
       0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
       0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
       0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
       0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
       0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
	  // math, cp437
	  // alpha, beta(sz), gamma(!small),
/*E0*/  0x3b1,   0xdf,  0x3b3,  0x3c0,  0x3a3,  0x3c3,   0xb5,  0x3c4,
        0x3a6,  0x398,  0x3a9,  0x3b4, 0x221e,  0x3c6,  0x3b5, 0x2229,
         //                                       *, div, circa,
/*F0*/ 0x2261,   0xb1, 0x2265, 0x2264, 0x222b, 0xd7,   0xf7, 0x2248,

	//  degree,  dbl _,  dot,  radix,   exp(n), exp(2), overline, big delta
         0xb0, 0x2017, 0x2022, 0x221a, 0x207f,   0xb2, 0xaf, 0x2206,  // 0x95,
	//0x27f5, 0x2192, 0x27f6, 0x27f7, 0x27fa, 0x27ea, 0x27e8, 0x27e9, // tmp
	//0x2227, 0x2228, 0x2229, 0x222a (vereinigt), 0x22c2, 0x22c3, 0x22c6, 0x229b, // tmp
};

// A personal codepage. (Using Exxxx as number according to the rfc)
// This is a mix of cp 437 (box drawing chars), German Umlauts and sz,
// greek (greek alphabet), and several logical and mathematical
// operators and signs.
// (Need those for academical writings)
static const unsigned short cpe4000[] = {
	/*euro �, �, �, �,ae �,oe �,ue �,sz */
	0x20ac, 0x00c4, 0x00d6, 0x00dc, 0x00e4, 0x00f6, 0x00fc, 0x00df,
	//+-,    div  , Radix ,  circa, not equ,Paragr., Grad,  Dbl Quot.low,
	0x00b1, 0x00f7, 0x0221, 0x2248, 0x2260, 0x00a7, 0x00b0, 0x0201e,
// Dbl Quote up, single low, up, long a,e,i,o,u
	0x0201d, 0x201a, 0x219, 0x0100, 0x0112, 0x014c ,0x012a, 0x016a,
   //Dehn: a,e,i,o,u                      Double !, ??, !?
	0x0101, 0x0113, 0x012b, 0x014d, 0x016b, 0x203c, 0x2047, 0x2049,
	// Greek Capitals
	0x0390/*xx*/, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
	0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
	0x03a0, 0x03a1, 0xfffd, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7,
	0x03a8, 0x03a9, /*lig*/ 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af,
	// box drawing. same as cp437
	0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
	0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
	0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
	0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
	// greek small letters
	0x00e0/*xx*/,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
	0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
	0x00f0,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,
	0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x00a0,
};

static const unsigned short cp437[] = {
// 80
	  0xc7,  0xfc,  0xe9,  0xe2,  0xe4,  0xe0,  0xe5,  0xe7,
	  0xea,  0xeb,  0xe8,  0xef,  0xee,  0xec,  0xc4,  0xc5,
// 90
	  0xc9,  0xe6,  0xc6,  0xf4,  0xf6,  0xf2,  0xfb,  0xf9,
	  0xff,  0xd6,  0xdc,  0xa2,  0xa3,  0xa5,0x20a7, 0x192,
// A0
	  0xe1,  0xed,  0xf3,  0xfa,  0xf1,  0xd1,  0xaa,  0xba,
	  0xbf,0x2310,  0xac,  0xbd,  0xbc,  0xa1,  0xab,  0xbb,
// B0
	0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, // box drawing
	0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
// C0
	0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
	0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
// D0
	0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
	0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, // end box drawing
// E0
	 0x3b1,  0xdf, 0x393, 0x3c0, 0x3a3, 0x3c3,  0xb5, 0x3c4,
	 0x3a6, 0x398, 0x3a9, 0x3b4,0x221e, 0x3c6, 0x3b5,0x2229,
// F0
	0x2261,  0xb1,0x2265,0x2264,0x2320,0x2321,  0xf7,0x2248,
	  0xb0,0x2219,  0xb7,0x221a,0x207f,  0xb2,0x25a0,  0xa0,
};

static const unsigned short cp850[] = {
// 80
	  0xc7,  0xfc,  0xe9,  0xe2,  0xe4,  0xe0,  0xe5,  0xe7,
	  0xea,  0xeb,  0xe8,  0xef,  0xee,  0xec,  0xc4,  0xc5,
// 90
	  0xc9,  0xe6,  0xc6,  0xf4,  0xf6,  0xf2,  0xfb,  0xf9,
	  0xff,  0xd6,  0xdc,  0xf8,  0xa3,  0xd8,  0xd7, 0x192,
// A0
	  0xe1,  0xed,  0xf3,  0xfa,  0xf1,  0xd1,  0xaa,  0xba,
	  0xbf,  0xae,  0xac,  0xbd,  0xbc,  0xa1,  0xab,  0xbb,
// B0
	0x2591,0x2592,0x2593,0x2502,0x2524,  0xc1,  0xc2,  0xc0,
	  0xa9,0x2563,0x2551,0x2557,0x255d,  0xa2,  0xa5,0x2510,
// C0
	0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,  0xe3,  0xc3,
	0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,  0xa4,
// D0
	  0xf0,  0xd0,  0xca,  0xcb,  0xc8, 0x131,  0xcd,  0xce,
	  0xcf,0x2518,0x250c,0x2588,0x2584,  0xa6,  0xcc,0x2580,
// E0
	  0xd3,  0xdf,  0xd4,  0xd2,  0xf5,  0xd5,  0xb5,  0xfe,
	  0xde,  0xda,  0xdb,  0xd9,  0xfd,  0xdd,  0xaf,  0xb4,
// F0
	  0xad,  0xb1,0x2017,  0xbe,  0xb6,  0xa7,  0xf7,  0xb8,
	  0xb0,  0xa8,  0xb7,  0xb9,  0xb3,  0xb2,0x25a0,  0xa0,
};

// this is ansi, dec-mcs, the first page of unicode, and windows 1252
static const unsigned short cp1252[] = {
// 80
	0x20ac,0xfffd,0x201a, 0x192,0x201e,0x2026,0x2020,0x2021,
	 0x2c6,0x2030, 0x160,0x2039, 0x152,0xfffd, 0x17d,0xfffd,
// 90
	0xfffd,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
	 0x2dc,0x2122, 0x161,0x203a, 0x153,0xfffd, 0x17e, 0x178,
// A0 - FF = 1 page of unicode
	  0xa0,  0xa1,  0xa2,  0xa3,  0xa4,  0xa5,  0xa6,  0xa7,
	  0xa8,  0xa9,  0xaa,  0xab,  0xac,  0xad,  0xae,  0xaf,
	  0xb0,  0xb1,  0xb2,  0xb3,  0xb4,  0xb5,  0xb6,  0xb7,
	  0xb8,  0xb9,  0xba,  0xbb,  0xbc,  0xbd,  0xbe,  0xbf,
	  0xc0,  0xc1,  0xc2,  0xc3,  0xc4,  0xc5,  0xc6,  0xc7,
	  0xc8,  0xc9,  0xca,  0xcb,  0xcc,  0xcd,  0xce,  0xcf,
	  0xd0,  0xd1,  0xd2,  0xd3,  0xd4,  0xd5,  0xd6,  0xd7,
	  0xd8,  0xd9,  0xda,  0xdb,  0xdc,  0xdd,  0xde,  0xdf,
	  0xe0,  0xe1,  0xe2,  0xe3,  0xe4,  0xe5,  0xe6,  0xe7,
	  0xe8,  0xe9,  0xea,  0xeb,  0xec,  0xed,  0xee,  0xef,
	  0xf0,  0xf1,  0xf2,  0xf3,  0xf4,  0xf5,  0xf6,  0xf7,
	  0xf8,  0xf9,  0xfa,  0xfb,  0xfc,  0xfd,  0xfe,  0xff,
};

// I don't know, if this is useful at all.
static const unsigned short iso8859_15[] = {
  0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
  0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
  0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
  0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
  //
  0xa0, 0xa1, 0xa2, 0xa3, 0x00, 0xa5, 0x00, 0xa7, /* 0xa0-0xa7 */
  0x00, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
  0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
  0x00, 0xb9, 0xba, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0xb8-0xbf */
//
	  0xc0,  0xc1,  0xc2,  0xc3,  0xc4,  0xc5,  0xc6,  0xc7,
	  0xc8,  0xc9,  0xca,  0xcb,  0xcc,  0xcd,  0xce,  0xcf,
	  0xd0,  0xd1,  0xd2,  0xd3,  0xd4,  0xd5,  0xd6,  0xd7,
	  0xd8,  0xd9,  0xda,  0xdb,  0xdc,  0xdd,  0xde,  0xdf,
	  0xe0,  0xe1,  0xe2,  0xe3,  0xe4,  0xe5,  0xe6,  0xe7,
	  0xe8,  0xe9,  0xea,  0xeb,  0xec,  0xed,  0xee,  0xef,
	  0xf0,  0xf1,  0xf2,  0xf3,  0xf4,  0xf5,  0xf6,  0xf7,
	  0xf8,  0xf9,  0xfa,  0xfb,  0xfc,  0xfd,  0xfe,  0xff,
};

static const unsigned short cp1251[] = {
	0x0402, 0x0403, 0x201a, 0x0453, 0x201e, 0x2026, 0x2020, 0x2021,
	0x20ac, 0x2030, 0x0409, 0x2039, 0x040a, 0x040c, 0x040b, 0x040f,
	0x0452, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
	0xfffd, 0x2122, 0x0459, 0x203a, 0x045a, 0x045c, 0x045b, 0x045f,
	0x00a0, 0x040e, 0x045e, 0x0408, 0x00a4, 0x0490, 0x00a6, 0x00a7,
	0x0401, 0x00a9, 0x0404, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0407,
	0x00b0, 0x00b1, 0x0406, 0x0456, 0x0491, 0x00b5, 0x00b6, 0x00b7,
	0x0451, 0x2116, 0x0454, 0x00bb, 0x0458, 0x0405, 0x0455, 0x0457,
	0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
	0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
	0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
	0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
	0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
	0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
	0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
	0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
};

static const unsigned short cp1250[] = {
	0x20ac,0xfffd,0x201a,0xfffd,0x201e,0x2026,0x2020,0x2021,
	0xfffd,0x2030, 0x160,0x2039, 0x15a, 0x164, 0x17d, 0x179,
	0xfffd,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
	0xfffd,0x2122, 0x161,0x203a, 0x15b, 0x165, 0x17e, 0x17a,
	  0xa0, 0x2c7, 0x2d8, 0x141,  0xa4, 0x104,  0xa6,  0xa7,
	  0xa8,  0xa9, 0x15e,  0xab,  0xac,  0xad,  0xae, 0x17b,
	  0xb0,  0xb1, 0x2db, 0x142,  0xb4,  0xb5,  0xb6,  0xb7,
	  0xb8, 0x105, 0x15f,  0xbb, 0x13d, 0x2dd, 0x13e, 0x17c,
	 0x154,  0xc1,  0xc2, 0x102,  0xc4, 0x139, 0x106,  0xc7,
	 0x10c,  0xc9, 0x118,  0xcb, 0x11a,  0xcd,  0xce, 0x10e,
	 0x110, 0x143, 0x147,  0xd3,  0xd4, 0x150,  0xd6,  0xd7,
	 0x158, 0x16e,  0xda, 0x170,  0xdc,  0xdd, 0x162,  0xdf,
	 0x155,  0xe1,  0xe2, 0x103,  0xe4, 0x13a, 0x107,  0xe7,
	 0x10d,  0xe9, 0x119,  0xeb, 0x11b,  0xed,  0xee, 0x10f,
	 0x111, 0x144, 0x148,  0xf3,  0xf4, 0x151,  0xf6,  0xf7,
	 0x159, 0x16f,  0xfa, 0x171,  0xfc,  0xfd, 0x163, 0x2d9,
};

static const unsigned short cp1253[] = {
	0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
	0xfffd, 0x2030, 0xfffd, 0x2039, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
	0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
	0xfffd, 0x2122, 0xfffd, 0x203a, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
	0x00a0, 0x0385, 0x0386, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
	0x00a8, 0x00a9, 0xfffd, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x2015,
	0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x0384, 0x00b5, 0x00b6, 0x00b7,
	0x0388, 0x0389, 0x038a, 0x00bb, 0x038c, 0x00bd, 0x038e, 0x038f,

	0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
	0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
	0x03a0, 0x03a1, 0xfffd, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7,
	0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af,

	0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
	0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
	0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7,
	0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0xfffd,
};

static const unsigned short cp1255[] = {
	0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
	0x02c6, 0x2030, 0xfffd, 0x2039, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
	0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
	0x02dc, 0x2122, 0xfffd, 0x203a, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
	0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x20aa, 0x00a5, 0x00a6, 0x00a7,
	0x00a8, 0x00a9, 0x00d7, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
	0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
	0x00b8, 0x00b9, 0x00f7, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
	0x05b0, 0x05b1, 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7,
	0x05b8, 0x05b9, 0x05ba, 0x05bb, 0x05bc, 0x05bd, 0x05be, 0x05bf,
	0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05f0, 0x05f1, 0x05f2, 0x05f3,
	0x05f4, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd,
	0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7,
	0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df,
	0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7,
	0x05e8, 0x05e9, 0x05ea, 0xfffd, 0xfffd, 0x200e, 0x200f, 0xfffd,
};

static const unsigned short cp1256[] = {
	0x20ac, 0x067e, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
	0x02c6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,
	0x06af, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
	0x06a9, 0x2122, 0x0691, 0x203a, 0x0153, 0x200c, 0x200d, 0x06ba,
	0x00a0, 0x060c, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
	0x00a8, 0x00a9, 0x06be, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
	0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
	0x00b8, 0x00b9, 0x061b, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x061f,
	0x06c1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
	0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f,
	0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00d7,
	0x0637, 0x0638, 0x0639, 0x063a, 0x0640, 0x0641, 0x0642, 0x0643,
	0x00e0, 0x0644, 0x00e2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00e7,
	0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x0649, 0x064a, 0x00ee, 0x00ef,
	0x064b, 0x064c, 0x064d, 0x064e, 0x00f4, 0x064f, 0x0650, 0x00f7,
	0x0651, 0x00f9, 0x0652, 0x00fb, 0x00fc, 0x200e, 0x200f, 0x06d2,
};

static const unsigned short cp1257[] = {
	0x20ac, 0xfffd, 0x201a, 0xfffd, 0x201e, 0x2026, 0x2020, 0x2021,
	0xfffd, 0x2030, 0xfffd, 0x2039, 0xfffd, 0x00a8, 0x02c7, 0x00b8,
	0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
	0xfffd, 0x2122, 0xfffd, 0x203a, 0xfffd, 0x00af, 0x02db, 0xfffd,
	0x00a0, 0xfffd, 0x00a2, 0x00a3, 0x00a4, 0xfffd, 0x00a6, 0x00a7,
	0x00d8, 0x00a9, 0x0156, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00c6,
	0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
	0x00f8, 0x00b9, 0x0157, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00e6,
	0x0104, 0x012e, 0x0100, 0x0106, 0x00c4, 0x00c5, 0x0118, 0x0112,
	0x010c, 0x00c9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012a, 0x013b,
	0x0160, 0x0143, 0x0145, 0x00d3, 0x014c, 0x00d5, 0x00d6, 0x00d7,
	0x0172, 0x0141, 0x015a, 0x016a, 0x00dc, 0x017b, 0x017d, 0x00df,
	0x0105, 0x012f, 0x0101, 0x0107, 0x00e4, 0x00e5, 0x0119, 0x0113,
	0x010d, 0x00e9, 0x017a, 0x0117, 0x0123, 0x0137, 0x012b, 0x013c,
	0x0161, 0x0144, 0x0146, 0x00f3, 0x014d, 0x00f5, 0x00f6, 0x00f7,
	0x0173, 0x0142, 0x015b, 0x016b, 0x00fc, 0x017c, 0x017e, 0x02d9,
};

static const unsigned short cp1258[] = {
	0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
	0x02c6, 0x2030, 0xfffd, 0x2039, 0x0152, 0xfffd, 0xfffd, 0xfffd,
	0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
	0x02dc, 0x2122, 0xfffd, 0x203a, 0x0153, 0xfffd, 0xfffd, 0x0178,
	0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
	0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
	0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
	0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
	0x00c0, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
	0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x0300, 0x00cd, 0x00ce, 0x00cf,
	0x0110, 0x00d1, 0x0309, 0x00d3, 0x00d4, 0x01a0, 0x00d6, 0x00d7,
	0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x01af, 0x0303, 0x00df,
	0x00e0, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
	0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x0301, 0x00ed, 0x00ee, 0x00ef,
	0x0111, 0x00f1, 0x0323, 0x00f3, 0x00f4, 0x01a1, 0x00f6, 0x00f7,
	0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x01b0, 0x20ab, 0x00ff,
};

// mac roman
static const unsigned short macintosh[] = {
  /* 0x80 */
  0x00c4, 0x00c5, 0x00c7, 0x00c9, 0x00d1, 0x00d6, 0x00dc, 0x00e1,
  0x00e0, 0x00e2, 0x00e4, 0x00e3, 0x00e5, 0x00e7, 0x00e9, 0x00e8,
  /* 0x90 */
  0x00ea, 0x00eb, 0x00ed, 0x00ec, 0x00ee, 0x00ef, 0x00f1, 0x00f3,
  0x00f2, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x00f9, 0x00fb, 0x00fc,
  /* 0xa0 */
  0x2020, 0x00b0, 0x00a2, 0x00a3, 0x00a7, 0x2022, 0x00b6, 0x00df,
  0x00ae, 0x00a9, 0x2122, 0x00b4, 0x00a8, 0x2260, 0x00c6, 0x00d8,
  /* 0xb0 */
  0x221e, 0x00b1, 0x2264, 0x2265, 0x00a5, 0x00b5, 0x2202, 0x2211,
  0x220f, 0x03c0, 0x222b, 0x00aa, 0x00ba, 0x2126, 0x00e6, 0x00f8,
  /* 0xc0 */
  0x00bf, 0x00a1, 0x00ac, 0x221a, 0x0192, 0x2248, 0x2206, 0x00ab,
  0x00bb, 0x2026, 0x00a0, 0x00c0, 0x00c3, 0x00d5, 0x0152, 0x0153,
  /* 0xd0 */
  0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x25ca,
  0x00ff, 0x0178, 0x2044, 0x00a4, 0x2039, 0x203a, 0xfb01, 0xfb02,
  /* 0xe0 */
  0x2021, 0x00b7, 0x201a, 0x201e, 0x2030, 0x00c2, 0x00ca, 0x00c1,
  0x00cb, 0x00c8, 0x00cd, 0x00ce, 0x00cf, 0x00cc, 0x00d3, 0x00d4,
  /* 0xf0 */
  0xfffd, 0x00d2, 0x00da, 0x00db, 0x00d9, 0x0131, 0x02c6, 0x02dc,
  0x00af, 0x02d8, 0x02d9, 0x02da, 0x00b8, 0x02dd, 0x02db, 0x02c7,
};

static const unsigned short mac_centraleurope[] = {
	0x00c4, 0x0100, 0x0101, 0x00c9, 0x0104, 0x00d6, 0x00dc, 0x00e1,
	0x0105, 0x010c, 0x00e4, 0x010d, 0x0106, 0x0107, 0x00e9, 0x0179,
	0x017a, 0x010e, 0x00ed, 0x010f, 0x0112, 0x0113, 0x0116, 0x00f3,
	0x0117, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x011a, 0x011b, 0x00fc,
	0x2020, 0x00b0, 0x0118, 0x00a3, 0x00a7, 0x2022, 0x00b6, 0x00df,
	0x00ae, 0x00a9, 0x2122, 0x0119, 0x00a8, 0x2260, 0x0123, 0x012e,
	0x012f, 0x012a, 0x2264, 0x2265, 0x012b, 0x0136, 0x2202, 0x2211,
	0x0142, 0x013b, 0x013c, 0x013d, 0x013e, 0x0139, 0x013a, 0x0145,
	0x0146, 0x0143, 0x00ac, 0x221a, 0x0144, 0x0147, 0x2206, 0x00ab,
	0x00bb, 0x2026, 0x00a0, 0x0148, 0x0150, 0x00d5, 0x0151, 0x014c,
	0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x25ca,
	0x014d, 0x0154, 0x0155, 0x0158, 0x2039, 0x203a, 0x0159, 0x0156,
	0x0157, 0x0160, 0x201a, 0x201e, 0x0161, 0x015a, 0x015b, 0x00c1,
	0x0164, 0x0165, 0x00cd, 0x017d, 0x017e, 0x016a, 0x00d3, 0x00d4,
	0x016b, 0x016e, 0x00da, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173,
	0x00dd, 0x00fd, 0x0137, 0x017b, 0x0141, 0x017c, 0x0122, 0x02c7,
};

static const unsigned short atarist[128] = {
  /* 0x80 */
  0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
  0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
  /* 0x90 */
  0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
  0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x00df, 0x0192,
  /* 0xa0 */
  0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
  0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
  /* 0xb0 */
  0x00e3, 0x00f5, 0x00d8, 0x00f8, 0x0153, 0x0152, 0x00c0, 0x00c3,
  0x00d5, 0x00a8, 0x00b4, 0x2020, 0x00b6, 0x00a9, 0x00ae, 0x2122,
  /* 0xc0 */
  0x0133, 0x0132, 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5,
  0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05db, 0x05dc, 0x05de, 0x05e0,
  /* 0xd0 */
  0x05e1, 0x05e2, 0x05e4, 0x05e6, 0x05e7, 0x05e8, 0x05e9, 0x05ea,
  0x05df, 0x05da, 0x05dd, 0x05e3, 0x05e5, 0x00a7, 0x2227, 0x221e,
  /* 0xe0 */
  0x03b1, 0x03b2, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
  0x03a6, 0x0398, 0x03a9, 0x03b4, 0x222e, 0x03c6, 0x2208, 0x2229,
  /* 0xf0 */
  0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
  0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x00b3, 0x00af,
};

#if 0
static const unsigned short cp1254[] = {
  /* 0x80 */
  0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
  0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0xfffd, 0xfffd, 0xfffd,
  /* 0x90 */
  0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
  0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0xfffd, 0xfffd, 0x0178,
  0x00, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
  0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */
  0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
  0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
  0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
  0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, 0x00, 0xff, /* 0xf8-0xff */
#endif

#endif


code:
// Color related functions
// Default colors are defined in config.h

#include "colors.h"

ushort sixd_to_16bit(int x) { return x == 0 ? 0 : 0x3737 + 0x2828 * x; }

static XftColor cc_rc[COLORCACHESIZE];
// for UTF8: (Truecolor) ulongs, and other code needs changes
static uint cc_mode[COLORCACHESIZE];
static uint cc_p;

// get a cached color, if present
Color* getcachecolor( uint fg, Glyph*g, uint winmode ){

	for ( int a = 0; a<cc_p; a++ ){
		if ( cc_mode[a] == (( (fg<<16) | ( (winmode<<24)&0xff000000) | ( fg==1?g->fg:g->bg) ) |(g->mode<<8))){
		//printf("cachehit: %d  %d  %x\n",fg,a,cc_mode[a]);
		if ( a>0 ){
			//printf("swap: %d\n",a);
			Color tmp;
			memcpy( &tmp, &cc_rc[a], sizeof(Color) );
			memcpy( &cc_rc[a], &cc_rc[a-1], sizeof(Color) );
			memcpy( &cc_rc[a-1], &tmp, sizeof(Color) );
			uint t = cc_mode[a];
			cc_mode[a] = cc_mode[a-1];
			cc_mode[a-1] = t;
			a--;
		}
			return( &cc_rc[a] );
		}
	}
	return(0);
}

// Cache a color, fg: 0=bg, 1=fg, 2=cursor(fg)
// Copies the color, and returns a pointer to the copy
Color* cachecolor( uint fg, Glyph*g, uint winmode, Color *color ){
	Color *ret;
	if ( (ret=getcachecolor(fg,g,winmode)) ){
		//printf("double store\n");
		return( ret );
	}
	if ( cc_p == COLORCACHESIZE-1 ){
		//printf("Free cachecolor\n");
		XftColorFree(xwin.dpy, xwin.vis, xwin.cmap, &cc_rc[cc_p]);
		//cc_rc[cc_p] = cc_rc[0];
	} else cc_p++;

	memmove( &cc_rc[1], &cc_rc[0], sizeof(Color)*(COLORCACHESIZE-1) );
	memmove( &cc_mode[1], &cc_mode[0], sizeof(uint)*(COLORCACHESIZE-1) );
	memcpy( cc_rc, color, sizeof(Color) );
	cc_mode[0] = ( fg<<16 ) | ((winmode<<24)&0xff000000 ) | g->mode<<8 | ( fg==1?g->fg:g->bg);
	//printf("cache: %d  %x\n",fg,cc_mode[cc_p]);
	return(cc_rc);
}

int xloadcolor(int i, const char *name, Color *p_color) {
	XRenderColor color = {.alpha = 0xffff};

	if (!name) {
		if (BETWEEN(i, 16, 255)) {  /* 256 color */
			if (i < 6 * 6 * 6 + 16) { /* same colors as xterm */
				color.red = sixd_to_16bit(((i - 16) / 36) % 6);
				color.green = sixd_to_16bit(((i - 16) / 6) % 6);
				color.blue = sixd_to_16bit(((i - 16) / 1) % 6);
			} else { /* greyscale */
				color.red = 0x0808 + 0x0a0a * (i - (6 * 6 * 6 + 16));
				color.green = color.blue = color.red;
			}
			return XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &color, p_color);
		} else
			name = colorname[i]; // color 0..16
	}
	//printf("color name: %s\n",name);
	if ( name[0] == '#' ){
		# define HX(x) ( x<='9' ? x- 0x30 : x-(0x61+10) )
		//Color
		color.red = HX( name[1] ) * 16 + HX(name[2] );
		color.green = HX( name[3] ) * 16 + HX(name[4] );
		color.blue = HX( name[5] ) * 16 + HX(name[6] );
		return XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &color, p_color);
		# undef HX
	}

	return XftColorAllocName(xwin.dpy, xwin.vis, xwin.cmap, name, p_color);
}

void xloadcolors(void) {
	int i;
	static int loaded;
	Color *cp;

	if (loaded) {
		printf("Loaded!! - colors.c\n");
		return; // dunno. this code drives me crazy
				  // there might be memory leaks
				  // misc24
		for (cp = dc.color_array; cp < &dc.color_array[dc.color_arraylen]; ++cp)
			XftColorFree(xwin.dpy, xwin.vis, xwin.cmap, cp);
	} else {
		dc.color_arraylen = MAX(LEN(colorname), 256);
		dc.color_array = xmalloc(dc.color_arraylen * sizeof(Color));
	}

	for (i = 0; i < dc.color_arraylen; i++)
		if (!xloadcolor(i, NULL, &dc.color_array[i])) {
			if (colorname[i])
				die("could not allocate color '%s'\n", colorname[i]);
			else
				die("could not allocate color %d\n", i);
		}

	// Load gradient tables
	dc.colortable = xmalloc( 4*8*sizeof(Color) );
	Color *p_color = dc.colortable;
	for ( int a = 0; a<4; a++ ){
		for ( int b = 0; b<8; b++ ){
			 if ( !XftColorAllocName(xwin.dpy, xwin.vis, xwin.cmap, colortablenames[b][a], p_color) ){
				 printf( "Cannot load color: %s\n",colortablenames[b][a] );
			 	if ( !XftColorAllocName(xwin.dpy, xwin.vis, xwin.cmap, "gray", p_color) )
				 	die( "Cannot load fallback \"gray\"\n" );
			 }
			 p_color++;
		}
	}

	dc.bgcolors = xmalloc( 16*sizeof(Color) );
	p_color = dc.bgcolors;
	for ( int a = 0; a<16; a++ ){
		if ( !XftColorAllocName(xwin.dpy, xwin.vis, xwin.cmap, bgcolornames[a],p_color) ){
			printf( "Cannot load color: %s\n",bgcolornames[a]);
			if ( !XftColorAllocName(xwin.dpy, xwin.vis, xwin.cmap, "gray", p_color) )
				die( "Cannot load fallback \"gray\"\n" );
		}
		p_color++;
	}

		loaded = 1;
}

int xsetcolorname(int x, const char *name) {
	Color p_color;

	if (!BETWEEN(x, 0, dc.color_arraylen))
		return 1;

	if (!xloadcolor(x, name, &p_color))
		return 1;

	XftColorFree(xwin.dpy, xwin.vis, xwin.cmap, &dc.color_array[x]);
	dc.color_array[x] = p_color;

	return 0;
}

#if 0
// is yet in xdraw.c. somepointer trouble, as to expect.
void getGlyphColor( Glyph *base, Color **pfg, Color **pbg ){
	XRenderColor colfg, colbg;
	Color revfg, revbg, truefg, truebg, *cltmp;
	Color *fg,*bg;

	/* Fallback on color display for attributes not supported by the font */
	if (base->mode & ATTR_ITALIC && base->mode & ATTR_BOLD) {
		if (dc.ibfont.badslant || dc.ibfont.badweight)
			base->fg = defaultattr;
	} else if ((base->mode & ATTR_ITALIC && dc.ifont.badslant) ||
			(base->mode & ATTR_BOLD && dc.bfont.badweight)) {
		base->fg = defaultattr;
	}

	if (IS_TRUECOL(base->fg)) {
		//printf("Truecolor\n");
		colfg.alpha = 0xffff;
		colfg.red = TRUERED(base->fg);
		colfg.green = TRUEGREEN(base->fg);
		colfg.blue = TRUEBLUE(base->fg);
		XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colfg, &truefg);
		fg = &truefg;
	} else {
		fg = &dc.color_array[base->fg];
	}

	if (IS_TRUECOL(base->bg)) {
		colbg.alpha = 0xffff;
		colbg.green = TRUEGREEN(base->bg);
		colbg.red = TRUERED(base->bg);
		colbg.blue = TRUEBLUE(base->bg);
		XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colbg, &truebg);
		bg = &truebg;
	} else {
		bg = &dc.color_array[base->bg];
	}
#define AS(c) colfg.c = fg->color.c
#define ASB(c) colbg.c = bg->color.c
	//AS(red);AS(green);AS(blue);AS(alpha);
	//ASB(red);ASB(green);ASB(blue);ASB(alpha);
#undef AS
#undef ASB

#define boldf 0xfff
	//#define cbold(c) colfg.c = fg->color.c + boldf <= 0xffff ? fg->color.c+boldf : fg->color.c ;
#define cbold(c) colfg.c = ((fg->color.c + fg->color.c/2) | fg->color.c ) & 0xffff
	//#define cbold(c) colfg.c = fg->color.c > 250?  : fg->color.c+ 5;
	//#define cfaint(c) colfg.c = fg->color.c - (fg->color.c/2)
#define cfaint(c) colfg.c = fg->color.c - fg->color.c/2; // prev: - .c/4
																			//
	/* Change basic system colors [0-7] to bright system colors [8-15] */
	if ((base->mode & ATTR_BOLD) == ATTR_BOLD ){
		if ( BETWEEN(base->fg, 0, 7)){
			fg = &dc.color_array[base->fg + 8];
	} else {
	//if ( ( (base->mode & ATTR_BOLD) == ATTR_BOLD ) && !BETWEEN(base->fg,0,15) )  {
		cbold(red); //= fg->color.red * 2;
		cbold(green); //= fg->color.green * 2;
		cbold(blue); //= fg->color.blue +  2;
		colfg.alpha = fg->color.alpha;
		XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colfg, &revfg);
		fg = &revfg;
		}
	}

		// also BOLD|FAINT
	if ( (base->mode & ATTR_FAINT) == ATTR_FAINT ) { //&& !BETWEEN(base->fg,0,15) )  {
		cfaint(red); //= fg->color.red * 2;
		cfaint(green); //= fg->color.green * 2;
		cfaint(blue); //= fg->color.blue +  2;
		colfg.alpha = fg->color.alpha;//2;
		XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colfg, &revfg);
		fg = &revfg;
	}

	if (IS_SET(MODE_REVERSE)) {
		if (fg == &dc.color_array[defaultfg]) {
			fg = &dc.color_array[defaultbg];
		} else {
			//						colfg.blue = ~fg->color.blue;
			//						colfg.alpha = fg->color.alpha;
#define AS(c) colfg.c = ~colfg.c
			AS(red);AS(green);AS(blue);
#undef AS

			XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colfg, &revfg);
			fg = &revfg;
		}

		if ( bg == &dc.color_array[defaultbg]) {
			bg = &dc.color_array[defaultfg];
		} else {
			//					fprintf(stderr,"inv\n");//D
			//colbg.red = ~bg->color.red;
			//colbg.green = ~bg->color.green;
			//colbg.blue = ~bg->color.blue;
			//colbg.alpha = bg->color.alpha;
#define ASB(c) colbg.c = ~bg->color.c
			ASB(red);ASB(green);ASB(blue);
#undef ASB
			XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colbg, &revbg);
			bg = &revbg;
		}
	}

#define CLFA 24000
	// Change colors on focusout
	if ( !(twin.mode & MODE_FOCUSED) ){
		/*colfg.red = fg->color.red / 2;
		  colfg.green = fg->color.green / 4 * 3;
		  colfg.blue = fg->color.blue / 4 * 3;*/
		if ( (fg->color.blue > CLFA) && (fg->color.red < CLFA) && (fg->color.green < CLFA) ){
			colfg.red = fg->color.red +13000;
			colfg.green = fg->color.green +13000;
			colfg.blue = fg->color.blue;
			colfg.alpha = fg->color.alpha;
			XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colfg, &revfg);
			fg = &revfg;
		}
		if ( (bg->color.blue > CLFA) && (bg->color.red < CLFA) && (bg->color.green < CLFA) ){
			colbg.red = bg->color.red +CLFA;
			colbg.green = bg->color.green +CLFA;
			colbg.blue = bg->color.blue;
			colbg.alpha = bg->color.alpha;
			XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colbg, &revbg);
			bg = &revbg;
		}
#if 0
		if ( (fg->color.blue > CLFA) && (fg->color.red < CLFA) ){
			colfg.red = fg->color.red +CLFA;
			colfg.green = fg->color.green;// +CLFA;
			colfg.blue = fg->color.blue;
			colfg.alpha = fg->color.alpha;
			XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colfg, &revfg);
			fg = &revfg;
		}
		if ( (fg->color.blue > CLFA) && (fg->color.green < CLFA) ){
			colfg.red = fg->color.red;// +CLFA;
			colfg.green = fg->color.green +CLFA;
			colfg.blue = fg->color.blue;
			colfg.alpha = fg->color.alpha;
			XftColorAllocValue(xwin.dpy, xwin.vis, xwin.cmap, &colfg, &revfg);
			fg = &revfg;
		}
#endif
	}

	if (base->mode & ATTR_REVERSE) {
		//	fprintf(stderr,"attrinv\n");//D
#if 0
		bg = &dc.color_array[selectionbg];
		if (!ignoreselfg)
			fg = &dc.color_array[selectionfg];
#else
			cltmp = bg;
			bg = fg;
			fg = cltmp;
//#define AS(c) {int tc = colfg.c; colfg.c=colbg.c;colbg.c = tc;}
//					AS(red);AS(green);AS(blue);
//#undef AS
#endif
		//				fg = &revfg;
		//				bg = &revbg;
	}

	if (base->mode & ATTR_BLINK && twin.mode & MODE_BLINK)
		fg = bg;

	if (base->mode & ATTR_INVISIBLE)
		fg = bg;

	*pfg = fg;
	*pbg = bg;
}
#endif

repo_name: misc/slterm

license: mit


code:
#ifndef colors_h
#define colors_h
// color related functions and definitions

// number of colors to cache
#define COLORCACHESIZE 64

#define FOR_RGB(_do) _do(red);_do(green);_do(blue)

#define INVERT_COLOR(_color) _color.red = ~_color.red; _color.green = ~_color.green; _color.blue = ~_color.blue

#ifndef UTF8
#define IS_TRUECOL(x)(0)
#define TRUECOLOR(r,g,b) (0)
#else
#define TRUECOLOR(r, g, b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
#define IS_TRUECOL(x) (1 << 24 & (x))
#endif

#define TRUERED(x) (((x)&0xff0000) >> 8)
#define TRUEGREEN(x) (((x)&0xff00))
#define TRUEBLUE(x) (((x)&0xff) << 8)

#endif


code:
// Main configuration file

#ifndef CONFIG_H
#define CONFIG_H

#ifndef extract_keyref

// Silence syntaxcheckerplugin
#include <X11/XKBlib.h>
#include <X11/Xatom.h>
#include <X11/Xft/Xft.h>
#include <X11/Xlib.h>
#include <X11/Xresource.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>

// Config options

/*
 font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
       and doc/fontconfig.txt

 the default regular font can be overwritten via command line
 e.g.: slterm -f 'Monospace:pixelsize=13:antialias=true'

 To use embedded fonts, set EMBEDFONT to 1 in config.make,
 The attributes below are still used.
 To change the embedded fonts, you need to change the files in src/embed/

*/

// regular font
static char *regular_font = "Liberation Mono:Bold:pixelsize=13:antialias=true:autohint=true";
//static char *font = "Monospace:pixelsize=13:antialias=true:autohint=true";

//if size not set
int default_font_pixelsize = 14;

// if set to 0, the sizes will be determined.
// else these sizes are used, regardless of a given pixelsize
//int fontwidth = 8; // width in pixel, fontspacing is added
int fontwidth = 0; // width in pixel, fontspacing is added
int fontheight = 0; // height in pixel. should be larger than pixelsize
//int fontheight = 15; // height in pixel. should be larger than pixelsize

// more/less font width spacing
// here, with utf8 enabled, -1 looks much better.
int fontspacing = 0;
//int fontspacing = -1;

/* if fonts below are set, they are used, no matter of xresources or command line options
 else, if set to 0, the appropiate weight and slant are added to "regular_font"
 (italic,bold,bold italic) when usexxxfont below is set to 1.
The pixelsize as well as charwidth and height are set according to the regular font,
pixelsize (if unset) defaults to 14.
*/
static char *italic_font = "Liberation Mono:Bold:Italic:pixelsize=13:antialias=true:autohint=true";
static char *bold_font = 0;
static char *bolditalic_font = 0;

// Whether to use another font, for bold/italic/bolditalic
#if 1
int useboldfont = 0;
int useitalicfont = 1;
int usebolditalicfont = 0;
#else
int useboldfont = 1;
int useitalicfont = 1;
int usebolditalicfont = 1;
#endif

/* Kerning / character bounding-box multipliers */
//static float cwscale = 1.0;
//static float chscale = 1.0;

// The terminal's borderwidth in percent of a char's width
// if set to 0, borderpx is not changed
int borderperc = 40;

// the borderwidth in pixel. borderpc is used to calculate borderpx, if set.
int borderpx = 0;

/*
 What program is execed by slterm depends of these precedence rules:
 1: program passed with -e
 2: utmp option
 3: SHELL environment variable
 4: value of shell in /etc/passwd
 5: value of shell in config.h
 */
static char *shell = "/bin/sh";
char *utmp = NULL;
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";

/* identification sequence returned in DA and DECID */
char *vtiden = "\033[?6c";

/*
 word delimiter string
 More advanced example: L" `'\"()[]{}"
 */
wchar_t *worddelimiters = L" ";

/* selection timeouts (in milliseconds) */
static unsigned int doubleclicktimeout = 300;
static unsigned int tripleclicktimeout = 600;

/* alt screens */
int allowaltscreen = 1;

/* frames per second slterm should at maximum draw to the screen */
/* set to log(framerate) ->   log(128) = 7; log(64) = 6; log(32) = 5 */
#define xfps_shift 7
#define actionfps_shift 5

/*
 blinking timeout (set to 0 to disable blinking) for the terminal blinking
 attribute.
 */
static unsigned int blinktimeout = 800;

/* thickness of underline and bar cursors */
static unsigned int cursorthickness = 2;

/* bell volume. It must be a value between -100 and 100. 0 to disable */
static int bellvolume = 50;

/*
 default TERM value
 used also for the identification of the capabilities to curses
 this can be overriden in the shell by exporting a known terminal name,
 e.g.: export TERM=xterm-256color
 To make slterm known to curses et al, the terminfo capability file
 (tic) needs to be installed: tix -sx slterm.terminfo or
 slterm -I | tic -sx -
 */
char *termname = "slterm-256color";

/*
 spaces per tab

 When you are changing this value, don't forget to adapt the 'it' value in
 the slterm.terminfo and appropriately install the slterm.terminfo in the environment where
 you use this slterm version.

	it#$tabspaces,

 Secondly make sure your kernel is not expanding tabs. When running `stty
 -a` tab0 should appear. You can tell the terminal to not expand tabs by
 running following command:
	stty tabs
 */
unsigned int tabspaces = 8;

/*
 The table of the first 8 (32) colors, numbered 30..37
 Names are defined by xorg, and (should be) conformant with css names.
 a table of colornames is in doc/colornames.html, and colornames_gray.html.
 RGB in hexadecimal (#RRGGBB) is also possible.
 The table is oriented at the de facto xterm standard.

 each color is: "normal", "bold", "faint", "bold+faint"
 They are used via the ansi sequences, e.g "\033[31m" for red.
 > echo -e "\e[33;1m Text" shows text in red (bold)
 > echo -e "\e[33;1;2m Text" shows text in red (bold_faint)
 (30-37 is foreground,40-47 background color, according to 0..7)
 foregroundcolor 8-15 (90..97) gets color 0-7, bold.

 colors 16 - 255 are colors used from xterm and calculated in colors.c/xdraw.c
  the algorithm to display faint and bold_faint colors is slightly modified
  for better contrast.
 (todo: use colors 8-15 to switch to betacode (-> switch via vi syntax colorizing ))
*/
static const char* colortablenames[8][4] = {
#define GRADIENT(_normal,_bold,_faint,_bold_faint) { #_normal, #_bold, #_faint, #_bold_faint }

//	   0m          	1m    		2m           	1;2m
//	   normal      	bold      	faint       	bold_faint

	{ "black",     	"gray50", 	"gray11",   	"darkslategray" },
	{ "red3",      	"red",   	"darkred",  	"orangered" },
	{ "green3", 		"green", 	"darkgreen",	"PaleGreen" },
	//{ "green3", 		"green", 	"darkgreen",	"olive" },
	{ "saddlebrown",	"yellow",	"#531818",  	"orange" },
	//{ "saddlebrown",	"yellow",	"#531818",  	"chocolate" },
	{ "blue2",     	"#5050ff", 	"darkblue", 	"#00aaea" }, //"deepskyblue" },
	{ "magenta3",  	"magenta", 	"darkmagenta",	"blueviolet" },
	//{ "cyan3",     	"cyan", 		"#321680", 	"aquamarine" },
	{ "cyan3",     	"cyan", 		"darkcyan", 	"aquamarine" },
	{ "gray90",    	"white", 	"darkkhaki", 	"SlateGray3"  }
	// The default text color is "gray90" on "black"

};

// background colors (40..47, and 100..107 )
static const char* bgcolornames[16] = {

	"black", "DarkRed", "Green4", "saddlebrown",
	//"black", "OrangeRed", "Green4", "saddlebrown",
	"blue4" , "magenta4", "#321680", "silver",
	//"blue4" , "magenta4", "turquoise4", "silver",

	"darkslategray", "red", "green", "yellow",
	"blue", "magenta", "cyan", "white"

};

    //"brown3", // sort of brown (orange). brown is "brown" and faint..
	//"#592a1d",
	 //"#532020", // brown
	 //"#531818", // brown
	 //"#562215", // brown

// Outdated. the current table is colortablenames.
// dgreen 036209
// lgreen 00ff10
// dblue 070060
// dfblue 3c33aa
static const char *colorname[] = {
    /* 8 normal colors */
    "black", "red3", "green3", //"brown3", // sort of brown (orange). brown is "brown" and faint..
	"#592a1d", //"#532020", // brown //"#531818", // brown //"#562215", // brown //"yellow3",
    "blue2", "magenta3", "cyan3", "gray90",
    /* 8 bright colors */
    "gray50", "red", "green", "yellow",
    //"#5050ff", // light blue
	 "#00aaea", // schweinchenblau
    //"#5c5cff",
    "magenta", "cyan", "white",
    [255] = 0,
    /* more colors can be added after 255 to use with DefaultXX */
    "#cccccc", "#2e3440",
};

/*
 Default colors (colorname index)
 foreground, background, cursor, reverse cursor
*/
unsigned char defaultfg = 7;
unsigned char defaultbg = 0;
static unsigned char defaultcs = 15;
//static unsigned char defaultrcs = 202;
// Unfocused window
static unsigned char unfocusedrcs = 46; //118;//226;

// colors and attribute for the statusbar
unsigned char statusfg = 75; //21;
unsigned char statusbg = 21; //82;
unsigned char statusattr = ATTR_BOLD; // ATTR_REVERSE

/* Colors used for selection */
unsigned int selectionbg = 19;
//unsigned int selectionbg = 257;
unsigned int selectionfg = 7;
/* If 0 use selectionfg as foreground in order to have a uniform foreground-color */
/* Else if 1 keep original foreground-color of each cell => more colors :) */
//static int ignoreselfg = 1;

/*
 Default shape of cursor
 2: Block
 4: Underline ("_")
 6: Bar ("|")
 7: Block, and (X)
 8: double underline
 9: empty block
 10: underline with sides
 11: under- and overline with sides
 12: overline with sides
*/
unsigned int cursorshape = 4;

/* Default columns and rows numbers */
static unsigned int cols = 80;
static unsigned int rows = 24;

/* Default colour and shape of the mouse cursor */
static unsigned int mouseshape = XC_xterm;
static unsigned int mousefg = 7;
static unsigned int mousebg = 0;

/*
 Xresources preferences to load at startup
 TODO: update this with colortablenames
*/
#ifdef XRESOURCES
ResourcePref resources[] = {
    { "font", STRING, &font },
    { "color0", STRING, &colorname[0] },
    { "color1", STRING, &colorname[1] },
    { "color2", STRING, &colorname[2] },
    { "color3", STRING, &colorname[3] },
    { "color4", STRING, &colorname[4] },
    { "color5", STRING, &colorname[5] },
    { "color6", STRING, &colorname[6] },
    { "color7", STRING, &colorname[7] },
    { "color8", STRING, &colorname[8] },
    { "color9", STRING, &colorname[9] },
    { "color10", STRING, &colorname[10] },
    { "color11", STRING, &colorname[11] },
    { "color12", STRING, &colorname[12] },
    { "color13", STRING, &colorname[13] },
    { "color14", STRING, &colorname[14] },
    { "color15", STRING, &colorname[15] },
    { "background", STRING, &colorname[256] },
    { "foreground", STRING, &colorname[257] },
    { "cursorColor", STRING, &colorname[258] },
    { "termname", STRING, &termname },
    { "shell", STRING, &shell },
    //{ "xfps", INTEGER, &xfps },
    //{ "actionfps", INTEGER, &actionfps },
    { "blinktimeout", INTEGER, &blinktimeout },
    { "bellvolume", INTEGER, &bellvolume },
    { "tabspaces", INTEGER, &tabspaces },
    { "borderpx", INTEGER, &borderpx },
//    { "cwscale", FLOAT, &cwscale },
//    { "chscale", FLOAT, &chscale },
};
#endif

/*
 Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set).
 Note that if you want to use ShiftMask with selmasks, set this to an other
 modifier, set to 0 to not use it.
*/
static uint forcemousemod = ShiftMask;

/*
 Internal mouse shortcuts.
 Beware that overloading Button1 will disable the selection.
*/
const unsigned int mousescrollincrement = 3;
static MouseShortcut mshortcuts[] = {
    /* mask                 button   function        argument       release */
    { ShiftMask, Button4, kscrollup, {.i = mousescrollincrement*3}, 0, /* !alt */ -1 },
    { XK_ANY_MOD, Button4, kscrollup, {.i = mousescrollincrement}, 0, /* !alt */ -1 },
    { ShiftMask, Button5, kscrolldown, {.i = mousescrollincrement*3}, 0, /* !alt */ -1 },
    { XK_ANY_MOD, Button5, kscrolldown, {.i = mousescrollincrement}, 0, /* !alt */ -1 },
    { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
    { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
    { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
};

/* Internal keyboard shortcuts. */
// inputmodes
#define ALLMODES 0xffffffff
#define MODE_DEFAULT 0x01
#define MODE_REGULAR MODE_DEFAULT
#define MODE_LESS 0x02
#define IMODE_HELP 0x04 // 0x4 | 0x2 , keys for lessmode

#define ALL_KEYS UINT_MAX-1
// all comments, starting with //K are parsed into the keystroke shortref

#define I(value) { .i=value }
#define BIND(mask,keysym,function,argument,inputmode,...) { mask,keysym,function,argument,inputmode }

#else  // ifndef extract_keyref
		 // definitions to extract a key reference
#define BIND(mask,keysym,function,argument,inputmode,...) inputmode; mask ; keysym ; function ; __VA_ARGS__
#define ControlMask Control
#define ShiftMask Shift
#define Mod1Mask Alt
#define Mod4Mask Win
#define XK_ANY_MOD All
#define ALLMODES All
#define MODE_LESS Less
#define IMODE_HELP Help
#endif

#define ALT Mod1Mask
#define SHIFT ShiftMask
#define CONTROL ControlMask
#define WIN Mod4Mask

// masks: Mod1Mask .. Mod5Mask, ControlMask, ShiftMask, LockMask
// mod1 = alt, mod2 = win , mod3 = Capslock (here)
// mod4 = win (!)
#define MODKEY Mod1Mask
#define TERMMOD (ControlMask|ShiftMask)
#define SETBOOKMARKMASK (ControlMask|Mod1Mask)
// CapsLock
//#define BOOKMARKMASK Mod2Mask
#define BOOKMARKMASK ControlMask
// Ctrl+Shift+Win
#define SETFONTMASK ShiftMask|CONTROL

/*
 The table of bound shortcuts and keys
 Can be changed.
 The key names are in the according header file of xorg,
 here: /usr/include/X11/keysymdef.h

 The first matching binding will be used,
 the table is matched in its order here.
 e.g.
 Match Shift + PageUp
 Match PageUp
 */
#ifndef extract_keyref
Shortcut shortcuts[] = {
#endif
/*  ( mask,       keysym,   function,  argument, INPUTMODE ) */

BIND( ControlMask, XK_F1, showhelp, { 0},ALLMODES ),

BIND( XK_ANY_MOD, XK_Break, sendbreak, {.i = 0},ALLMODES ),
BIND( ControlMask, XK_Print, toggleprinter, {.i = 0},ALLMODES ),
BIND( ShiftMask, XK_Print, printscreen, {.i = 0},ALLMODES ),
BIND( XK_ANY_MOD, XK_Print, printsel, {.i = 0},ALLMODES ),
BIND( TERMMOD, XK_I, inverse_screen, {},ALLMODES ),

BIND(ControlMask|ShiftMask|Mod1Mask|Mod4Mask, XK_I, dump_terminfo, {}, MODE_DEFAULT ),

// Change font size/width
    //{ SETFONTMASK, XK_Prior, zoom, {.f = +1},ALLMODES ),
BIND( SETFONTMASK, XK_Page_Up, zoom, {.f = +1},ALLMODES ),
BIND( SETFONTMASK, XK_Page_Down, zoom, {.f = -1},ALLMODES ),
    //{ SETFONTMASK, XK_Next, zoom, {.f = -1},ALLMODES ),
BIND( SETFONTMASK, XK_BackSpace, zoomreset, {.f = 0},ALLMODES ),

BIND( SETFONTMASK, XK_Insert, set_fontwidth, {.i = -1},ALLMODES ),
BIND( SETFONTMASK, XK_Delete, set_fontwidth, {.i = 1},ALLMODES ),
BIND( SETFONTMASK, XK_End, set_fontheight, {.i = -1},ALLMODES ),
BIND( SETFONTMASK, XK_Home, set_fontheight, {.i = +1},ALLMODES ),

// Scrolling
BIND( ShiftMask, XK_Page_Up, kscrollup, {.i = -1},ALLMODES ),
BIND( ShiftMask, XK_Page_Down, kscrolldown, {.i = -1},ALLMODES ),
BIND( ShiftMask, XK_End, scrolltobottom, { },ALLMODES ),
BIND( ShiftMask, XK_Home, scrolltotop, { },ALLMODES ),
 		// Shift+Up/Down: Scroll Up/Down 3 lines
BIND( ShiftMask, XK_Up, kscrollup, {.i = 3},ALLMODES ),
BIND( ShiftMask, XK_Down, kscrolldown, {.i = 3},ALLMODES ),

// lessmode
BIND( XK_ANY_MOD, XK_Up, kscrollup, {.i = 1},MODE_LESS ),
BIND( XK_ANY_MOD, XK_Down, kscrolldown, {.i = 1},MODE_LESS ),
BIND( XK_ANY_MOD, XK_Page_Up, kscrollup, {.i = -1},MODE_LESS ),
BIND( XK_ANY_MOD, XK_Page_Down, kscrolldown, {.i = -1},MODE_LESS ),
BIND( XK_ANY_MOD, XK_space, kscrolldown, {.i = -1},MODE_LESS ),
BIND( XK_ANY_MOD, XK_End, scrolltobottom, { },MODE_LESS ),
BIND( XK_ANY_MOD, XK_Home, scrolltotop, { },MODE_LESS ),

// help mode
BIND( XK_ANY_MOD, XK_q, quithelp, { 0},IMODE_HELP ),
BIND( XK_ANY_MOD, XK_Escape, quithelp, { 0},IMODE_HELP ),
BIND( XK_ANY_MOD, XK_Up, kscrollup, {.i = 1},IMODE_HELP ),
BIND( XK_ANY_MOD, XK_Down, kscrolldown, {.i = 1},IMODE_HELP ),
BIND( XK_ANY_MOD, XK_Page_Up, kscrollup, {.i = -1},IMODE_HELP ),
BIND( XK_ANY_MOD, XK_Page_Down, kscrolldown, {.i = -1},IMODE_HELP ),
BIND( XK_ANY_MOD, XK_space, kscrolldown, {.i = -1},IMODE_HELP ),
BIND( XK_ANY_MOD, XK_End, scrolltobottom, { },IMODE_HELP ),
BIND( XK_ANY_MOD, XK_Home, scrolltotop, { },IMODE_HELP ),

		// abort precessing when in the help view.
BIND( XK_ANY_MOD, ALL_KEYS, dummy, {}, IMODE_HELP ),

// clipboard
BIND( TERMMOD, XK_C, clipcopy, {.i = 0},ALLMODES ),
BIND( TERMMOD, XK_V, clippaste, {.i = 0},ALLMODES ),
BIND( TERMMOD, XK_Y, selpaste, {.i = 0},ALLMODES ),
BIND( ShiftMask, XK_Insert, selpaste, {.i = 0},ALLMODES ),
BIND( TERMMOD, XK_S, keyboard_select, { 0 },ALLMODES ),
BIND( Mod1Mask, XK_s, keyboard_select, { 0 },ALLMODES ),

BIND( TERMMOD, XK_Num_Lock, numlock, {.i = 0},ALLMODES ),

// scrollmarks
BIND( SETBOOKMARKMASK, XK_1, set_scrollmark, { .i=1 },ALLMODES ),
BIND( SETBOOKMARKMASK, XK_2, set_scrollmark, { .i=2 },ALLMODES ),
BIND( SETBOOKMARKMASK, XK_3, set_scrollmark, { .i=3 },ALLMODES ),
BIND( SETBOOKMARKMASK, XK_4, set_scrollmark, { .i=4 },ALLMODES ),
BIND( SETBOOKMARKMASK, XK_5, set_scrollmark, { .i=5 },ALLMODES ),
BIND( SETBOOKMARKMASK, XK_6, set_scrollmark, { .i=6 },ALLMODES ),
BIND( SETBOOKMARKMASK, XK_7, set_scrollmark, { .i=7 },ALLMODES ),
BIND( SETBOOKMARKMASK, XK_8, set_scrollmark, { .i=8 },ALLMODES ),
BIND( SETBOOKMARKMASK, XK_9, set_scrollmark, { .i=9 },ALLMODES ),
BIND( SETBOOKMARKMASK, XK_0, set_scrollmark, { .i=0 },ALLMODES ),
		// set scrollmark 0 on Return
    //{ XK_ANY_MOD, XK_Return, set_scrollmark, { .i=0 },ALLMODES ),

// here Capslock (mapped with xmodmap)
BIND( BOOKMARKMASK, XK_1, scrollmark, { .i=1 },ALLMODES ),
BIND( BOOKMARKMASK, XK_2, scrollmark, { .i=2 },ALLMODES ),
BIND( BOOKMARKMASK, XK_3, scrollmark, { .i=3 },ALLMODES ),
BIND( BOOKMARKMASK, XK_4, scrollmark, { .i=4 },ALLMODES ),
BIND( BOOKMARKMASK, XK_5, scrollmark, { .i=5 },ALLMODES ),
BIND( BOOKMARKMASK, XK_6, scrollmark, { .i=6 },ALLMODES ),
BIND( BOOKMARKMASK, XK_7, scrollmark, { .i=7 },ALLMODES ),
BIND( BOOKMARKMASK, XK_8, scrollmark, { .i=8 },ALLMODES ),
BIND( BOOKMARKMASK, XK_9, scrollmark, { .i=9 },ALLMODES ),
BIND( BOOKMARKMASK, XK_0, scrollmark, { .i=0 },ALLMODES ),

/* replaced with retmarks
BIND( XK_ANY_MOD, XK_1, scrollmark, { .i=1 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_2, scrollmark, { .i=2 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_3, scrollmark, { .i=3 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_4, scrollmark, { .i=4 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_5, scrollmark, { .i=5 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_6, scrollmark, { .i=6 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_7, scrollmark, { .i=7 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_8, scrollmark, { .i=8 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_9, scrollmark, { .i=9 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_0, scrollmark, { .i=0 },MODE_LESS ),*/

BIND( XK_ANY_MOD, XK_1, retmark, { .i=1 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_2, retmark, { .i=2 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_3, retmark, { .i=3 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_4, retmark, { .i=4 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_5, retmark, { .i=5 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_6, retmark, { .i=6 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_7, retmark, { .i=7 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_8, retmark, { .i=8 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_9, retmark, { .i=9 },MODE_LESS ),
BIND( XK_ANY_MOD, XK_0, retmark, { .i=-2 },MODE_LESS ),

BIND( SETBOOKMARKMASK, XK_Return, enterscroll, { .i=11 },ALLMODES ),
    //{ ControlMask, XK_Return, enterscroll, { .i=11 },ALLMODES ),
BIND( ShiftMask, XK_Return, enterscroll, { .i=11 },ALLMODES ),
    //{ XK_ANY_MOD, XK_Return, leavescroll, { 0 },ALLMODES ),

	// doesnt ork ??
	// { TERMMOD, XK_E, ttysend, { .s="\x80" }, ALLMODES ),

BIND( ShiftMask, XK_BackSpace, retmark , {  },ALLMODES ),
BIND( ShiftMask, XK_ISO_Left_Tab, retmark, {}, ALLMODES ), // tab left <- to enter lessmode
BIND( XK_ANY_MOD,XK_BackSpace, retmark , { },MODE_LESS ),
BIND( XK_ANY_MOD,XK_Tab, retmark , { .i=-1 },MODE_LESS ), // tab -> to scroll down
	// tab left or backspace and right cycle between set retmarks.

// "less mode" enter with Ctrl+shift+ Cursor/Page up/down
//  Up and PageUp also scroll upwards
// toggle with Ctrl+Shift + L / down
// quit with q or Escape
	// switch on.
//BIND( TERMMOD, XK_Up, lessmode_toggle, I( LESSMODE_ON | SCROLLUP(3) ) ,ALLMODES ),
BIND( ALT+ShiftMask, XK_Up, lessmode_toggle, I( LESSMODE_ON | SCROLLUP(3) ) ,ALLMODES ),
//BIND( TERMMOD, XK_Page_Up, lessmode_toggle, I( LESSMODE_ON | SCROLL_PAGEUP) ,ALLMODES ),
BIND( ALT+SHIFT, XK_Page_Up, lessmode_toggle, I( LESSMODE_ON | SCROLL_PAGEUP) ,ALLMODES ),
//BIND( TERMMOD, XK_Page_Down, lessmode_toggle, I( LESSMODE_ON | SCROLL_PAGEDOWN),ALLMODES ),
BIND( ALT+SHIFT, XK_Page_Down, lessmode_toggle, I( LESSMODE_ON | SCROLL_PAGEDOWN),ALLMODES ),
//BIND( TERMMOD, XK_Down, lessmode_toggle,I( LESSMODE_ON | SCROLLDOWN(3)),ALLMODES ),
BIND( ALT+SHIFT, XK_Down, lessmode_toggle,I( LESSMODE_ON | SCROLLDOWN(3)),ALLMODES ),
//BIND( TERMMOD, XK_Home, lessmode_toggle,I( LESSMODE_ON | SCROLL_TOP ),ALLMODES ),
BIND( ALT+SHIFT, XK_Home, lessmode_toggle,I( LESSMODE_ON | SCROLL_TOP ),ALLMODES ),

	// toggle
BIND( ALT+SHIFT, XK_L, lessmode_toggle, I(LESSMODE_TOGGLE),ALLMODES ),
BIND( XK_ANY_MOD, XK_Scroll_Lock, lessmode_toggle, I(LESSMODE_TOGGLE),ALLMODES ),
	// switchoff
BIND( XK_ANY_MOD, XK_Escape, lessmode_toggle,  I(LESSMODE_OFF | SCROLL_BOTTOM),MODE_LESS ),
BIND( XK_ANY_MOD, XK_q, lessmode_toggle, I(LESSMODE_OFF | SCROLL_BOTTOM),MODE_LESS ),
BIND( ShiftMask, XK_Return, lessmode_toggle, I(LESSMODE_TOGGLE),MODE_LESS ),

// select charmap
BIND( ControlMask|Mod4Mask, XK_1, set_charmap, { .i=1 },ALLMODES ),
BIND( ControlMask|Mod4Mask, XK_2, set_charmap, { .i=2 },ALLMODES ),
BIND( ControlMask|Mod4Mask, XK_3, set_charmap, { .i=3 },ALLMODES ),
BIND( ControlMask|Mod4Mask, XK_4, set_charmap, { .i=4 },ALLMODES ),
BIND( ControlMask|Mod4Mask, XK_5, set_charmap, { .i=5 },ALLMODES ),
BIND( ControlMask|Mod4Mask, XK_6, set_charmap, { .i=6 },ALLMODES ),
BIND( ControlMask|Mod4Mask, XK_7, set_charmap, { .i=7 },ALLMODES ),
BIND( ControlMask|Mod4Mask, XK_8, set_charmap, { .i=8 },ALLMODES ),
BIND( ControlMask|Mod4Mask, XK_9, set_charmap, { .i=9 },ALLMODES ),
BIND( ControlMask|Mod4Mask, XK_0, set_charmap, { .i=0 },ALLMODES ),

    //{ TERMMOD, XK_T, temp, {.i = 0},ALLMODES },

#ifndef extract_keyref
};
#undef I
#undef BIND

#undef ALT
#undef SHIFT
#undef CONTROL
#undef WIN

/*
 Special keys (change & recompile slterm.terminfo accordingly)

 Mask value:
   Use XK_ANY_MOD to match the key no matter modifiers state
   Use XK_NO_MOD to match the key alone (no modifiers)
 appkey value:
   0: no value
   > 0: keypad application mode enabled
   = 2: term.numlock = 1
   < 0: keypad application mode disabled
 appcursor value:
   0: no value
   > 0: cursor application mode enabled
   < 0: cursor application mode disabled

 Be careful with the order of the definitions because st searches in
 this table sequentially, so any XK_ANY_MOD must be in the last
 position for a key.
*/

/*
 If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
 to be mapped below, add them to this array.
*/
static KeySym mappedkeys[] = { -1 };

/*
 State bits to ignore when matching key or button events.  By default,
 numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored.
*/
static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;

#define K(key,mod,str,appkey,appcursor) { key,mod,str,sizeof(str)-1,appkey,appcursor }

static Key key[] = {
    /* keysym           mask            string      appkey appcursor */

	 // Linux compatibility definitions below
	 K( XK_Return, Mod1Mask, "\033\r", 0, 0),
    K( XK_Return, XK_ANY_MOD, "\r", 0, 0),
    K( XK_Up, ShiftMask, "\033[1;2A", 0, 0),
    K( XK_Up, Mod1Mask, "\033[1;3A", 0, 0),
    K( XK_Up, ShiftMask|Mod1Mask, "\033[1;4A", 0, 0),
    K( XK_Up, ControlMask, "\033[1;5A", 0, 0),
    K( XK_Up, ShiftMask|ControlMask, "\033[1;6A", 0, 0),
    K( XK_Up, ControlMask|Mod1Mask, "\033[1;7A", 0, 0),
    K( XK_Up, ShiftMask|ControlMask|Mod1Mask, "\033[1;8A", 0, 0),
    K( XK_Up, XK_ANY_MOD, "\033[A", 0, -1),
    K( XK_Up, XK_ANY_MOD, "\033OA", 0, +1),
    K( XK_Down, ShiftMask, "\033[1;2B", 0, 0),
    K( XK_Down, Mod1Mask, "\033[1;3B", 0, 0),
    K( XK_Down, ShiftMask|Mod1Mask, "\033[1;4B", 0, 0),
    K( XK_Down, ControlMask, "\033[1;5B", 0, 0),
    K( XK_Down, ShiftMask|ControlMask, "\033[1;6B", 0, 0),
    K( XK_Down, ControlMask|Mod1Mask, "\033[1;7B", 0, 0),
    K( XK_Down, ShiftMask|ControlMask|Mod1Mask, "\033[1;8B", 0, 0),
    K( XK_Down, XK_ANY_MOD, "\033[B", 0, -1),
    K( XK_Down, XK_ANY_MOD, "\033OB", 0, +1),
    K( XK_Left, ShiftMask, "\033[1;2D", 0, 0),
    K( XK_Left, Mod1Mask, "\033[1;3D", 0, 0),
    K( XK_Left, ShiftMask|Mod1Mask, "\033[1;4D", 0, 0),
    K( XK_Left, ControlMask, "\033[1;5D", 0, 0),
    K( XK_Left, ShiftMask|ControlMask, "\033[1;6D", 0, 0),
    K( XK_Left, ControlMask|Mod1Mask, "\033[1;7D", 0, 0),
    K( XK_Left, ShiftMask|ControlMask|Mod1Mask, "\033[1;8D", 0, 0),
    K( XK_Left, XK_ANY_MOD, "\033[D", 0, -1),
    K( XK_Left, XK_ANY_MOD, "\033OD", 0, +1),
    K( XK_Right, ShiftMask, "\033[1;2C", 0, 0),
    K( XK_Right, Mod1Mask, "\033[1;3C", 0, 0),
    K( XK_Right, ShiftMask|Mod1Mask, "\033[1;4C", 0, 0),
    K( XK_Right, ControlMask, "\033[1;5C", 0, 0),
    K( XK_Right, ShiftMask|ControlMask, "\033[1;6C", 0, 0),
    K( XK_Right, ControlMask|Mod1Mask, "\033[1;7C", 0, 0),
    K( XK_Right, ShiftMask|ControlMask|Mod1Mask, "\033[1;8C", 0, 0),
    K( XK_Right, XK_ANY_MOD, "\033[C", 0, -1),
    K( XK_Right, XK_ANY_MOD, "\033OC", 0, +1),

    K( XK_Insert, ShiftMask, "\033[4l", -1, 0),
    K( XK_Insert, ShiftMask, "\033[2;2~", +1, 0),
    K( XK_Insert, ControlMask, "\033[L", -1, 0),
    K( XK_Insert, ControlMask, "\033[2;5~", +1, 0),
    K( XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0),
    K( XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0),
    K( XK_Delete, ControlMask, "\033[M", -1, 0),
    K( XK_Delete, ControlMask, "\033[3;5~", +1, 0),
    K( XK_Delete, ShiftMask, "\033[2K", -1, 0),
    K( XK_Delete, ShiftMask, "\033[3;2~", +1, 0),
    K( XK_Delete, XK_ANY_MOD, "\033[P", -1, 0),
    K( XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0),
    K( XK_BackSpace, XK_NO_MOD, "\177", 0, 0),
    K( XK_BackSpace, Mod1Mask, "\033\177", 0, 0),
    K( XK_Home, ShiftMask, "\033[2J", 0, -1),
    K( XK_Home, ShiftMask, "\033[1;2H", 0, +1),
    K( XK_Home, XK_ANY_MOD, "\033[H", 0, -1),
    K( XK_Home, XK_ANY_MOD, "\033[1~", 0, +1),
    K( XK_End, ControlMask, "\033[J", -1, 0),
    K( XK_End, ControlMask, "\033[1;5F", +1, 0),
    K( XK_End, ShiftMask, "\033[K", -1, 0),
    K( XK_End, ShiftMask, "\033[1;2F", +1, 0),
    K( XK_End, XK_ANY_MOD, "\033[4~", 0, 0),
    K( XK_Prior, ControlMask, "\033[5;5~", 0, 0),
    K( XK_Prior, ShiftMask, "\033[5;2~", 0, 0),
    K( XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0),
    K( XK_Next, ControlMask, "\033[6;5~", 0, 0),
    K( XK_Next, ShiftMask, "\033[6;2~", 0, 0),
    K( XK_Next, XK_ANY_MOD, "\033[6~", 0, 0),
    K( XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0),

    K( XK_F1, XK_NO_MOD, "\033OP", 0, 0),
    K( XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0),
    K( XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0),
    K( XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0),
    K( XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0),
    K( XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0),
    K( XK_F2, XK_NO_MOD, "\033OQ", 0, 0),
    K( XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0),
    K( XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0),
    K( XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0),
    K( XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0),
    K( XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0),
    K( XK_F3, XK_NO_MOD, "\033OR", 0, 0),
    K( XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0),
    K( XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0),
    K( XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0),
    K( XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0),
    K( XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0),
    K( XK_F4, XK_NO_MOD, "\033OS", 0, 0),
    K( XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0),
    K( XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0),
    K( XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0),
    K( XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0),
    K( XK_F5, XK_NO_MOD, "\033[15~", 0, 0),
    K( XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0),
    K( XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0),
    K( XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0),
    K( XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0),
    K( XK_F6, XK_NO_MOD, "\033[17~", 0, 0),
    K( XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0),
    K( XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0),
    K( XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0),
    K( XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0),
    K( XK_F7, XK_NO_MOD, "\033[18~", 0, 0),
    K( XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0),
    K( XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0),
    K( XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0),
    K( XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0),
    K( XK_F8, XK_NO_MOD, "\033[19~", 0, 0),
    K( XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0),
    K( XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0),
    K( XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0),
    K( XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0),
    K( XK_F9, XK_NO_MOD, "\033[20~", 0, 0),
    K( XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0),
    K( XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0),
    K( XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0),
    K( XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0),
    K( XK_F10, XK_NO_MOD, "\033[21~", 0, 0),
    K( XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0),
    K( XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0),
    K( XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0),
    K( XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0),
    K( XK_F11, XK_NO_MOD, "\033[23~", 0, 0),
    K( XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0),
    K( XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0),
    K( XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0),
    K( XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0),
    K( XK_F12, XK_NO_MOD, "\033[24~", 0, 0),
    K( XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0),
    K( XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0),
    K( XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0),
    K( XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0),

	 K( XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0),
    K( XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0),

    K( XK_KP_Home, ShiftMask, "\033[2J", 0, -1),
    K( XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1),
    K( XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1),
    K( XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1),
    K( XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0),
    K( XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1),
    K( XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1),
    K( XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0),
    K( XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1),
    K( XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1),
    K( XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0),
    K( XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1),
    K( XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1),
    K( XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0),
    K( XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1),
    K( XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1),
    K( XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0),
    K( XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0),
    K( XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0),
    K( XK_KP_End, ControlMask, "\033[J", -1, 0),
    K( XK_KP_End, ControlMask, "\033[1;5F", +1, 0),
    K( XK_KP_End, ShiftMask, "\033[K", -1, 0),
    K( XK_KP_End, ShiftMask, "\033[1;2F", +1, 0),
    K( XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0),
    K( XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0),
    K( XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0),
    K( XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0),
    K( XK_KP_Insert, ShiftMask, "\033[4l", -1, 0),
    K( XK_KP_Insert, ControlMask, "\033[L", -1, 0),
    K( XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0),
    K( XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0),
    K( XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0),
    K( XK_KP_Delete, ControlMask, "\033[M", -1, 0),
    K( XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0),
    K( XK_KP_Delete, ShiftMask, "\033[2K", -1, 0),
    K( XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0),
    K( XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0),
    K( XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0),
    K( XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0),
    K( XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0),
    K( XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0),
    K( XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0),
    K( XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0),
    K( XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0),
    K( XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0),
    K( XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0),
    K( XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0),
    K( XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0),
    K( XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0),
    K( XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0),
    K( XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0),
    K( XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0),
    K( XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0),

//#ifdef F13_35
#if 1
    K( XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0),
    K( XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0),
    K( XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0),
    K( XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0),
    K( XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0),
    K( XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0),
    K( XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0),
    K( XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0),
    K( XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0),
    K( XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0),
    K( XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0),
    K( XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0),
    K( XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0),
    K( XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0),
    K( XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0),
    K( XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0),
    K( XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0),
    K( XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0),
    K( XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0),
    K( XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0),
    K( XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0),
    K( XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0),
    K( XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0),
#endif
};
#undef K

/*
 Selection types' masks.
 Use the same masks as usual.
 Button1Mask is always unset, to make masks match between ButtonPress.
 ButtonRelease and MotionNotify.
 If no match is found, regular selection is used.
*/
static uint selmasks[] = {
    [SEL_RECTANGULAR] = Mod1Mask,
};

/*
 select codepages
 can be: cp437, cp850, cp1250,cp1251,cp1252,cp1253,cp1255,
         cp1256,cp1257,cp1258,cpe4000,cpe4002a,
         macintosh, atarist, mac_centraleurope
 (macintosh = MacRoman)
 other codepages could be added in charmaps.h
 use Ctrl+Win+ [1..9] to switch to the other codepages on the fly.

 cp1252 is at the same time the DEC-MCS, ANSI, and Windows1252 default codepage.

 cp437 is the old ibm codepage, with those signs to draw borders and boxes.
 (cp437 is uncomplete here, the "graphics mode" signs 0..0x1f are missing.
 it's the old issue of the IBM PC1. Reinvented.)

 Me, I'm happy with CP1252, it has got umlauts, and yet every application
 was able to work with the ansi code table without modifications.

 Now, I did write a personal codepage, named cpe4000
 There are Umlauts, sz, box drawing chars ( at the places of the cp437 / 850),
 the greek alphabet and several mathematical and logical chars.
 It's what I do need for writing.
 There's a filter for the conversion to and from utf8 and between codepages,
 within tools.
 Numbered the cp e4000, according to the rfc's 0xExxxx is reserved for private
 assignments.

 Finally, I created another codepage. Naming this cpe4002a,
 but I regard the codepage as alpha, I'm going to change some things.
 Got the box drawing chars at the same location as with cp437.
 umlauts are there, at the locations of cp437/cp850
 Several logical and mathematical operators and signs
*/

// assign to Ctrl+Win +                    0,       1,    2        3      4      5      6
const short unsigned int* codepage[] = { cp1250, cp1251, cp1252, cp1253, cp437, cp850, cpe4002a,
//    7                    8      9
	mac_centraleurope, macintosh    };
// the default codepage is cp1252
// and assigned to Ctrl+Win+2

#ifdef MISC //my local copy
int selected_codepage = 6;
#else
// the default codepage (cp1252)
int selected_codepage = 2;
#endif

// convert the x clipboard to and from utf8, when yanking/pasting
#ifndef UTF8 // utf8->utf8 wouldn't be useful
#define UTF8_CLIPBOARD
#endif

// environment variables, exported to the shell
// besides SHELL, USER, HOME, TERM, COLUMNS, LINES, TERMCAP
// which are determined and set in system.c
const char *export_env[][2] = {

		// display chars 128-255 in less
   { "LESSCHARSET", "dos"},

		// "save" default. better than unset.
		// is set in the shell normally
   { "LANG", "C"},
   { "LC_ALL", "C"},

	// color ansi escape sequences
   { "NORM", "\e[0;37;40m"},

   { "BLACK", "\e[30m"},
   { "RED", "\e[31m"},
   { "GREEN", "\e[32m"},
   { "BROWN", "\e[33m"},
   { "BLUE", "\e[34m"},
   { "MAGENTA", "\e[35m"},
   { "CYAN", "\e[36m"},
   { "WHITE", "\e[37m"},

   { "ORANGE", "\e[1;2;33m"},
   { "ORANGERED", "\e[1;2;31m"},
   { "GRAY", "\e[1;2;30m"},
   { "PURPLE", "\e[1;2;35m"},
   { "MINT", "\e[1;2;32m"},
   { "TURQUOISE", "\e[1;2;36m"},

   { "LBLACK", "\e[90m"},
   { "LGRAY", "\e[90m"},
   { "LRED", "\e[91m"},
   { "LGREEN", "\e[92m"},
   { "LYELLOW", "\e[93m"},
   { "LBROWN", "\e[93m"}, // well. "compatibility"
   { "YELLOW", "\e[93m"},
   { "LBLUE", "\e[94m"},
   { "LMAGENTA", "\e[95m"},
   { "LCYAN", "\e[96m"},
   { "LWHITE", "\e[97m"},

   { "DBLACK", "\e[2;30m"},
   { "DGRAY", "\e[2;30m"},
   { "DRED", "\e[2;31m"},
   { "DGREEN", "\e[2;32m"},
   { "DYELLOW", "\e[2;33m"}, // is brown
   { "DBROWN", "\e[2;33m"},
   { "DBLUE", "\e[2;34m"},
   { "DMAGENTA", "\e[2;35m"},
   { "DCYAN", "\e[2;36m"},
   { "DWHITE", "\e[2;37m"},

   { "LDBLACK", "\e[1;2;30m"},
   { "LDGRAY", "\e[1;2;30m"},
   { "LDRED", "\e[1;2;31m"},
   { "LDGREEN", "\e[1;2;32m"},
   { "LDYELLOW", "\e[1;2;33m"},
   { "LDBROWN", "\e[1;2;33m"},
   { "LDBLUE", "\e[1;2;34m"},
   { "LDMAGENTA", "\e[1;2;35m"},
   { "LDCYAN", "\e[1;2;36m"},
   { "LDWHITE", "\e[1;2;37m"},

   { "BGBLACK", "\e[40m"},
   { "BGRED", "\e[41m"},
   { "BGGREEN", "\e[42m"},
   { "BGBROWN", "\e[43m"},
   { "BGBLUE", "\e[44m"},
   { "BGMAGENTA", "\e[45m"},
   { "BGCYAN", "\e[46m"},
   { "BGWHITE", "\e[47m"},

   { "BGLBLACK", "\e[100m"},
   { "BGGRAY", "\e[100m"},
   { "BGLRED", "\e[101m"},
   { "BGLGREEN", "\e[102m"},
   { "BGLYELLOW", "\e[103m"},
   { "BGYELLOW", "\e[103m"},
   { "BGLBROWN", "\e[103m"},
   { "BGLBLUE", "\e[104m"},
   { "BGLMAGENTA", "\e[105m"},
   { "BGLCYAN", "\e[106m"},
   { "BGLWHITE", "\e[107m"},

   { "BOLD","\e[1m" },
   { "FAINT","\e[2m" },
   { "CURSIVE","\e[3m" },
   { "UNDERLINE","\e[4m" },
   { "BLINK","\e[6m" },
   { "REVERSE","\e[7m" },
   { "STRIKETHROUGH","\e[9m" },
   { "DOUBLEUNDERLINE","\e[21m" },
	{0} };

// size of the history buffer for the alt screen.
// this buffer is used as cache by some programs,
// e.g. man does scrolling, and repainting, mixed
// Both sizes need to be a power of 2

#define ALTSCREEN_HISTSIZE 1024

// needs to be larger than the help text
#define HELPSCREEN_HISTSIZE 512

// end of config

#endif

#endif


code:
// handle control chars and sequences, ansi escape sequences.

#include "controlchars.h"

static CSIEscape csiescseq;
static STREscape strescseq;

int handle_controlchars( Rune u IF_UTF8(, uint decoded_len, char* decoded_char ) ){
#ifndef UTF8
#define decoded_len 1
#endif

	if (term->esc & ESC_STR) { // within a esc sequence
		if (u == '\a' || u == 030 || u == 032 || u == 033 || ISCONTROLC1(u)) {
			term->esc &= ~(ESC_START | ESC_STR | ESC_DCS);
			if (IS_SET(MODE_SIXEL)) {
				/* TODO: render sixel */
				term->mode &= ~MODE_SIXEL;
				return(1);
			}
			term->esc |= ESC_STR_END;
			goto check_control_code;
		}

		if (IS_SET(MODE_SIXEL)) {
			/* TODO: implement sixel mode */
			return(1);
		}
		if (term->esc & ESC_DCS && strescseq.len == 0 && u == 'q') {
			term->mode |= MODE_SIXEL;
		}

		if (strescseq.len + decoded_len >= strescseq.siz) {
			/*
			 * Here is a bug in terminals. If the user never sends
			 * some code to stop the str or esc command, then st
			 * will stop responding. But this is better than
			 * silently failing with unknown characters. At least
			 * then users will report back.
			 *
			 * In the case users ever get fixed, here is the code:
			 */
			/*
			 * term->esc = 0;
			 * strhandle();
			 */
			//if (strescseq.siz > (SIZE_MAX - UTF_SIZ) / 2)
			if (strescseq.siz > 8192 ) {
				// misc2024 How could a user fix that, when not being told? Eh??
				// albite nowadays SIZE_MAX is defined here with 0xfffffff*4,
				// why. anyways. The comment above might be about 30 years old.
				// I added the error msg. And changed the maximum size to an
				// IMHO more reasonable value.
				// Users might like to be told about problems
				fprintf(stderr,"ESC Sequence too long, exceeding 8kB\n");
				return(1);
			}
			strescseq.siz *= 2;
			strescseq.buf = xrealloc(strescseq.buf, strescseq.siz);
		}

#ifdef UTF8
		memmove(&strescseq.buf[strescseq.len], decoded_char, decoded_len);
		strescseq.len += decoded_len;
#else
		strescseq.buf[strescseq.len] = u;
		strescseq.len++;
#endif
		return(1);
	}

check_control_code:
	/*
	 * Actions of control codes must be performed as soon they arrive
	 * because they can be embedded inside a control sequence, and
	 * they must not cause conflicts with sequences.
	 */
	if (ISCONTROL(u)) {
		//	if ( u>=0x80 )
		//		printf("cont r: %x\n",u);

		tcontrolcode(u);
		/*
		 * control codes are not shown ever
		 */
		return(1);
	} else if (term->esc & ESC_START) {
		if (term->esc & ESC_CSI) {
			csiescseq.buf[csiescseq.len++] = u;
			if (BETWEEN(u, 0x40, 0x7E) ||
					csiescseq.len >= sizeof(csiescseq.buf) - 1) {
				term->esc = 0;
				csiparse();
				csihandle();
			}
			return(1);
		} else if (term->esc & ESC_UTF8) {
			tdefutf8(u);
		} else if (term->esc & ESC_ALTCHARSET) {
			tdeftran(u);
		} else if (term->esc & ESC_TEST) {
			tdectest(u);
		} else {
			if (!eschandle(u)) {
				return(1);
			}
			/* sequence already finished */
		}
		term->esc = 0;
		/*
		 * All characters which form part of a sequence are not
		 * printed
		 */
		return(1);
	}

#ifndef UTF8
#undef decoded_len
#endif

	return(0);
}

void strparse(void) {
	int c;
	char *p = strescseq.buf;

	strescseq.narg = 0;
	strescseq.buf[strescseq.len] = '\0';

	if (*p == '\0') {
		return;
	}

	while (strescseq.narg < STR_ARG_SIZ) {
		strescseq.args[strescseq.narg++] = p;
		while ((c = *p) != ';' && c != '\0') {
			++p;
		}
		if (c == '\0') {
			return;
		}
		*p++ = '\0';
	}
}

void strdump(void) {
	size_t i;
	uint c;

	fprintf(stderr, "ESC%c", strescseq.type);
	for (i = 0; i < strescseq.len; i++) {
		c = strescseq.buf[i] & 0xff;
		if (c == '\0') {
			putc('\n', stderr);
			return;
		} else if (isprint(c)) {
			putc(c, stderr);
		} else if (c == '\n') {
			fprintf(stderr, "(\\n)");
		} else if (c == '\r') {
			fprintf(stderr, "(\\r)");
		} else if (c == 0x1b) {
			fprintf(stderr, "(\\e)");
		} else {
			fprintf(stderr, "(%02x)", c);
		}
	}
	fprintf(stderr, "ESC\\\n");
}

void strreset(void) {
	strescseq = (STREscape){
		.buf = xrealloc(strescseq.buf, STR_BUF_SIZ),
			.siz = STR_BUF_SIZ,
	};
}

void tstrsequence(uchar c) {
	strreset();

	switch (c) {
		case 0x90: /* DCS -- Device Control String */
			c = 'P';
			term->esc |= ESC_DCS;
			break;
		case 0x9f: /* APC -- Application Program Command */
			c = '_';
			break;
		case 0x9e: /* PM -- Privacy Message */
			c = '^';
			break;
		case 0x9d: /* OSC -- Operating System Command */
			c = ']';
			break;
	}
	strescseq.type = c;
	term->esc |= ESC_STR;
}

void csiparse(void) {
	char *p = csiescseq.buf, *np;
	long int v;

	csiescseq.narg = 0;
	if (*p == '?') {
		csiescseq.priv = 1;
		p++;
	}

	csiescseq.buf[csiescseq.len] = '\0';
	while (p < csiescseq.buf + csiescseq.len) {
		np = NULL;
		v = strtol(p, &np, 10);
		if (np == p) {
			v = 0;
		}
		if (v == LONG_MAX || v == LONG_MIN) {
			v = -1;
		}
		csiescseq.arg[csiescseq.narg++] = v;
		p = np;
		if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ) {
			break;
		}
		p++;
	}
	csiescseq.mode[0] = *p++;
	csiescseq.mode[1] = (p < csiescseq.buf + csiescseq.len) ? *p : '\0';
}

void csidump(void) {
	size_t i;
	uint c;

	fprintf(stderr, "ESC[");
	for (i = 0; i < csiescseq.len; i++) {
		c = csiescseq.buf[i] & 0xff;
		if (isprint(c)) {
			putc(c, stderr);
		} else if (c == '\n') {
			fprintf(stderr, "(\\n)");
		} else if (c == '\r') {
			fprintf(stderr, "(\\r)");
		} else if (c == 0x1b) {
			fprintf(stderr, "(\\e)");
		} else {
			fprintf(stderr, "(%02x)", c);
		}
	}
	putc('\n', stderr);
}

void csireset(void) { memset(&csiescseq, 0, sizeof(csiescseq)); }

void csihandle(void) {
	char buf[40];
	int len;

	//printf("scseq.mode: %c\n", csiescseq.mode[0]);//DBG
	switch (csiescseq.mode[0]) {
		default:
unknown:
			fprintf(stderr, "erresc: unknown csi ");
			csidump();
			/* die(""); */
			break;
		case '@': /* ICH -- Insert <n> blank char */
			DEFAULT(csiescseq.arg[0], 1);
			tinsertblank(csiescseq.arg[0]);
			break;
		case 'A': /* CUU -- Cursor <n> Up */
			DEFAULT(csiescseq.arg[0], 1);
			tmoveto(term->cursor.x, term->cursor.y - csiescseq.arg[0]);
			break;
		case 'B': /* CUD -- Cursor <n> Down */
		case 'e': /* VPR --Cursor <n> Down */
			DEFAULT(csiescseq.arg[0], 1);
			tmoveto(term->cursor.x, term->cursor.y + csiescseq.arg[0]);
			break;
		case 'i': /* MC -- Media Copy */
			switch (csiescseq.arg[0]) {
				case 0:
					tdump();
					break;
				case 1:
					tdumpline(term->cursor.y);
					break;
				case 2:
					tdumpsel();
					break;
				case 4:
					term->mode &= ~MODE_PRINT;
					break;
				case 5:
					term->mode |= MODE_PRINT;
					break;
			}
			break;
		case 'c': /* DA -- Device Attributes */
			if (csiescseq.arg[0] == 0) {
				ttywrite((utfchar*)vtiden, strlen(vtiden), 0);
			}
			break;
		case 'C': /* CUF -- Cursor <n> Forward */
		case 'a': /* HPR -- Cursor <n> Forward */
			DEFAULT(csiescseq.arg[0], 1);
			tmoveto(term->cursor.x + csiescseq.arg[0], term->cursor.y);
			break;
		case 'D': /* CUB -- Cursor <n> Backward */
			DEFAULT(csiescseq.arg[0], 1);
			tmoveto(term->cursor.x - csiescseq.arg[0], term->cursor.y);
			break;
		case 'E': /* CNL -- Cursor <n> Down and first col */
			DEFAULT(csiescseq.arg[0], 1);
			tmoveto(0, term->cursor.y + csiescseq.arg[0]);
			break;
		case 'F': /* CPL -- Cursor <n> Up and first col */
			DEFAULT(csiescseq.arg[0], 1);
			tmoveto(0, term->cursor.y - csiescseq.arg[0]);
			break;
		case 'g': /* TBC -- Tabulation clear */
			switch (csiescseq.arg[0]) {
				case 0: /* clear current tab stop */
					term->tabs[term->cursor.x] = 0;
					break;
				case 3: /* clear all the tabs */
					memset(term->tabs, 0, term->colalloc * sizeof(*term->tabs));
					break;
				default:
					goto unknown;
			}
			break;
		case 'G': /* CHA -- Move to <col> */
		case '`': /* HPA */
			DEFAULT(csiescseq.arg[0], 1);
			tmoveto(csiescseq.arg[0] - 1, term->cursor.y);
			break;
		case 'H': /* CUP -- Move to <row> <col> */
		case 'f': /* HVP */
			DEFAULT(csiescseq.arg[0], 1);
			DEFAULT(csiescseq.arg[1], 1);
			tmoveato(csiescseq.arg[1] - 1, csiescseq.arg[0] - 1);
			if ( ispagebased <0 ) ispagebased = 0;
			else ispagebased++;
			//printf("H ispagebased: %d\n",ispagebased);
			break;
		case 'I': /* CHT -- Cursor Forward Tabulation <n> tab stops */
			DEFAULT(csiescseq.arg[0], 1);
			tputtab(csiescseq.arg[0]);
			break;
		case 'J': /* ED -- Clear screen */
			switch (csiescseq.arg[0]) {
				case 0: /* below */
					tclearregion(term->cursor.x, term->cursor.y, term->colalloc - 1, term->cursor.y);
					if (term->cursor.y < term->rows - 1) {
						tclearregion(0, term->cursor.y + 1, term->colalloc - 1, term->rows - 1);
					}
					break;
				case 1: /* above */
					if (term->cursor.y > 1) {
						tclearregion(0, 0, term->cols - 1, term->cursor.y - 1);
					}
					tclearregion(0, term->cursor.y, term->cursor.x, term->cursor.y);
					break;
				case 2: /* all */
					tclearregion(0, 0, term->cols - 1, term->rows - 1);
					break;
				default:
					goto unknown;
			}
			break;
		case 'K': /* EL -- Clear line */
			if ( ispagebased <0 ) ispagebased = 0;
			else ispagebased++;
			//printf("K ispagebased: %d\n",ispagebased);

			switch (csiescseq.arg[0]) {
				case 0: /* right */
					tclearregion(term->cursor.x, term->cursor.y, term->colalloc - 1, term->cursor.y);
					break;
				case 1: /* left */
					tclearregion(0, term->cursor.y, term->cursor.x, term->cursor.y);
					break;
				case 2: /* all */
					tclearregion(0, term->cursor.y, term->colalloc - 1, term->cursor.y);
					break;
			}
			break;
		case 'S': /* SU -- Scroll <n> line up */
			DEFAULT(csiescseq.arg[0], 1);
			tscrollup(term->top, csiescseq.arg[0], 0);
			break;
		case 'T': /* SD -- Scroll <n> line down */
			DEFAULT(csiescseq.arg[0], 1);
			tscrolldown(term->top, csiescseq.arg[0], 0);
			break;
		case 'L': /* IL -- Insert <n> blank lines */
			DEFAULT(csiescseq.arg[0], 1);
			tinsertblankline(csiescseq.arg[0]);
			break;
		case 'l': /* RM -- Reset Mode */
			tsetmode(csiescseq.priv, 0, csiescseq.arg, csiescseq.narg);
			break;
		case 'M': /* DL -- Delete <n> lines */
			DEFAULT(csiescseq.arg[0], 1);
			tdeleteline(csiescseq.arg[0]);
			break;
		case 'X': /* ECH -- Erase <n> char */
			DEFAULT(csiescseq.arg[0], 1);
			tclearregion(term->cursor.x, term->cursor.y, term->cursor.x + csiescseq.arg[0] - 1, term->cursor.y);
			break;
		case 'P': /* DCH -- Delete <n> char */
			DEFAULT(csiescseq.arg[0], 1);
			//printf("Delc\n");
			tdeletechar(csiescseq.arg[0]);
			break;
		case 'Z': /* CBT -- Cursor Backward Tabulation <n> tab stops */
			DEFAULT(csiescseq.arg[0], 1);
			tputtab(-csiescseq.arg[0]);
			break;
		case 'd': /* VPA -- Move to <row> */
			DEFAULT(csiescseq.arg[0], 1);
			tmoveato(term->cursor.x, csiescseq.arg[0] - 1);
			break;
		case 'h': /* SM -- Set terminal mode */
			tsetmode(csiescseq.priv, 1, csiescseq.arg, csiescseq.narg);
			break;
		case 'm': /* SGR -- Terminal attribute (color) */
			tsetattr(csiescseq.arg, csiescseq.narg);
			break;
		case 'n': /* DSR – Device Status Report (cursor position) */
			if (csiescseq.arg[0] == 6) {
				len =
					snprintf(buf, sizeof(buf), "\033[%i;%iR", term->cursor.y + 1, term->cursor.x + 1);
				ttywrite((utfchar*)buf, len, 0);
			}
			break;
		case 'r': /* DECSTBM -- Set Scrolling Region */
			if (csiescseq.priv) {
				goto unknown;
			} else {
				DEFAULT(csiescseq.arg[0], 1);
				DEFAULT(csiescseq.arg[1], term->rows);
				tsetscroll(csiescseq.arg[0] - 1, csiescseq.arg[1] - 1);
				tmoveato(0, 0);
			}
			break;
		case 's': /* DECSC -- Save cursor position (ANSI.SYS) */
			tcursor(CURSOR_SAVE);
			printf("csave\n");
			break;
		case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
			tcursor(CURSOR_LOAD);
			break;
		case ' ':
			switch (csiescseq.mode[1]) {
				case 'q': /* DECSCUSR -- Set Cursor Style */
					if (xsetcursor(csiescseq.arg[0], csiescseq.arg[1] )) {
						goto unknown;
					}
					break;
				default:
					goto unknown;
			}
			break;
	}
}

void strhandle(void) {
	char *p = NULL, *dec;
	int j, narg, par;

	term->esc &= ~(ESC_STR_END | ESC_STR);
	strparse();
	par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0;

	switch (strescseq.type) {
		case ']': /* OSC -- Operating System Command */
			switch (par) {
				case 0:
				case 1:
				case 2:
					if (narg > 1) {
						xsettitle(strescseq.args[1]);
					}
					return;
				case 52:
					if (narg > 2) {
						dec = base64dec(strescseq.args[2]);
						if (dec) { // misc ?? this could make trouble, in theory
							xsetsel(dec);
							xclipcopy();
						} else {
							fprintf(stderr, "erresc: invalid base64\n");
						}
					}
					return;
				case 4: /* color set */
					if (narg < 3) {
						break;
					}
					p = strescseq.args[2];
					/* FALLTHROUGH */
				case 104: /* color reset, here p = NULL */
					j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
					if (xsetcolorname(j, p)) {
						if (par == 104 && narg <= 1) {
							return; /* color reset without parameter */
						}
						fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", j,
								p ? p : "(null)");
					} else {
						/*
						 * TODO if defaultbg color is changed, borders
						 * are dirty
						 */
						redraw();
					}
					return;
			}
			break;
		case 'k': /* old title set compatibility */
			xsettitle(strescseq.args[0]);
			return;
		case 'P': /* DCS -- Device Control String */
			term->mode |= ESC_DCS;
		case '_': /* APC -- Application Program Command */
		case '^': /* PM -- Privacy Message */
			return;
	}

	fprintf(stderr, "erresc: unknown str ");
	strdump();
}

// misc: handle control chars
// bin mode should go here.
void tcontrolcode(uchar ascii) {
	//printf("tcontrolcode: %d\n", ascii); //DBG
	switch (ascii) {
		case '\t': /* HT */
			tputtab(1);
			return;
		case '\b': /* BS */
			tmoveto(term->cursor.x - 1, term->cursor.y);
			return;
		case '\r': /* CR */
			tmoveto(0, term->cursor.y);
			if ( ispagebased > 20 ) ispagebased = 20;
			else	ispagebased--;
			return;
		case '\f': /* LF */
		case '\v': /* VT */
		case '\n': /* LF */
			/* go to first col if the mode is set */
			if ( ispagebased > 20 ) ispagebased = 20;
			else	ispagebased--;
			//printf("n : %d\n", ispagebased );
			tnewline(IS_SET(MODE_CRLF));
			return;
		case '\a': /* BEL */
			if (term->esc & ESC_STR_END) {
				/* backwards compatibility to xterm */
				strhandle();
			} else {
				xbell();
			}
			break;
		case '\033': /* ESC */
			csireset();
			term->esc &= ~(ESC_CSI | ESC_ALTCHARSET | ESC_TEST);
			term->esc |= ESC_START;
			return;
		case '\016': /* SO (LS1 -- Locking shift 1) */
		case '\017': /* SI (LS0 -- Locking shift 0) */
			term->charset = 1 - (ascii - '\016'); // todo: handle charset
			return;
		case '\032': /* SUB */
			tsetchar('?', &term->cursor.attr, term->cursor.x, term->cursor.y);
		case '\030': /* CAN */
			csireset();
			break;
		case '\005': /* ENQ (IGNORED) */
		case '\000': /* NUL (IGNORED) */
		case '\021': /* XON (IGNORED) */
		case '\023': /* XOFF (IGNORED) */
		case 0177:   /* DEL (IGNORED) */
			return;
		case 0x80: /* TODO: PAD */
		case 0x81: /* TODO: HOP */
		case 0x82: /* TODO: BPH */
		case 0x83: /* TODO: NBH */
		case 0x84: /* TODO: IND */
			break;
		case 0x85:     /* NEL -- Next line */
			tnewline(1); /* always go to first col */
			break;
		case 0x86: /* TODO: SSA */
		case 0x87: /* TODO: ESA */
			break;
		case 0x88: /* HTS -- Horizontal tab stop */
			term->tabs[term->cursor.x] = 1;
			break;
		case 0x89: /* TODO: HTJ */
		case 0x8a: /* TODO: VTS */
		case 0x8b: /* TODO: PLD */
		case 0x8c: /* TODO: PLU */
		case 0x8d: /* TODO: RI */
		case 0x8e: /* TODO: SS2 */
		case 0x8f: /* TODO: SS3 */
		case 0x91: /* TODO: PU1 */
		case 0x92: /* TODO: PU2 */
		case 0x93: /* TODO: STS */
		case 0x94: /* TODO: CCH */
		case 0x95: /* TODO: MW */
		case 0x96: /* TODO: SPA */
		case 0x97: /* TODO: EPA */
		case 0x98: /* TODO: SOS */
		case 0x99: /* TODO: SGCI */
			break;
		case 0x9a: /* DECID -- Identify Terminal */
			ttywrite((utfchar*)vtiden, strlen(vtiden), 0);
			break;
		case 0x9b: /* TODO: CSI */
		case 0x9c: /* TODO: ST */
			break;
		case 0x90: /* DCS -- Device Control String */
		case 0x9d: /* OSC -- Operating System Command */
		case 0x9e: /* PM -- Privacy Message */
		case 0x9f: /* APC -- Application Program Command */
			tstrsequence(ascii);
			return;
	}
	/* only CAN, SUB, \a and C1 chars interrupt a sequence */
	term->esc &= ~(ESC_STR_END | ESC_STR);
}

/*
 * returns 1 when the sequence is finished and it hasn't to read
 * more characters for this sequence, otherwise 0
 */
int eschandle(uchar ascii) {
	//printf("eschandle: %c\n", ascii); //DBG
	switch (ascii) {
		case '[':
			term->esc |= ESC_CSI;
			return 0;
		case '#':
			term->esc |= ESC_TEST;
			return 0;
		case '%':
			term->esc |= ESC_UTF8;
			return 0;
		case 'P': /* DCS -- Device Control String */
		case '_': /* APC -- Application Program Command */
		case '^': /* PM -- Privacy Message */
		case ']': /* OSC -- Operating System Command */
		case 'k': /* old title set compatibility */
			tstrsequence(ascii);
			return 0;
		case 'n': /* LS2 -- Locking shift 2 */
		case 'o': /* LS3 -- Locking shift 3 */
			term->charset = 2 + (ascii - 'n');
			break;
		case '(': /* GZD4 -- set primary charset G0 */
		case ')': /* G1D4 -- set secondary charset G1 */
		case '*': /* G2D4 -- set tertiary charset G2 */
		case '+': /* G3D4 -- set quaternary charset G3 */
			term->icharset = ascii - '(';
			term->esc |= ESC_ALTCHARSET;
			return 0;
		case 'D': /* IND -- Linefeed */
			if (term->cursor.y == term->bot) {
				tscrollup(term->top, 1, 1);
			} else {
				tmoveto(term->cursor.x, term->cursor.y + 1);
			}
			break;
		case 'E':      /* NEL -- Next line */
			tnewline(1); /* always go to first col */
			break;
		case 'H': /* HTS -- Horizontal tab stop */
			term->tabs[term->cursor.x] = 1;
			break;
		case 'M': /* RI -- Reverse index */
			if (term->cursor.y == term->top) {
				tscrolldown(term->top, 1, 1);
			} else {
				tmoveto(term->cursor.x, term->cursor.y - 1);
			}
			break;
		case 'Z': /* DECID -- Identify Terminal */
			ttywrite((utfchar*)vtiden, strlen(vtiden), 0);
			break;
		case 'c': /* RIS -- Reset to initial state */
			treset();
			resettitle();
			xloadcolors();
			break;
		case '=': /* DECPAM -- Application keypad */
			xsetmode(1, MODE_APPKEYPAD);
			break;
		case '>': /* DECPNM -- Normal keypad */
			xsetmode(0, MODE_APPKEYPAD);
			break;
		case '7': /* DECSC -- Save Cursor */
			tcursor(CURSOR_SAVE);
			break;
		case '8': /* DECRC -- Restore Cursor */
			tcursor(CURSOR_LOAD);
			break;
		case '\\': /* ST -- String Terminator */
			if (term->esc & ESC_STR_END) {
				strhandle();
			}
			break;
		default:
			fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n", (uchar)ascii,
					isprint(ascii) ? ascii : '.');
			break;
	}
	return 1;
}

void tsetmode(int priv, int set, int *args, int narg) {
	int alt, *lim;

	for (lim = args + narg; args < lim; ++args) {
		if (priv) {
			switch (*args) {
				case 1: /* DECCKM -- Cursor key */
					xsetmode(set, MODE_APPCURSOR);
					break;
				case 5: /* DECSCNM -- Reverse video */
					xsetmode(set, MODE_REVERSE);
					break;
				case 6: /* DECOM -- Origin */
					MODBIT(term->cursor.state, set, CURSOR_ORIGIN);
					tmoveato(0, 0);
					break;
				case 7: /* DECAWM -- Auto wrap */
					MODBIT(term->mode, set, MODE_WRAP);
					break;
				case 0:  /* Error (IGNORED) */
				case 2:  /* DECANM -- ANSI/VT52 (IGNORED) */
				case 3:  /* DECCOLM -- Column  (IGNORED) */
				case 4:  /* DECSCLM -- Scroll (IGNORED) */
				case 8:  /* DECARM -- Auto repeat (IGNORED) */
				case 18: /* DECPFF -- Printer feed (IGNORED) */
				case 19: /* DECPEX -- Printer extent (IGNORED) */
				case 42: /* DECNRCM -- National characters (IGNORED) */
				case 12: /* att610 -- Start blinking cursor (IGNORED) */
					break;
				case 25: /* DECTCEM -- Text Cursor Enable Mode */
					xsetmode(!set, MODE_HIDE);
					break;
				case 9: /* X10 mouse compatibility mode */
					xsetpointermotion(0);
					xsetmode(0, MODE_MOUSE);
					xsetmode(set, MODE_MOUSEX10);
					break;
				case 1000: /* 1000: report button press */
					xsetpointermotion(0);
					xsetmode(0, MODE_MOUSE);
					xsetmode(set, MODE_MOUSEBTN);
					break;
				case 1002: /* 1002: report motion on button press */
					xsetpointermotion(0);
					xsetmode(0, MODE_MOUSE);
					xsetmode(set, MODE_MOUSEMOTION);
					break;
				case 1003: /* 1003: enable all mouse motions */
					xsetpointermotion(set);
					xsetmode(0, MODE_MOUSE);
					xsetmode(set, MODE_MOUSEMANY);
					break;
				case 1004: /* 1004: send focus events to tty */
					xsetmode(set, MODE_FOCUS);
					break;
				case 1006: /* 1006: extended reporting mode */
					xsetmode(set, MODE_MOUSESGR);
					break;
				case 1034:
					xsetmode(set, MODE_8BIT);
					break;
				case 1049: /* swap screen & set/restore cursor as xterm */
					if (!allowaltscreen) {
						break;
					}
					tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
					/* FALLTHROUGH */
				case 47: /* swap screen */
				case 1047:
					if (!allowaltscreen) {
						break;
					}
					alt = IS_SET(MODE_ALTSCREEN);
					if (alt) {
						tclearregion(0, 0, term->cols - 1, term->rows - 1);
					}
					if (set ^ alt) { /* set is always 1 or 0 */
						tswapscreen();
					}
					if (*args != 1049) {
						break;
					}
					/* FALLTHROUGH */
				case 1048:
					tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
					break;
				case 2004: /* 2004: bracketed paste mode */
					xsetmode(set, MODE_BRCKTPASTE);
					break;
					/* Not implemented mouse modes. See comments there. */
				case 1001: /* mouse highlight mode; can hang the
								  terminal by design when implemented. */
				case 1005: /* UTF-8 mouse mode; will confuse
								  applications not supporting UTF-8
								  and luit. */
				case 1015: /* urxvt mangled mouse mode; incompatible
								  and can be mistaken for other control
								  codes. */
					break;
				default:
					fprintf(stderr, "erresc: unknown private set/reset mode %d\n", *args);
					break;
			}
		} else {
			switch (*args) {
				case 0: /* Error (IGNORED) */
					break;
				case 2:
					xsetmode(set, MODE_KBDLOCK);
					break;
				case 4: /* IRM -- Insertion-replacement */
					MODBIT(term->mode, set, MODE_INSERT);
					break;
				case 12: /* SRM -- Send/Receive */
					MODBIT(term->mode, !set, MODE_ECHO);
					break;
				case 20: /* LNM -- Linefeed/new line */
					MODBIT(term->mode, set, MODE_CRLF);
					break;
				default:
					fprintf(stderr, "erresc: unknown set/reset mode %d\n", *args);
					break;
			}
		}
	}
}

void tdefutf8(utfchar ascii) {
#ifdef UTF8
	if (ascii == 'G')
		term->mode |= MODE_UTF8;
	else
		if (ascii == '@') {
			term->mode &= ~MODE_UTF8;
		}
#endif
}

void tdeftran(utfchar ascii) {
	static char cs[] = "0B";
	static int vcs[] = {CS_GRAPHIC0, CS_USA};
	char *p;

	if ((p = strchr(cs, ascii)) == NULL) {
		fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
	} else {
		term->trantbl[term->icharset] = vcs[p - cs];
	}
}


code:
// handle control chars and sequences, ansi escape sequences.
//

#pragma once

#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == 0x7f) // 0x7f = delete

//#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
#define ISCONTROLC1(c) (0)

#define ISCONTROL(c) ((c <= 0x1f) || (c==0x7f))
//#define ISCONTROL(c) ((c <= 0x1f) || BETWEEN(c, 0x7f, 0x9f))
//#define ISCONTROL(c) (0)

#define ESC_BUF_SIZ (256 * UTF_SIZ) // UTF_SIZ is 4 with utf8, 1 without
#define ESC_ARG_SIZ 16
#define STR_BUF_SIZ ESC_BUF_SIZ
#define STR_ARG_SIZ ESC_ARG_SIZ

enum escape_state {
  ESC_START = 1,
  ESC_CSI = 2,
  ESC_STR = 4, /* OSC, PM, APC */
  ESC_ALTCHARSET = 8,
  ESC_STR_END = 16, /* a final string was encountered */
  ESC_TEST = 32,    /* Enter in test mode */
  ESC_UTF8 = 64,
  ESC_DCS = 128,
};

/* CSI Escape sequence structs */
/* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
typedef struct {
  char buf[ESC_BUF_SIZ]; /* raw string */
  size_t len;            /* raw string length */
  char priv;
  int arg[ESC_ARG_SIZ];
  int narg; /* nb of args */
  char mode[2];
} CSIEscape;

/* STR Escape sequence structs */
/* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
typedef struct {
  char type;  /* ESC type ... */
  char *buf;  /* allocated raw string */
  size_t siz; /* allocation size */
  size_t len; /* raw string length */
  char *args[STR_ARG_SIZ];
  int narg; /* nb of args */
} STREscape;

#ifdef UTF8
int handle_controlchars( Rune u, uint decoded_len, char* decoded_char );
#else
int _handle_controlchars( Rune u );
#define handle_controlchars( _rune, ... ) _handle_controlchars( _rune )
#endif

static void tdefutf8(utfchar);
static void tdeftran(utfchar);
static void tsetmode(int, int, int *, int);

static void tstrsequence(uchar);
static void tcontrolcode(uchar);

static void csidump(void);
static void csihandle(void);
static void csiparse(void);
static void csireset(void);
static int eschandle(uchar);

static void strdump(void);
static void strparse(void);
static void strreset(void);