Changeset 3989


Ignore:
Timestamp:
11/21/09 15:58:11 (3 years ago)
Author:
jylam
Message:
  • Handle 'interleaved' control characters INSIDE a CSI command. vttest uses that, can't find anything nor in ECMA-48 or XTerm sources, but it seems we have to handle it anyway.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • neercs/trunk/src/term.c

    r3988 r3989  
    125125                            unsigned int, unsigned int const *); 
    126126 
     127static int handle_single_char(unsigned char c, int *x, int *y, 
     128                               struct screen_list *screen_list, 
     129                               struct screen *sc); 
     130 
     131static int handle_single_char(unsigned char c, int *x, int *y, 
     132                               struct screen_list *screen_list, 
     133                               struct screen *sc) 
     134{ 
     135    if (c == '\r') 
     136    { 
     137        *x = 0; 
     138    } 
     139 
     140    else if (c == '\n') 
     141    { 
     142        *x = 0; 
     143        *y = *y + 1; 
     144    } 
     145    else if (c == '\a') 
     146    { 
     147        if (!sc->bell) 
     148            screen_list->in_bell++; 
     149        sc->bell = 1; 
     150    } 
     151 
     152    else if (c == '\t') 
     153    { 
     154        *x = (*x + 7) & ~7; 
     155    } 
     156 
     157    else if (c == '\x08') 
     158    { 
     159        if (*x > 0) 
     160            *x = *x - 1; 
     161    } 
     162 
     163    else if (c == '\x0e') 
     164    { 
     165        /* Shift Out (Ctrl-N) -> Switch to Alternate Character Set: invokes 
     166           the G1 character set. */ 
     167        sc->conv_state.glr[0] = 1; 
     168    } 
     169 
     170    else if (c == '\x0f') 
     171    { 
     172        /* Shift In (Ctrl-O) -> Switch to Standard Character Set: invokes the 
     173           G0 character set. */ 
     174        sc->conv_state.glr[0] = 0; 
     175    } 
     176    else  
     177    { 
     178        return 1;     
     179    } 
     180        return 0; 
     181 
     182} 
     183 
    127184long int import_term(struct screen_list *screen_list, struct screen *sc, 
    128185                     void const *data, unsigned int size) 
     
    166223        skip = 1; 
    167224 
    168         if (buffer[i] == '\r') 
    169         { 
    170             x = 0; 
    171         } 
    172  
    173         else if (buffer[i] == '\n') 
    174         { 
    175             x = 0; 
    176             y++; 
    177         } 
    178         else if (buffer[i] == '\a') 
    179         { 
    180             if (!sc->bell) 
    181                 screen_list->in_bell++; 
    182             sc->bell = 1; 
    183         } 
    184  
    185         else if (buffer[i] == '\t') 
    186         { 
    187             x = (x + 7) & ~7; 
    188         } 
    189  
    190         else if (buffer[i] == '\x08') 
    191         { 
    192             if (x > 0) 
    193                 x--; 
    194         } 
    195  
    196         else if (buffer[i] == '\x0e') 
    197         { 
    198             /* Shift Out (Ctrl-N) -> Switch to Alternate Character Set: 
    199                invokes the G1 character set. */ 
    200             sc->conv_state.glr[0] = 1; 
    201         } 
    202  
    203         else if (buffer[i] == '\x0f') 
    204         { 
    205             /* Shift In (Ctrl-O) -> Switch to Standard Character Set: invokes 
    206                the G0 character set. */ 
    207             sc->conv_state.glr[0] = 0; 
    208         } 
     225#define ASCCHAR(c) (c>31&&c<127)?c:'?' 
     226        if (buffer[i] == '\033') 
     227        { 
     228            debug("ansi ESC : '%c%c%c%c%c'\n", 
     229                  ASCCHAR(buffer[i + 1]), 
     230                  ASCCHAR(buffer[i + 2]), 
     231                  ASCCHAR(buffer[i + 3]), 
     232                  ASCCHAR(buffer[i + 4]), ASCCHAR(buffer[i + 5])); 
     233        } 
     234 
     235        if(!handle_single_char(buffer[i], &x, &y, screen_list, sc))  
     236        {} 
     237 
    209238 
    210239        /* If there are not enough characters to parse the escape sequence, 
    211240           wait until the next try. We require 3. */ 
    212         else if (buffer[i] == '\033' && i + 2 >= size) 
    213             break; 
     241         
     242    else if (buffer[i] == '\033' && i + 2 >= size) 
     243        break; 
    214244 
    215245        /* Single Shift Select of G2 Character Set (SS2: 0x8e): affects next 
    216246           character only */ 
    217         else if (buffer[i] == '\033' && buffer[i + 1] == 'N') 
    218         { 
    219             sc->conv_state.ss = 2; 
    220             skip += 1; 
    221         } 
     247    else if (buffer[i] == '\033' && buffer[i + 1] == 'N') 
     248    { 
     249        sc->conv_state.ss = 2; 
     250        skip += 1; 
     251    } 
    222252        /* Reverse Index (RI) go up one line, reverse scroll if necessary */ 
    223         else if (buffer[i] == '\033' && buffer[i + 1] == 'M') 
    224         { 
    225             /* FIXME : not sure about the meaning of 'go up one line' and 'if 
    226                necessary' words. Implemented as a scroller only. */ 
    227             for (j = bottom - 1; j > top; j--) 
     253    else if (buffer[i] == '\033' && buffer[i + 1] == 'M') 
     254    { 
     255        /* FIXME : not sure about the meaning of 'go up one line' and 'if 
     256           necessary' words. Implemented as a scroller only. */ 
     257        for (j = bottom - 1; j > top; j--) 
     258        { 
     259            for (k = 0; k < width; k++) 
     260            { 
     261                caca_put_char(sc->cv, k, j, caca_get_char(sc->cv, k, j - 1)); 
     262                caca_put_attr(sc->cv, k, j, caca_get_attr(sc->cv, k, j - 1)); 
     263            } 
     264        } 
     265        caca_draw_line(sc->cv, 0, top - 1, width - 1, top - 1, ' '); 
     266        skip += 1; 
     267    } 
     268 
     269        /* Single Shift Select of G3 Character Set (SS2: 0x8f): affects next 
     270           character only */ 
     271    else if (buffer[i] == '\033' && buffer[i + 1] == 'O') 
     272    { 
     273        sc->conv_state.ss = 3; 
     274        skip += 1; 
     275    } 
     276 
     277        /* LOCKING-SHIFT TWO (LS2), ISO 2022, ECMA-48 (1986), ISO 6429 : 1988 */ 
     278    else if (buffer[i] == '\033' && buffer[i + 1] == 'n') 
     279    { 
     280        sc->conv_state.glr[0] = 2; 
     281        skip += 1; 
     282    } 
     283 
     284        /* LOCKING-SHIFT THREE (LS3) ISO 2022, ECMA-48 (1986), ISO 6429 : 1988  
     285         */ 
     286    else if (buffer[i] == '\033' && buffer[i + 1] == 'o') 
     287    { 
     288        sc->conv_state.glr[0] = 3; 
     289        skip += 1; 
     290    } 
     291 
     292        /* RESET TO INITIAL STATE (RIS), ECMA-48 (1986), ISO 6429 : 1988 */ 
     293    else if (buffer[i] == '\033' && buffer[i + 1] == 'c') 
     294    { 
     295        sc->dfg = CACA_DEFAULT; 
     296        sc->dbg = CACA_DEFAULT; 
     297 
     298        caca_set_color_ansi(sc->cv, sc->dfg, sc->dbg); 
     299        sc->clearattr = caca_get_attr(sc->cv, -1, -1); 
     300        ansi_parse_grcm(sc, 1, &dummy); 
     301 
     302        reset_conv_state(sc); 
     303        skip += 1; 
     304    } 
     305 
     306        /* Coding Method Delimiter (CMD), ECMA-48 (1991), ISO/IEC 6429:1992 
     307           (ISO IR 189) */ 
     308    else if (buffer[i] == '\033' && buffer[i + 1] == 'd') 
     309    { 
     310        reset_conv_state(sc); 
     311        skip += 1; 
     312    } 
     313 
     314        /* GZDM4, G0-Designators, multi, 94^n chars [grandfathered short form 
     315           from ISO 2022:1986] */ 
     316    else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
     317             && (buffer[i + 2] >= '@') && (buffer[i + 2] <= 'C')) 
     318    { 
     319        sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 2]); 
     320        skip += 2; 
     321    } 
     322 
     323        /* GnDMx Gn-Designators, 9x^n chars; need one more char to distinguish  
     324           these */ 
     325    else if (buffer[i] == '\033' && buffer[i + 1] == '$' && (i + 3 >= size)) 
     326        break; 
     327 
     328        /* GZD4 G0-Designator, 94 chars */ 
     329    else if (buffer[i] == '\033' && buffer[i + 1] == '(') 
     330    { 
     331        sc->conv_state.gn[0] = buffer[i + 2]; 
     332        skip += 2; 
     333    } 
     334 
     335        /* G1D4 G1-Designator, 94 chars */ 
     336    else if (buffer[i] == '\033' && buffer[i + 1] == ')') 
     337    { 
     338        sc->conv_state.gn[1] = buffer[i + 2]; 
     339        skip += 2; 
     340    } 
     341 
     342        /* G2D4 G2-Designator, 94 chars */ 
     343    else if (buffer[i] == '\033' && buffer[i + 1] == '*') 
     344    { 
     345        sc->conv_state.gn[2] = buffer[i + 2]; 
     346        skip += 2; 
     347    } 
     348 
     349        /* G3D4 G3-Designator, 94 chars */ 
     350    else if (buffer[i] == '\033' && buffer[i + 1] == '+') 
     351    { 
     352        sc->conv_state.gn[3] = buffer[i + 2]; 
     353        skip += 2; 
     354    } 
     355 
     356        /* G2D6 G2-Designator, 96 chars */ 
     357    else if (buffer[i] == '\033' && buffer[i + 1] == '.') 
     358    { 
     359        sc->conv_state.gn[2] = LITERAL2CHAR('.', buffer[i + 2]); 
     360        skip += 2; 
     361    } 
     362 
     363        /* G3D6 G3-Designator, 96 chars */ 
     364    else if (buffer[i] == '\033' && buffer[i + 1] == '/') 
     365    { 
     366        sc->conv_state.gn[3] = LITERAL2CHAR('.', buffer[i + 2]); 
     367        skip += 2; 
     368    } 
     369 
     370        /* GZDM4 G0-Designator, 94^n chars */ 
     371    else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
     372             && buffer[i + 2] == '(') 
     373    { 
     374        sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 3]); 
     375        skip += 3; 
     376    } 
     377 
     378        /* G1DM4 G1-Designator, 94^n chars */ 
     379    else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
     380             && buffer[i + 2] == ')') 
     381    { 
     382        sc->conv_state.gn[1] = LITERAL2CHAR('$', buffer[i + 3]); 
     383        skip += 3; 
     384    } 
     385 
     386        /* G2DM4 G2-Designator, 94^n chars */ 
     387    else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
     388             && buffer[i + 2] == '*') 
     389    { 
     390        sc->conv_state.gn[2] = LITERAL2CHAR('$', buffer[i + 3]); 
     391        skip += 3; 
     392    } 
     393 
     394        /* G3DM4 G3-Designator, 94^n chars */ 
     395    else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
     396             && buffer[i + 2] == '+') 
     397    { 
     398        sc->conv_state.gn[3] = LITERAL2CHAR('$', buffer[i + 3]); 
     399        skip += 3; 
     400    } 
     401 
     402        /* G2DM6 G2-Designator, 96^n chars */ 
     403    else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
     404             && buffer[i + 2] == '.') 
     405    { 
     406        sc->conv_state.gn[2] = LITERAL3CHAR('$', '.', buffer[i + 3]); 
     407        skip += 3; 
     408    } 
     409 
     410        /* G3DM6 G3-Designator, 96^n chars */ 
     411    else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
     412             && buffer[i + 2] == '/') 
     413    { 
     414        sc->conv_state.gn[3] = LITERAL3CHAR('$', '.', buffer[i + 3]); 
     415        skip += 3; 
     416    } 
     417    else if (buffer[i] == '\033' && buffer[i + 1] == '#') 
     418    { 
     419        debug("ansi private '#' sequence\n"); 
     420 
     421        switch (buffer[i + 2]) 
     422        { 
     423        case '8':              /* DECALN Fills the entire screen area with 
     424                                   uppercase Es for screen focus and 
     425                                   alignment. */ 
     426            for (j = 0; j < height; j++) 
    228427            { 
    229428                for (k = 0; k < width; k++) 
    230429                { 
    231                     caca_put_char(sc->cv, k, j, 
    232                                   caca_get_char(sc->cv, k, j - 1)); 
    233                     caca_put_attr(sc->cv, k, j, 
    234                                   caca_get_attr(sc->cv, k, j - 1)); 
     430                    caca_put_char(sc->cv, k, j, 'E'); 
    235431                } 
    236432            } 
    237             caca_draw_line(sc->cv, 0, top - 1, width - 1, top - 1, ' '); 
    238             skip += 1; 
    239         } 
    240  
    241         /* Single Shift Select of G3 Character Set (SS2: 0x8f): affects next 
    242            character only */ 
    243         else if (buffer[i] == '\033' && buffer[i + 1] == 'O') 
    244         { 
    245             sc->conv_state.ss = 3; 
    246             skip += 1; 
    247         } 
    248  
    249         /* LOCKING-SHIFT TWO (LS2), ISO 2022, ECMA-48 (1986), ISO 6429 : 1988 */ 
    250         else if (buffer[i] == '\033' && buffer[i + 1] == 'n') 
    251         { 
    252             sc->conv_state.glr[0] = 2; 
    253             skip += 1; 
    254         } 
    255  
    256         /* LOCKING-SHIFT THREE (LS3) ISO 2022, ECMA-48 (1986), ISO 6429 : 1988  
     433            skip += 2; 
     434            break; 
     435 
     436        default: 
     437            debug("Unknow private sequence 'ESC#%c'\n", buffer[i + 2]); 
     438            continue; 
     439        } 
     440 
     441    } 
     442        /* Interpret escape commands, as per Standard ECMA-48 "Control 
     443           Functions for Coded Character Sets", 5.4. Control sequences. */ 
     444    else if (buffer[i] == '\033' && buffer[i + 1] == '[') 
     445    { 
     446        unsigned int argc = 0, argv[101]; 
     447        unsigned int param, inter, junk, final; 
     448 
     449 
     450        /* Compute offsets to parameter bytes, intermediate bytes and to the 
     451           final byte. Only the final byte is mandatory, there can be zero of 
     452           the others. 0 param=2 inter final final+1 
     453           +-----+------------------+---------------------+-----------------+ 
     454           | CSI | parameter bytes | intermediate bytes | final byte | | | 
     455           0x30 - 0x3f | 0x20 - 0x2f | 0x40 - 0x7e | | ^[[ | 0123456789:;<=>? 
     456           | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ | 
     457           +-----+------------------+---------------------+-----------------+ */ 
     458        param = 2; 
     459 
     460        /* vttest use to interleave normal characters (\014 CR or \010 BS) 
     461           into CSI sequences, either directly after ESC[ or after param. 
     462           Can't find anything related to this in any documentation nor XTerm 
     463           sources, thought. */ 
     464 
     465        for (junk = param; i + junk < size; junk++) 
     466            if (buffer[i + junk] < 0x20) 
     467            { 
     468                handle_single_char(buffer[i + junk], &x, &y, screen_list, sc); 
     469            } 
     470            else 
     471            { 
     472                break; 
     473            } 
     474 
     475        /* Intermediate offset */ 
     476        for (inter = junk; i + inter < size; inter++) 
     477            if (buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f) 
     478            { 
     479                break; 
     480            } 
     481        /* Interleaved character */ 
     482        for (junk = inter; i + junk < size; junk++) 
     483            if (buffer[i + junk] < 0x20) 
     484            { 
     485                handle_single_char(buffer[i + junk], &x, &y, screen_list, sc); 
     486            } 
     487            else 
     488            { 
     489                break; 
     490            } 
     491 
     492        /* Final Byte offset */ 
     493        for (final = junk; i + final < size; final++) 
     494            if (buffer[i + final] < 0x20 || buffer[i + final] > 0x2f) 
     495            { 
     496                break; 
     497            } 
     498        if (i + final >= size 
     499            || buffer[i + final] < 0x40 || buffer[i + final] > 0x7e) 
     500        { 
     501            debug("ansi Invalid Final Byte (%d %c)\n", buffer[i + final], 
     502                  buffer[i + final]); 
     503            break;              /* Invalid Final Byte */ 
     504        } 
     505 
     506        skip += final; 
     507 
     508        /* Sanity checks */ 
     509        if (param < inter && buffer[i + param] >= 0x3c) 
     510        { 
     511            /* Private sequence, only parse what we know */ 
     512            debug("ansi import: private sequence \"^[[%.*s\"", 
     513                  final - param + 1, buffer + i + param); 
     514            continue;           /* Private sequence, skip it entirely */ 
     515        } 
     516 
     517        if (final - param > 100) 
     518            continue;           /* Suspiciously long sequence, skip it */ 
     519 
     520        /* Parse parameter bytes as per ECMA-48 5.4.2: Parameter string format  
    257521         */ 
    258         else if (buffer[i] == '\033' && buffer[i + 1] == 'o') 
    259         { 
    260             sc->conv_state.glr[0] = 3; 
    261             skip += 1; 
    262         } 
    263  
    264         /* RESET TO INITIAL STATE (RIS), ECMA-48 (1986), ISO 6429 : 1988 */ 
    265         else if (buffer[i] == '\033' && buffer[i + 1] == 'c') 
    266         { 
    267             sc->dfg = CACA_DEFAULT; 
    268             sc->dbg = CACA_DEFAULT; 
    269  
    270             caca_set_color_ansi(sc->cv, sc->dfg, sc->dbg); 
    271             sc->clearattr = caca_get_attr(sc->cv, -1, -1); 
    272             ansi_parse_grcm(sc, 1, &dummy); 
    273  
    274             reset_conv_state(sc); 
    275             skip += 1; 
    276         } 
    277  
    278         /* Coding Method Delimiter (CMD), ECMA-48 (1991), ISO/IEC 6429:1992 
    279            (ISO IR 189) */ 
    280         else if (buffer[i] == '\033' && buffer[i + 1] == 'd') 
    281         { 
    282             reset_conv_state(sc); 
    283             skip += 1; 
    284         } 
    285  
    286         /* GZDM4, G0-Designators, multi, 94^n chars [grandfathered short form 
    287            from ISO 2022:1986] */ 
    288         else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
    289                  && (buffer[i + 2] >= '@') && (buffer[i + 2] <= 'C')) 
    290         { 
    291             sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 2]); 
    292             skip += 2; 
    293         } 
    294  
    295         /* GnDMx Gn-Designators, 9x^n chars; need one more char to distinguish  
    296            these */ 
    297         else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
    298                  && (i + 3 >= size)) 
    299             break; 
    300  
    301         /* GZD4 G0-Designator, 94 chars */ 
    302         else if (buffer[i] == '\033' && buffer[i + 1] == '(') 
    303         { 
    304             sc->conv_state.gn[0] = buffer[i + 2]; 
    305             skip += 2; 
    306         } 
    307  
    308         /* G1D4 G1-Designator, 94 chars */ 
    309         else if (buffer[i] == '\033' && buffer[i + 1] == ')') 
    310         { 
    311             sc->conv_state.gn[1] = buffer[i + 2]; 
    312             skip += 2; 
    313         } 
    314  
    315         /* G2D4 G2-Designator, 94 chars */ 
    316         else if (buffer[i] == '\033' && buffer[i + 1] == '*') 
    317         { 
    318             sc->conv_state.gn[2] = buffer[i + 2]; 
    319             skip += 2; 
    320         } 
    321  
    322         /* G3D4 G3-Designator, 94 chars */ 
    323         else if (buffer[i] == '\033' && buffer[i + 1] == '+') 
    324         { 
    325             sc->conv_state.gn[3] = buffer[i + 2]; 
    326             skip += 2; 
    327         } 
    328  
    329         /* G2D6 G2-Designator, 96 chars */ 
    330         else if (buffer[i] == '\033' && buffer[i + 1] == '.') 
    331         { 
    332             sc->conv_state.gn[2] = LITERAL2CHAR('.', buffer[i + 2]); 
    333             skip += 2; 
    334         } 
    335  
    336         /* G3D6 G3-Designator, 96 chars */ 
    337         else if (buffer[i] == '\033' && buffer[i + 1] == '/') 
    338         { 
    339             sc->conv_state.gn[3] = LITERAL2CHAR('.', buffer[i + 2]); 
    340             skip += 2; 
    341         } 
    342  
    343         /* GZDM4 G0-Designator, 94^n chars */ 
    344         else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
    345                  && buffer[i + 2] == '(') 
    346         { 
    347             sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 3]); 
    348             skip += 3; 
    349         } 
    350  
    351         /* G1DM4 G1-Designator, 94^n chars */ 
    352         else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
    353                  && buffer[i + 2] == ')') 
    354         { 
    355             sc->conv_state.gn[1] = LITERAL2CHAR('$', buffer[i + 3]); 
    356             skip += 3; 
    357         } 
    358  
    359         /* G2DM4 G2-Designator, 94^n chars */ 
    360         else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
    361                  && buffer[i + 2] == '*') 
    362         { 
    363             sc->conv_state.gn[2] = LITERAL2CHAR('$', buffer[i + 3]); 
    364             skip += 3; 
    365         } 
    366  
    367         /* G3DM4 G3-Designator, 94^n chars */ 
    368         else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
    369                  && buffer[i + 2] == '+') 
    370         { 
    371             sc->conv_state.gn[3] = LITERAL2CHAR('$', buffer[i + 3]); 
    372             skip += 3; 
    373         } 
    374  
    375         /* G2DM6 G2-Designator, 96^n chars */ 
    376         else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
    377                  && buffer[i + 2] == '.') 
    378         { 
    379             sc->conv_state.gn[2] = LITERAL3CHAR('$', '.', buffer[i + 3]); 
    380             skip += 3; 
    381         } 
    382  
    383         /* G3DM6 G3-Designator, 96^n chars */ 
    384         else if (buffer[i] == '\033' && buffer[i + 1] == '$' 
    385                  && buffer[i + 2] == '/') 
    386         { 
    387             sc->conv_state.gn[3] = LITERAL3CHAR('$', '.', buffer[i + 3]); 
    388             skip += 3; 
    389         } 
    390         else if (buffer[i] == '\033' && buffer[i + 1] == '#') 
    391         { 
    392             debug("ansi private '#' sequence\n"); 
    393  
    394             switch (buffer[i + 2]) 
    395             { 
    396             case '8':          /* DECALN Fills the entire screen area with 
    397                                    uppercase Es for screen focus and 
    398                                    alignment. */ 
    399                 for (j = 0; j < height; j++) 
     522        if (param < inter) 
     523        { 
     524            argv[0] = 0; 
     525            for (j = param; j < inter; j++) 
     526            { 
     527                if (buffer[i + j] == ';') 
     528                    argv[++argc] = 0; 
     529                else if (buffer[i + j] >= '0' && buffer[i + j] <= '9') 
     530                    argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0'); 
     531            } 
     532            argc++; 
     533        } 
     534 
     535        /* Interpret final byte. The code representations are given in ECMA-48  
     536           5.4: Control sequences, and the code definitions are given in 
     537           ECMA-48 8.3: Definition of control functions. */ 
     538        debug("ansi import: command '%c'", buffer[i + final]); 
     539        switch (buffer[i + final]) 
     540        { 
     541        case 'A':              /* CUU (0x41) - Cursor Up */ 
     542            y -= argc ? argv[0] : 1; 
     543            if (y < 0) 
     544                y = 0; 
     545            break; 
     546        case 'B':              /* CUD (0x42) - Cursor Down */ 
     547            y += argc ? argv[0] : 1; 
     548            break; 
     549        case 'C':              /* CUF (0x43) - Cursor Right */ 
     550            debug("ansi : CUF %d \n", argc ? argv[0] : 1); 
     551            x += argc ? argv[0] : 1; 
     552            break; 
     553        case 'D':              /* CUB (0x44) - Cursor Left */ 
     554            x -= argc ? argv[0] : 1; 
     555            if (x < 0) 
     556                x = 0; 
     557            break; 
     558        case 'G':              /* CHA (0x47) - Cursor Character Absolute */ 
     559            x = (argc && argv[0] > 0) ? argv[0] - 1 : 0; 
     560            break; 
     561        case 'H':              /* CUP (0x48) - Cursor Position */ 
     562            x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0; 
     563            y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0; 
     564            debug("ansi CUP : Cursor at %dx%d\n", x, y); 
     565            break; 
     566        case 'J':              /* ED (0x4a) - Erase In Page */ 
     567            savedattr = caca_get_attr(sc->cv, -1, -1); 
     568            caca_set_attr(sc->cv, sc->clearattr); 
     569            if (!argc || argv[0] == 0) 
     570            { 
     571                caca_draw_line(sc->cv, x, y, width, y, ' '); 
     572                caca_fill_box(sc->cv, 0, y + 1, width, height - 1, ' '); 
     573            } 
     574            else if (argv[0] == 1) 
     575            { 
     576                caca_fill_box(sc->cv, 0, 0, width, y, ' '); 
     577                caca_draw_line(sc->cv, 0, y, x, y, ' '); 
     578            } 
     579            else if (argv[0] == 2) 
     580            { 
     581                // x = y = 0; 
     582                caca_fill_box(sc->cv, 0, 0, width, height, ' '); 
     583            } 
     584            caca_set_attr(sc->cv, savedattr); 
     585            break; 
     586        case 'K':              /* EL (0x4b) - Erase In Line */ 
     587            debug("ansi EL : cursor at %dx%d\n", x, y); 
     588            if (!argc || argv[0] == 0) 
     589            { 
     590                caca_draw_line(sc->cv, x, y, width, y, ' '); 
     591            } 
     592            else if (argv[0] == 1) 
     593            { 
     594                caca_draw_line(sc->cv, 0, y, x, y, ' '); 
     595            } 
     596            else if (argv[0] == 2) 
     597            { 
     598                caca_draw_line(sc->cv, 0, y, width, y, ' '); 
     599            } 
     600            break; 
     601        case 'L':              /* IL - Insert line */ 
     602            { 
     603                unsigned int nb_lines = argc ? argv[0] : 1; 
     604                for (j = bottom - 1; j >= (unsigned int)y + nb_lines; j--) 
    400605                { 
    401606                    for (k = 0; k < width; k++) 
    402607                    { 
    403                         caca_put_char(sc->cv, k, j, 'E'); 
     608                        caca_put_char(sc->cv, k, j, 
     609                                      caca_get_char(sc->cv, k, j - nb_lines)); 
     610                        caca_put_attr(sc->cv, k, j, 
     611                                      caca_get_attr(sc->cv, k, j - nb_lines)); 
    404612                    } 
     613                    caca_draw_line(sc->cv, 0, j - nb_lines, width, 
     614                                   j - nb_lines, ' '); 
    405615                } 
    406                 skip += 2; 
    407                 break; 
    408  
    409             default: 
    410                 debug("Unknow private sequence 'ESC#%c'\n", buffer[i + 2]); 
    411                 continue; 
    412             } 
    413  
    414         } 
    415         /* Interpret escape commands, as per Standard ECMA-48 "Control 
    416            Functions for Coded Character Sets", 5.4. Control sequences. */ 
    417         else if (buffer[i] == '\033' && buffer[i + 1] == '[') 
    418         { 
    419             unsigned int argc = 0, argv[101]; 
    420             unsigned int param, inter, final; 
    421  
    422  
    423             /* Compute offsets to parameter bytes, intermediate bytes and to 
    424                the final byte. Only the final byte is mandatory, there can be 
    425                zero of the others. 0 param=2 inter final final+1 
    426                +-----+------------------+---------------------+-----------------+ 
    427                | CSI | parameter bytes | intermediate bytes | final byte | | | 
    428                0x30 - 0x3f | 0x20 - 0x2f | 0x40 - 0x7e | | ^[[ | 0123456789:;<=>? 
    429                | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ | 
    430                +-----+------------------+---------------------+-----------------+ */ 
    431             param = 2; 
    432  
    433             for (inter = param; i + inter < size; inter++) 
    434                 if (buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f) 
    435                     break; 
    436  
    437             for (final = inter; i + final < size; final++) 
    438                 if (buffer[i + final] < 0x20 || buffer[i + final] > 0x2f) 
    439                     break; 
    440  
    441             if (i + final >= size 
    442                 || buffer[i + final] < 0x40 || buffer[i + final] > 0x7e) 
    443                 break;          /* Invalid Final Byte */ 
    444  
    445             skip += final; 
    446  
    447             /* Sanity checks */ 
    448             if (param < inter && buffer[i + param] >= 0x3c) 
    449             { 
    450                 /* Private sequence, only parse what we know */ 
    451                 debug("ansi import: private sequence \"^[[%.*s\"", 
    452                       final - param + 1, buffer + i + param); 
    453                 continue;       /* Private sequence, skip it entirely */ 
    454             } 
    455  
    456             if (final - param > 100) 
    457                 continue;       /* Suspiciously long sequence, skip it */ 
    458  
    459             /* Parse parameter bytes as per ECMA-48 5.4.2: Parameter string 
    460                format */ 
    461             if (param < inter) 
    462             { 
    463                 argv[0] = 0; 
    464                 for (j = param; j < inter; j++) 
    465                 { 
    466                     if (buffer[i + j] == ';') 
    467                         argv[++argc] = 0; 
    468                     else if (buffer[i + j] >= '0' && buffer[i + j] <= '9') 
    469                         argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0'); 
    470                 } 
    471                 argc++; 
    472             } 
    473  
    474             /* Interpret final byte. The code representations are given in 
    475                ECMA-48 5.4: Control sequences, and the code definitions are 
    476                given in ECMA-48 8.3: Definition of control functions. */ 
    477             debug("ansi import: command '%c'", buffer[i + final]); 
    478             switch (buffer[i + final]) 
    479             { 
    480             case 'A':          /* CUU (0x41) - Cursor Up */ 
    481                 y -= argc ? argv[0] : 1; 
    482                 if (y < 0) 
    483                     y = 0; 
    484                 break; 
    485             case 'B':          /* CUD (0x42) - Cursor Down */ 
    486                 y += argc ? argv[0] : 1; 
    487                 break; 
    488             case 'C':          /* CUF (0x43) - Cursor Right */ 
    489                 x += argc ? argv[0] : 1; 
    490                 break; 
    491             case 'D':          /* CUB (0x44) - Cursor Left */ 
    492                 x -= argc ? argv[0] : 1; 
    493                 if (x < 0) 
    494                     x = 0; 
    495                 break; 
    496             case 'G':          /* CHA (0x47) - Cursor Character Absolute */ 
    497                 x = (argc && argv[0] > 0) ? argv[0] - 1 : 0; 
    498                 break; 
    499             case 'H':          /* CUP (0x48) - Cursor Position */ 
    500                 x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0; 
    501                 y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0; 
    502                 debug("ansi CUP : Cursor at %dx%d\n", x, y); 
    503                 break; 
    504             case 'J':          /* ED (0x4a) - Erase In Page */ 
     616            } 
     617            break; 
     618        case 'P':              /* DCH (0x50) - Delete Character */ 
     619            if (!argc || argv[0] == 0) 
     620                argv[0] = 1;    /* echo -ne 'foobar\r\e[0P\n' */ 
     621            /* Jylam : Start from x, not 0 */ 
     622            for (j = x; (unsigned int)(j + argv[0]) < width; j++) 
     623            { 
     624                caca_put_char(sc->cv, j, y, 
     625                              caca_get_char(sc->cv, j + argv[0], y)); 
     626                caca_put_attr(sc->cv, j, y, 
     627                              caca_get_attr(sc->cv, j + argv[0], y)); 
     628            } 
     629            break;              /* Jylam: this one was missing I guess */ 
     630#if 0 
     631            savedattr = caca_get_attr(sc->cv, -1, -1); 
     632            caca_set_attr(sc->cv, sc->clearattr); 
     633            for (; (unsigned int)j < width; j++) 
     634                caca_put_char(sc->cv, j, y, ' '); 
     635            caca_set_attr(sc->cv, savedattr); 
     636#endif 
     637        case 'X':              /* ECH (0x58) - Erase Character */ 
     638            if (argc && argv[0]) 
     639            { 
    505640                savedattr = caca_get_attr(sc->cv, -1, -1); 
    506641                caca_set_attr(sc->cv, sc->clearattr); 
    507                 if (!argc || argv[0] == 0) 
    508                 { 
    509                     caca_draw_line(sc->cv, x, y, width, y, ' '); 
    510                     caca_fill_box(sc->cv, 0, y + 1, width, height - 1, ' '); 
    511                 } 
    512                 else if (argv[0] == 1) 
    513                 { 
    514                     caca_fill_box(sc->cv, 0, 0, width, y, ' '); 
    515                     caca_draw_line(sc->cv, 0, y, x, y, ' '); 
    516                 } 
    517                 else if (argv[0] == 2) 
    518                 { 
    519                     // x = y = 0; 
    520                     caca_fill_box(sc->cv, 0, 0, width, height, ' '); 
    521                 } 
     642                caca_draw_line(sc->cv, x, y, x + argv[0] - 1, y, ' '); 
    522643                caca_set_attr(sc->cv, savedattr); 
    523                 break; 
    524             case 'K':          /* EL (0x4b) - Erase In Line */ 
    525                 debug("ansi EL : cursor at %dx%d\n", x, y); 
    526                 if (!argc || argv[0] == 0) 
    527                 { 
    528                     caca_draw_line(sc->cv, x, y, width, y, ' '); 
    529                 } 
    530                 else if (argv[0] == 1) 
    531                 { 
    532                     caca_draw_line(sc->cv, 0, y, x, y, ' '); 
    533                 } 
    534                 else if (argv[0] == 2) 
    535                 { 
    536                     caca_draw_line(sc->cv, 0, y, width, y, ' '); 
    537                 } 
    538                 break; 
    539             case 'L':          /* IL - Insert line */ 
    540                 { 
    541                     unsigned int nb_lines = argc ? argv[0] : 1; 
    542                     for (j = bottom - 1; j >= (unsigned int)y + nb_lines; j--) 
    543                     { 
    544                         for (k = 0; k < width; k++) 
    545                         { 
    546                             caca_put_char(sc->cv, k, j, 
    547                                           caca_get_char(sc->cv, k, 
    548                                                         j - nb_lines)); 
    549                             caca_put_attr(sc->cv, k, j, 
    550                                           caca_get_attr(sc->cv, k, 
    551                                                         j - nb_lines)); 
    552                         } 
    553                         caca_draw_line(sc->cv, 0, j - nb_lines, width, 
    554                                        j - nb_lines, ' '); 
    555                     } 
    556                 } 
    557                 break; 
    558             case 'P':          /* DCH (0x50) - Delete Character */ 
    559                 if (!argc || argv[0] == 0) 
    560                     argv[0] = 1;        /* echo -ne 'foobar\r\e[0P\n' */ 
    561                 /* Jylam : Start from x, not 0 */ 
    562                 for (j = x; (unsigned int)(j + argv[0]) < width; j++) 
    563                 { 
    564                     caca_put_char(sc->cv, j, y, 
    565                                   caca_get_char(sc->cv, j + argv[0], y)); 
    566                     caca_put_attr(sc->cv, j, y, 
    567                                   caca_get_attr(sc->cv, j + argv[0], y)); 
    568                 } 
    569                 break;          /* Jylam: this one was missing I guess */ 
    570 #if 0 
    571                 savedattr = caca_get_attr(sc->cv, -1, -1); 
    572                 caca_set_attr(sc->cv, sc->clearattr); 
    573                 for (; (unsigned int)j < width; j++) 
    574                     caca_put_char(sc->cv, j, y, ' '); 
    575                 caca_set_attr(sc->cv, savedattr); 
    576 #endif 
    577             case 'X':          /* ECH (0x58) - Erase Character */ 
    578                 if (argc && argv[0]) 
    579                 { 
    580                     savedattr = caca_get_attr(sc->cv, -1, -1); 
    581                     caca_set_attr(sc->cv, sc->clearattr); 
    582                     caca_draw_line(sc->cv, x, y, x + argv[0] - 1, y, ' '); 
    583                     caca_set_attr(sc->cv, savedattr); 
    584                 } 
    585             case 'd':          /* VPA (0x64) - Line Position Absolute */ 
    586                 y = (argc && argv[0] > 0) ? argv[0] - 1 : 0; 
    587                 break; 
    588             case 'f':          /* HVP (0x66) - Character And Line Position */ 
    589                 x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0; 
    590                 y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0; 
    591                 break; 
    592             case 'r':          /* FIXME */ 
    593                 if (argc == 2)  /* DCSTBM - Set top and bottom margin */ 
    594                 { 
    595                     debug("DCSTBM %d %d", argv[0], argv[1]); 
    596                     top = argv[0]; 
    597                     bottom = argv[1]; 
    598                 } 
    599                 else 
    600                     debug("ansi import: command r with %d params", argc); 
    601                 break; 
    602             case 'h':          /* SM (0x68) - FIXME */ 
    603                 debug("ansi import: set mode %i", argc ? (int)argv[0] : -1); 
    604                 break; 
    605             case 'l':          /* RM (0x6c) - FIXME */ 
    606                 debug("ansi import: reset mode %i", argc ? (int)argv[0] : -1); 
    607                 break; 
    608             case 'm':          /* SGR (0x6d) - Select Graphic Rendition */ 
    609                 if (argc) 
    610                     ansi_parse_grcm(sc, argc, argv); 
    611                 else 
    612                     ansi_parse_grcm(sc, 1, &dummy); 
    613                 break; 
    614             case 's':          /* Private (save cursor position) */ 
    615                 save_x = x; 
    616                 save_y = y; 
    617                 break; 
    618             case 'u':          /* Private (reload cursor position) */ 
    619                 x = save_x; 
    620                 y = save_y; 
    621                 break; 
    622             default: 
    623                 debug("ansi import: unknown command \"^[[%.*s\"", 
    624                       final - param + 1, buffer + i + param); 
    625                 break; 
    626             } 
    627         } 
     644            } 
     645        case 'd':              /* VPA (0x64) - Line Position Absolute */ 
     646            y = (argc && argv[0] > 0) ? argv[0] - 1 : 0; 
     647            break; 
     648        case 'f':              /* HVP (0x66) - Character And Line Position */ 
     649            x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0; 
     650            y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0; 
     651            break; 
     652        case 'r':              /* FIXME */ 
     653            if (argc == 2)      /* DCSTBM - Set top and bottom margin */ 
     654            { 
     655                debug("DCSTBM %d %d", argv[0], argv[1]); 
     656                top = argv[0]; 
     657                bottom = argv[1]; 
     658            } 
     659            else 
     660                debug("ansi import: command r with %d params", argc); 
     661            break; 
     662        case 'h':              /* SM (0x68) - FIXME */ 
     663            debug("ansi import: set mode %i", argc ? (int)argv[0] : -1); 
     664            break; 
     665        case 'l':              /* RM (0x6c) - FIXME */ 
     666            debug("ansi import: reset mode %i", argc ? (int)argv[0] : -1); 
     667            break; 
     668        case 'm':              /* SGR (0x6d) - Select Graphic Rendition */ 
     669            if (argc) 
     670                ansi_parse_grcm(sc, argc, argv); 
     671            else 
     672                ansi_parse_grcm(sc, 1, &dummy); 
     673            break; 
     674        case 's':              /* Private (save cursor position) */ 
     675            save_x = x; 
     676            save_y = y; 
     677            break; 
     678        case 'u':              /* Private (reload cursor position) */ 
     679            x = save_x; 
     680            y = save_y; 
     681            break; 
     682        default: 
     683            debug("ansi import: unknown command \"^[[%.*s\"", 
     684                  final - param + 1, buffer + i + param); 
     685            break; 
     686        } 
     687    } 
    628688 
    629689        /* Parse OSC stuff. */ 
    630         else if (buffer[i] == '\033' && buffer[i + 1] == ']') 
    631         { 
    632             char *string; 
    633             unsigned int command = 0; 
    634             unsigned int mode = 2, semicolon, final; 
    635  
    636             for (semicolon = mode; i + semicolon < size; semicolon++) 
    637             { 
    638                 if (buffer[i + semicolon] < '0' || buffer[i + semicolon] > '9') 
    639                     break; 
    640                 command = 10 * command + (buffer[i + semicolon] - '0'); 
    641             } 
    642  
    643             if (i + semicolon >= size || buffer[i + semicolon] != ';') 
    644                 break;          /* Invalid Mode */ 
    645  
    646             for (final = semicolon + 1; i + final < size; final++) 
    647                 if (buffer[i + final] < 0x20) 
    648                     break; 
    649  
    650             if (i + final >= size || buffer[i + final] != '\a') 
    651                 break;          /* Not enough data or no bell found */ 
    652             /* FIXME: XTerm also reacts to <ESC><backslash> and <ST> */ 
    653             /* FIXME: differenciate between not enough data (try again) and 
    654                invalid data (print shit) */ 
    655  
    656             skip += final; 
    657  
    658             string = malloc(final - (semicolon + 1) + 1); 
    659             memcpy(string, buffer + i + (semicolon + 1), 
    660                    final - (semicolon + 1)); 
    661             string[final - (semicolon + 1)] = '\0'; 
    662             debug("ansi import: got OSC command %i string '%s'", command, 
    663                   string); 
    664             if (command == 0 || command == 2) 
    665             { 
    666                 if (sc->title) 
    667                     free(sc->title); 
    668                 sc->title = string; 
    669             } 
    670             else 
    671                 free(string); 
    672         } 
     690    else if (buffer[i] == '\033' && buffer[i + 1] == ']') 
     691    { 
     692        char *string; 
     693        unsigned int command = 0; 
     694        unsigned int mode = 2, semicolon, final; 
     695 
     696        for (semicolon = mode; i + semicolon < size; semicolon++) 
     697        { 
     698            if (buffer[i + semicolon] < '0' || buffer[i + semicolon] > '9') 
     699                break; 
     700            command = 10 * command + (buffer[i + semicolon] - '0'); 
     701        } 
     702 
     703        if (i + semicolon >= size || buffer[i + semicolon] != ';') 
     704            break;              /* Invalid Mode */ 
     705 
     706        for (final = semicolon + 1; i + final < size; final++) 
     707            if (buffer[i + final] < 0x20) 
     708                break; 
     709 
     710        if (i + final >= size || buffer[i + final] != '\a') 
     711            break;              /* Not enough data or no bell found */ 
     712        /* FIXME: XTerm also reacts to <ESC><backslash> and <ST> */ 
     713        /* FIXME: differenciate between not enough data (try again) and 
     714           invalid data (print shit) */ 
     715 
     716        skip += final; 
     717 
     718        string = malloc(final - (semicolon + 1) + 1); 
     719        memcpy(string, buffer + i + (semicolon + 1), final - (semicolon + 1)); 
     720        string[final - (semicolon + 1)] = '\0'; 
     721        debug("ansi import: got OSC command %i string '%s'", command, string); 
     722        if (command == 0 || command == 2) 
     723        { 
     724            if (sc->title) 
     725                free(sc->title); 
     726            sc->title = string; 
     727        } 
     728        else 
     729            free(string); 
     730    } 
    673731 
    674732        /* Get the character we’re going to paste */ 
     733    else 
     734    { 
     735        size_t bytes; 
     736 
     737        if (i + 6 < size) 
     738        { 
     739            ch = caca_utf8_to_utf32((char const *)(buffer + i), &bytes); 
     740        } 
    675741        else 
    676742        { 
    677             size_t bytes; 
    678  
    679             if (i + 6 < size) 
    680             { 
    681                 ch = caca_utf8_to_utf32((char const *)(buffer + i), &bytes); 
    682             } 
    683             else 
    684             { 
    685                 /* Add a trailing zero to what we're going to read */ 
    686                 char tmp[7]; 
    687                 memcpy(tmp, buffer + i, size - i); 
    688                 tmp[size - i] = '\0'; 
    689                 ch = caca_utf8_to_utf32(tmp, &bytes); 
    690             } 
    691  
    692             if (!bytes) 
    693             { 
    694                 /* If the Unicode is invalid, assume it was latin1. */ 
    695                 ch = buffer[i]; 
    696                 bytes = 1; 
    697             } 
    698  
    699             /* very incomplete ISO-2022 implementation tailored to DEC ACS */ 
    700             if (sc->conv_state.cs == '@') 
    701             { 
    702                 if (((ch > ' ') && (ch <= '~')) 
    703                     && 
    704                     (sc->conv_state. 
    705                      gn[sc->conv_state.ss ? sc->conv_state. 
    706                         gn[sc->conv_state.ss] : sc->conv_state.glr[0]] == '0')) 
    707                 { 
    708                     ch = dec_acs(ch); 
    709                 } 
    710                 else if (((ch > 0x80) && (ch < 0xff)) 
    711                          && (sc->conv_state.gn[sc->conv_state.glr[1]] == '0')) 
    712                 { 
    713                     ch = dec_acs(ch + ' ' - 0x80); 
    714                 } 
    715             } 
    716             sc->conv_state.ss = 0;      /* no single-shift (GL) */ 
    717  
    718             wch = caca_utf32_is_fullwidth(ch) ? 2 : 1; 
    719  
    720             skip += bytes - 1; 
    721         } 
    722  
    723         /* Wrap long lines or grow horizontally */ 
    724         while ((unsigned int)x + wch > width) 
    725         { 
    726             x -= width; 
    727             y++; 
    728         } 
    729  
    730         /* Scroll or grow vertically */ 
    731         if ((unsigned int)y >= bottom) 
    732         { 
    733             int lines = (y - bottom) + 1; 
    734  
    735             savedattr = caca_get_attr(sc->cv, -1, -1); 
    736  
    737             for (j = top - 1; j + lines < bottom; j++) 
    738             { 
    739                 for (k = 0; k < width; k++) 
    740                 { 
    741                     caca_put_char(sc->cv, k, j, 
    742                                   caca_get_char(sc->cv, k, j + lines)); 
    743                     caca_put_attr(sc->cv, k, j, 
    744                                   caca_get_attr(sc->cv, k, j + lines)); 
    745                 } 
    746             } 
    747             caca_set_attr(sc->cv, sc->clearattr); 
    748             caca_fill_box(sc->cv, 0, bottom - lines, width, bottom - 1, ' '); 
    749             y -= lines; 
    750             caca_set_attr(sc->cv, savedattr); 
    751         } 
     743            /* Add a trailing zero to what we're going to read */ 
     744            char tmp[7]; 
     745            memcpy(tmp, buffer + i, size - i); 
     746            tmp[size - i] = '\0'; 
     747            ch = caca_utf8_to_utf32(tmp, &bytes); 
     748        } 
     749 
     750        if (!bytes) 
     751        { 
     752            /* If the Unicode is invalid, assume it was latin1. */ 
     753            ch = buffer[i]; 
     754            bytes = 1; 
     755        } 
     756 
     757        /* very incomplete ISO-2022 implementation tailored to DEC ACS */ 
     758        if (sc->conv_state.cs == '@') 
     759        { 
     760            if (((ch > ' ') && (ch <= '~')) 
     761                && 
     762                (sc->conv_state. 
     763                 gn[sc->conv_state.ss ? sc->conv_state. 
     764                    gn[sc->conv_state.ss] : sc->conv_state.glr[0]] == '0')) 
     765            { 
     766                ch = dec_acs(ch); 
     767            } 
     768            else if (((ch > 0x80) && (ch < 0xff)) 
     769                     && (sc->conv_state.gn[sc->conv_state.glr[1]] == '0')) 
     770            { 
     771                ch = dec_acs(ch + ' ' - 0x80); 
     772            } 
     773        } 
     774        sc->conv_state.ss = 0;  /* no single-shift (GL) */ 
     775 
     776        wch = caca_utf32_is_fullwidth(ch) ? 2 : 1; 
     777 
     778        skip += bytes - 1; 
     779    } 
     780 
     781    /* Wrap long lines or grow horizontally */ 
     782    while ((unsigned int)x + wch > width) 
     783    { 
     784        x -= width; 
     785        y++; 
     786    } 
     787 
     788    /* Scroll or grow vertically */ 
     789    if ((unsigned int)y >= bottom) 
     790    { 
     791        int lines = (y - bottom) + 1; 
     792 
     793        savedattr = caca_get_attr(sc->cv, -1, -1); 
     794 
     795        for (j = top - 1; j + lines < bottom; j++) 
     796        { 
     797            for (k = 0; k < width; k++) 
     798            { 
     799                caca_put_char(sc->cv, k, j, 
     800                              caca_get_char(sc->cv, k, j + lines)); 
     801                caca_put_attr(sc->cv, k, j, 
     802                              caca_get_attr(sc->cv, k, j + lines)); 
     803            } 
     804        } 
     805        caca_set_attr(sc->cv, sc->clearattr); 
     806        caca_fill_box(sc->cv, 0, bottom - lines, width, bottom - 1, ' '); 
     807        y -= lines; 
     808        caca_set_attr(sc->cv, savedattr); 
     809    } 
    752810 
    753811        /* Now paste our character, if any */ 
Note: See TracChangeset for help on using the changeset viewer.