Changeset 3989 for neercs/trunk


Ignore:
Timestamp:
Nov 21, 2009, 3:58:11 PM (11 years ago)
Author:
Jean-Yves Lamoureux
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.