Ticket #1819: linux-2.6.17.7-utf8_input-1.patch

File linux-2.6.17.7-utf8_input-1.patch, 10.7 KB (added by Matthew Burgess, 18 years ago)

update linux utf-8 patch

  • drivers/char/consolemap.c

    Submitted by: Alexander E. Patrakov <patrakov@ums.usu.ru>
    Signed-off-by: Alexander E. Patrakov <patrakov@ums.usu.ru>
    Date: 2006-07-24
    Initial Package Version: 2.6.17.6
    Upstream Status: Rejected: they say it modifies the meaning of an existing ioctl
    Origin: http://chris.heathens.co.nz/linux/downloads/patches-2.6.4-cdh1.tar.gz
            Porting to linux-2.6.16 by Alexander E. Patrakov
    Description: This patch fixes dead keys and copy/paste of non-ASCII characters
                 in UTF-8 mode on Linux console.
                 See more details about the original patch at:
                 http://chris.heathens.co.nz/linux/utf8.html
    
    diff -Naur linux-2.6.17.6.orig/drivers/char/consolemap.c linux-2.6.17.6/drivers/char/consolemap.c
    old new  
    178178        unsigned long   refcount;
    179179        unsigned long   sum;
    180180        unsigned char   *inverse_translations[4];
     181        u16             *inverse_trans_unicode;
    181182        int             readonly;
    182183};
    183184
     
    208209        }
    209210}
    210211
     212static void set_inverse_trans_unicode(struct vc_data *conp,
     213                                      struct uni_pagedir *p)
     214{
     215        int i, j, k, glyph;
     216        u16 **p1, *p2;
     217        u16 *q;
     218       
     219        if (!p) return;
     220        q = p->inverse_trans_unicode;
     221        if (!q) {
     222                q = p->inverse_trans_unicode =
     223                        kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL);
     224                if (!q)
     225                        return;
     226        }
     227        memset(q, 0, MAX_GLYPH * sizeof(u16));
     228
     229        for (i = 0; i < 32; i++) {
     230                p1 = p->uni_pgdir[i];
     231                if (!p1)
     232                        continue;
     233                for (j = 0; j < 32; j++) {
     234                        p2 = p1[j];
     235                        if (!p2)
     236                                continue;
     237                        for (k = 0; k < 64; k++) {
     238                                glyph = p2[k];
     239                                if (glyph >= 0 && glyph < MAX_GLYPH
     240                                               && q[glyph] < 32)
     241                                        q[glyph] = (i << 11) + (j << 6) + k;
     242                        }
     243                }
     244        }
     245}
     246
    211247unsigned short *set_translate(int m, struct vc_data *vc)
    212248{
    213249        inv_translate[vc->vc_num] = m;
     
    218254 * Inverse translation is impossible for several reasons:
    219255 * 1. The font<->character maps are not 1-1.
    220256 * 2. The text may have been written while a different translation map
    221  *    was active, or using Unicode.
     257 *    was active.
    222258 * Still, it is now possible to a certain extent to cut and paste non-ASCII.
    223259 */
    224 unsigned char inverse_translate(struct vc_data *conp, int glyph)
     260u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
    225261{
    226262        struct uni_pagedir *p;
     263        int m;
    227264        if (glyph < 0 || glyph >= MAX_GLYPH)
    228265                return 0;
    229         else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) ||
    230                  !p->inverse_translations[inv_translate[conp->vc_num]])
     266        else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
    231267                return glyph;
    232         else
    233                 return p->inverse_translations[inv_translate[conp->vc_num]][glyph];
     268        else if (use_unicode) {
     269                if (!p->inverse_trans_unicode)
     270                        return glyph;
     271                else
     272                        return p->inverse_trans_unicode[glyph];
     273        } else {
     274                m = inv_translate[conp->vc_num];
     275                if (!p->inverse_translations[m])
     276                        return glyph;
     277                else
     278                        return p->inverse_translations[m][glyph];
     279        }
    234280}
    235281
    236282static void update_user_maps(void)
     
    244290                p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
    245291                if (p && p != q) {
    246292                        set_inverse_transl(vc_cons[i].d, p, USER_MAP);
     293                        set_inverse_trans_unicode(vc_cons[i].d, p);
    247294                        q = p;
    248295                }
    249296        }
     
    354401                kfree(p->inverse_translations[i]);
    355402                p->inverse_translations[i] = NULL;
    356403        }
     404        if (p->inverse_trans_unicode) {
     405                kfree(p->inverse_trans_unicode);
     406                p->inverse_trans_unicode = NULL;
     407        }
    357408}
    358409
    359410void con_free_unimap(struct vc_data *vc)
     
    512563
    513564        for (i = 0; i <= 3; i++)
    514565                set_inverse_transl(vc, p, i); /* Update all inverse translations */
     566        set_inverse_trans_unicode(vc, p);
    515567 
    516568        return err;
    517569}
     
    562614
    563615        for (i = 0; i <= 3; i++)
    564616                set_inverse_transl(vc, p, i);   /* Update all inverse translations */
     617        set_inverse_trans_unicode(vc, p);
    565618        dflt = p;
    566619        return err;
    567620}
     
    618671                p->readonly = rdonly;
    619672}
    620673
     674/* may be called during an interrupt */
     675u32 conv_8bit_to_uni(unsigned char c)
     676{
     677        /*
     678         * Always use USER_MAP. This function is used by the keyboard,
     679         * which shouldn't be affected by G0/G1 switching, etc.
     680         * If the user map still contains default values, i.e. the
     681         * direct-to-font mapping, then assume user is using Latin1.
     682         */
     683        unsigned short uni = translations[USER_MAP][c];
     684        return uni == (0xf000 | c) ? c : uni;
     685}
     686
    621687int
    622688conv_uni_to_pc(struct vc_data *conp, long ucs)
    623689{
  • drivers/char/keyboard.c

    diff -Naur linux-2.6.17.6.orig/drivers/char/keyboard.c linux-2.6.17.6/drivers/char/keyboard.c
    old new  
    3434#include <linux/init.h>
    3535#include <linux/slab.h>
    3636
     37#include <linux/consolemap.h>
    3738#include <linux/kbd_kern.h>
    3839#include <linux/kbd_diacr.h>
    3940#include <linux/vt_kern.h>
     
    329330 * Many other routines do put_queue, but I think either
    330331 * they produce ASCII, or they produce some user-assigned
    331332 * string, and in both cases we might assume that it is
    332  * in utf-8 already. UTF-8 is defined for words of up to 31 bits,
    333  * but we need only 16 bits here
     333 * in utf-8 already.
    334334 */
    335 static void to_utf8(struct vc_data *vc, ushort c)
     335static void to_utf8(struct vc_data *vc, uint c)
    336336{
    337337        if (c < 0x80)
    338338                /*  0******* */
     
    341341                /* 110***** 10****** */
    342342                put_queue(vc, 0xc0 | (c >> 6));
    343343                put_queue(vc, 0x80 | (c & 0x3f));
    344         } else {
     344        } else if (c < 0x10000) {
     345                if (c >= 0xD800 && c < 0xE000)
     346                        return;
     347                if (c == 0xFFFF)
     348                        return;
    345349                /* 1110**** 10****** 10****** */
    346350                put_queue(vc, 0xe0 | (c >> 12));
    347351                put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
    348352                put_queue(vc, 0x80 | (c & 0x3f));
     353        } else if (c < 0x110000) {
     354                /* 11110*** 10****** 10****** 10****** */
     355                put_queue(vc, 0xf0 | (c >> 18));
     356                put_queue(vc, 0x80 | ((c >> 12) & 0x3f));
     357                put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
     358                put_queue(vc, 0x80 | (c & 0x3f));
    349359        }
    350360}
    351361
     362static void put_8bit(struct vc_data *vc, u8 c)
     363{
     364        if (kbd->kbdmode != VC_UNICODE || c < 32 || c == 127)
     365                /* Don't translate control chars */
     366                put_queue(vc, c);
     367        else
     368                to_utf8(vc, conv_8bit_to_uni(c));
     369}
     370
    352371/*
    353372 * Called after returning from RAW mode or when changing consoles - recompute
    354373 * shift_down[] and shift_state from key_down[] maybe called when keymap is
     
    416435        if (kbd->kbdmode == VC_UNICODE)
    417436                to_utf8(vc, d);
    418437        else if (d < 0x100)
    419                 put_queue(vc, d);
     438                put_8bit(vc, d);
    420439
    421440        return ch;
    422441}
     
    430449                if (kbd->kbdmode == VC_UNICODE)
    431450                        to_utf8(vc, diacr);
    432451                else if (diacr < 0x100)
    433                         put_queue(vc, diacr);
     452                        put_8bit(vc, diacr);
    434453                diacr = 0;
    435454        }
    436455        put_queue(vc, 13);
     
    798817        /* kludge */
    799818        if (up_flag && shift_state != old_state && npadch != -1) {
    800819                if (kbd->kbdmode == VC_UNICODE)
    801                         to_utf8(vc, npadch & 0xffff);
     820                        to_utf8(vc, npadch);
    802821                else
    803822                        put_queue(vc, npadch & 0xff);
    804823                npadch = -1;
  • drivers/char/selection.c

    diff -Naur linux-2.6.17.6.orig/drivers/char/selection.c linux-2.6.17.6/drivers/char/selection.c
    old new  
    2020
    2121#include <asm/uaccess.h>
    2222
     23#include <linux/kbd_kern.h>
    2324#include <linux/vt_kern.h>
    2425#include <linux/consolemap.h>
    2526#include <linux/selection.h>
     
    3435/* Variables for selection control. */
    3536/* Use a dynamic buffer, instead of static (Dec 1994) */
    3637struct vc_data *sel_cons;               /* must not be disallocated */
     38static int use_unicode;
    3739static volatile int sel_start = -1;     /* cleared by clear_selection */
    3840static int sel_end;
    3941static int sel_buffer_lth;
     
    5456        complement_pos(sel_cons, where);
    5557}
    5658
    57 static unsigned char
     59static u16
    5860sel_pos(int n)
    5961{
    60         return inverse_translate(sel_cons, screen_glyph(sel_cons, n));
     62        return inverse_translate(sel_cons, screen_glyph(sel_cons, n),
     63                                use_unicode);
    6164}
    6265
    6366/* remove the current selection highlight, if any,
     
    8689  0xFF7FFFFF  /* latin-1 accented letters, not division sign */
    8790};
    8891
    89 static inline int inword(const unsigned char c) {
    90         return ( inwordLut[c>>5] >> (c & 0x1F) ) & 1;
     92static inline int inword(const u16 c) {
     93        return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
    9194}
    9295
    9396/* set inwordLut contents. Invoked by ioctl(). */
     
    108111        return (v > u) ? u : v;
    109112}
    110113
     114/* stores the char in UTF8 and returns the number of bytes used (1-3) */
     115int store_utf8(u16 c, char *p)
     116{
     117        if (c < 0x80) {
     118                /*  0******* */
     119                p[0] = c;
     120                return 1;
     121        } else if (c < 0x800) {
     122                /* 110***** 10****** */
     123                p[0] = 0xc0 | (c >> 6);
     124                p[1] = 0x80 | (c & 0x3f);
     125                return 2;
     126        } else {
     127                /* 1110**** 10****** 10****** */
     128                p[0] = 0xe0 | (c >> 12);
     129                p[1] = 0x80 | ((c >> 6) & 0x3f);
     130                p[2] = 0x80 | (c & 0x3f);
     131                return 3;
     132        }
     133}
     134
    111135/* set the current selection. Invoked by ioctl() or by kernel code. */
    112136int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
    113137{
    114138        struct vc_data *vc = vc_cons[fg_console].d;
    115139        int sel_mode, new_sel_start, new_sel_end, spc;
    116140        char *bp, *obp;
    117         int i, ps, pe;
     141        int i, ps, pe, multiplier;
     142        u16 c;
     143        struct kbd_struct *kbd = kbd_table + fg_console;
    118144
    119145        poke_blanked_console();
    120146
     
    158184                clear_selection();
    159185                sel_cons = vc_cons[fg_console].d;
    160186        }
    161 
     187        use_unicode = kbd && kbd->kbdmode == VC_UNICODE;
     188       
    162189        switch (sel_mode)
    163190        {
    164191                case TIOCL_SELCHAR:     /* character-by-character selection */
     
    240267        sel_end = new_sel_end;
    241268
    242269        /* Allocate a new buffer before freeing the old one ... */
    243         bp = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL);
     270        multiplier = use_unicode ? 3 : 1;  /* chars can take up to 3 bytes */
     271        bp = kmalloc((sel_end-sel_start)/2*multiplier+1, GFP_KERNEL);
    244272        if (!bp) {
    245273                printk(KERN_WARNING "selection: kmalloc() failed\n");
    246274                clear_selection();
     
    251279
    252280        obp = bp;
    253281        for (i = sel_start; i <= sel_end; i += 2) {
    254                 *bp = sel_pos(i);
    255                 if (!isspace(*bp++))
     282                c = sel_pos(i);
     283                if (use_unicode)
     284                        bp += store_utf8(c, bp);
     285                else
     286                        *bp++ = c;
     287                if (!isspace(c))
    256288                        obp = bp;
    257289                if (! ((i + 2) % vc->vc_size_row)) {
    258290                        /* strip trailing blanks from line and add newline,
  • include/linux/consolemap.h

    diff -Naur linux-2.6.17.6.orig/include/linux/consolemap.h linux-2.6.17.6/include/linux/consolemap.h
    old new  
    1010
    1111struct vc_data;
    1212
    13 extern unsigned char inverse_translate(struct vc_data *conp, int glyph);
     13extern u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode);
    1414extern unsigned short *set_translate(int m, struct vc_data *vc);
    1515extern int conv_uni_to_pc(struct vc_data *conp, long ucs);
     16extern u32 conv_8bit_to_uni(unsigned char c);