Changeset 4074 for neercs


Ignore:
Timestamp:
Nov 30, 2009, 11:26:50 AM (10 years ago)
Author:
Jean-Yves Lamoureux
Message:
  • Moved ANSI emulation to ansi.c (term.c now just handles terminals stuff)
Location:
neercs/trunk
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • neercs/trunk/XCode/XCode.xcodeproj/project.pbxproj

    r4049 r4074  
    88
    99/* Begin PBXFileReference section */
     10                E62C165C10C3D46A006717EC /* ansi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ansi.c; path = ../src/ansi.c; sourceTree = SOURCE_ROOT; };
    1011                E6A767B510B44014008B6DEC /* client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = client.c; path = ../src/client.c; sourceTree = SOURCE_ROOT; };
    1112                E6A767B810B445AB008B6DEC /* neercs.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = neercs.1; path = ../doc/neercs.1; sourceTree = SOURCE_ROOT; };
     
    9899                                E6DB672510B19E2200B6F924 /* neercsrc */,
    99100                                E6DB671F10B19E2200B6F924 /* Makefile.am */,
     101                                E62C165C10C3D46A006717EC /* ansi.c */,
    100102                        );
    101103                        name = src;
  • neercs/trunk/src/Makefile.am

    r4048 r4074  
    66                 configuration.c mytrace.c mytrace.h input.c lock.c server.c \
    77                 client.c screen_list.c help.c python/interpreter.c python/py_module.c \
    8                  widgets.c        
     8                 widgets.c ansi.c       
    99neercs_CFLAGS = @CACA_CFLAGS@ @PYTHON3_CFLAGS@
    1010neercs_LDADD = @CACA_LIBS@ @UTIL_LIBS@ @PAM_LIBS@ @PYTHON3_LIBS@
  • neercs/trunk/src/term.c

    r4063 r4074  
    2828
    2929#include <caca.h>
    30 #include <caca.h>
    3130
    3231#include "neercs.h"
    3332
    34 /* DEC ACS with common extensions */
    35 static uint32_t dec_acs(uint32_t uc)
    36 {
    37     switch (uc)
    38     {
    39     case '+':
    40         return 0x2192;          /* RIGHTWARDS ARROW */
    41     case ',':
    42         return 0x2190;          /* LEFTWARDS ARROW */
    43     case '-':
    44         return 0x2191;          /* UPWARDS ARROW */
    45     case '.':
    46         return 0x2193;          /* DOWNWARDS ARROW */
    47     case '0':
    48         return 0x25AE;          /* BLACK VERTICAL RECTANGLE */
    49     case '_':
    50         return 0x25AE;          /* BLACK VERTICAL RECTANGLE */
    51     case '`':
    52         return 0x25C6;          /* BLACK DIAMOND */
    53     case 'a':
    54         return 0x2592;          /* MEDIUM SHADE */
    55     case 'b':
    56         return 0x2409;          /* SYMBOL FOR HORIZONTAL TABULATION */
    57     case 'c':
    58         return 0x240C;          /* SYMBOL FOR FORM FEED */
    59     case 'd':
    60         return 0x240D;          /* SYMBOL FOR CARRIAGE RETURN */
    61     case 'e':
    62         return 0x240A;          /* SYMBOL FOR LINE FEED */
    63     case 'f':
    64         return 0x00B0;          /* DEGREE SIGN */
    65     case 'g':
    66         return 0x00B1;          /* PLUS-MINUS SIGN */
    67     case 'h':
    68         return 0x2424;          /* SYMBOL FOR NEWLINE */
    69     case 'i':
    70         return 0x240B;          /* SYMBOL FOR VERTICAL TABULATION */
    71     case 'j':
    72         return 0x2518;          /* BOX DRAWINGS LIGHT UP AND LEFT */
    73     case 'k':
    74         return 0x2510;          /* BOX DRAWINGS LIGHT DOWN AND LEFT */
    75     case 'l':
    76         return 0x250C;          /* BOX DRAWINGS LIGHT DOWN AND RIGHT */
    77     case 'm':
    78         return 0x2514;          /* BOX DRAWINGS LIGHT UP AND RIGHT */
    79     case 'n':
    80         return 0x253C;          /* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
    81     case 'o':
    82         return 0x23BA;          /* HORIZONTAL SCAN LINE-1 */
    83     case 'p':
    84         return 0x23BB;          /* HORIZONTAL SCAN LINE-3 */
    85     case 'q':
    86         return 0x2500;          /* BOX DRAWINGS LIGHT HORIZONTAL */
    87     case 'r':
    88         return 0x23BC;          /* HORIZONTAL SCAN LINE-7 */
    89     case 's':
    90         return 0x23BD;          /* HORIZONTAL SCAN LINE-9 */
    91     case 't':
    92         return 0x251C;          /* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
    93     case 'u':
    94         return 0x2524;          /* BOX DRAWINGS LIGHT VERTICAL AND LEFT */
    95     case 'v':
    96         return 0x2534;          /* BOX DRAWINGS LIGHT UP AND HORIZONTAL */
    97     case 'w':
    98         return 0x252C;          /* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
    99     case 'x':
    100         return 0x2502;          /* BOX DRAWINGS LIGHT VERTICAL */
    101     case 'y':
    102         return 0x2264;          /* LESS-THAN OR EQUAL TO */
    103     case 'z':
    104         return 0x2265;          /* GREATER-THAN OR EQUAL TO */
    105     case '{':
    106         return 0x03C0;          /* GREEK SMALL LETTER PI */
    107     case '|':
    108         return 0x2260;          /* NOT EQUAL TO */
    109     case '}':
    110         return 0x00A3;          /* POUND SIGN */
    111     case '~':
    112         return 0x00B7;          /* MIDDLE DOT */
    113     default:
    114         return uc;
    115     }
    116 };
    117 
    118 static void reset_conv_state(struct screen *);
    119 
    120 #define LITERAL2CHAR(i0,i1) (((i0) << 8) | (i1))
    121 
    122 #define LITERAL3CHAR(i0,i1,i2) LITERAL2CHAR(LITERAL2CHAR(i0, i1), i2)
    123 
    124 static void ansi_parse_grcm(struct screen *,
    125                             unsigned int, unsigned int const *);
    126 
    127 static int handle_single_char(unsigned char c, int *x, int *y,
    128                               struct screen_list *screen_list,
    129                               struct screen *sc);
    130 
    131 static 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 = 10;
    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     else if (c == '\x0b')
    163     {
    164         /* Vertical tab */
    165         /* Not sure about the real meaning of it, just y++ for now */
    166         if (*y < caca_get_canvas_height(sc->cv))
    167             *y = *y + 1;
    168     }
    169     else if (c == '\x0e')
    170     {
    171         /* Shift Out (Ctrl-N) -> Switch to Alternate Character Set: invokes
    172            the G1 character set. */
    173         sc->conv_state.glr[0] = 1;
    174     }
    175 
    176     else if (c == '\x0f')
    177     {
    178         /* Shift In (Ctrl-O) -> Switch to Standard Character Set: invokes the
    179            G0 character set. */
    180         sc->conv_state.glr[0] = 0;
    181     }
    182     else
    183     {
    184         return 1;
    185     }
    186     return 0;
    187 
    188 }
    189 
    190 long int import_term(struct screen_list *screen_list, struct screen *sc,
    191                      void const *data, unsigned int size)
    192 {
    193     unsigned char const *buffer = (unsigned char const *)data;
    194     unsigned int i, j, k, skip, dummy = 0;
    195     unsigned int width, height, top, bottom;
    196     uint32_t savedattr;
    197     int x = 0, y = 0, save_x = 0, save_y = 0;
    198     char b[100];
    199 
    200     debug("ansi : import_term\n");
    201 
    202     width = caca_get_canvas_width(sc->cv);
    203     height = caca_get_canvas_height(sc->cv);
    204     x = caca_get_cursor_x(sc->cv);
    205     y = caca_get_cursor_y(sc->cv);
    206     top = 1;
    207     bottom = height;
    208 
    209     if (!sc->init)
    210     {
    211         sc->dfg = CACA_LIGHTGRAY;
    212         sc->dbg = CACA_BLACK;
    213 
    214         caca_set_color_ansi(sc->cv, sc->dfg, sc->dbg);
    215         sc->clearattr = caca_get_attr(sc->cv, -1, -1);
    216 
    217         ansi_parse_grcm(sc, 1, &dummy);
    218 
    219         reset_conv_state(sc);
    220 
    221         sc->init = 1;
    222     }
    223 
    224     for (i = 0; i < size; i += skip)
    225     {
    226         uint32_t ch = 0;
    227         int wch = 0;
    228 
    229         skip = 1;
    230 
    231         /* Control codes (ASCII < \x20) */
    232         if (!handle_single_char(buffer[i], &x, &y, screen_list, sc))
    233         {
    234         }
    235 
    236         /* If there are not enough characters to parse the escape sequence,
    237            wait until the next try. We require 3. */
    238 
    239         else if (buffer[i] == '\033' && i + 2 >= size)
    240             break;
    241 
    242         /* Single Shift Select of G2 Character Set (SS2: 0x8e): affects next
    243            character only */
    244         else if (buffer[i] == '\033' && buffer[i + 1] == 'N')
    245         {
    246             sc->conv_state.ss = 2;
    247             skip += 1;
    248         }
    249         /* Reverse Index (RI) go up one line, reverse scroll if necessary */
    250         else if (buffer[i] == '\033' && buffer[i + 1] == 'M')
    251         {
    252             /* FIXME : not sure about the meaning of 'go up one line' and 'if
    253                necessary' words. Implemented as a scroller only. */
    254             for (j = bottom - 1; j > top; j--)
    255             {
    256                 for (k = 0; k < width; k++)
    257                 {
    258                     caca_put_char(sc->cv, k, j,
    259                                   caca_get_char(sc->cv, k, j - 1));
    260                     caca_put_attr(sc->cv, k, j,
    261                                   caca_get_attr(sc->cv, k, j - 1));
    262                 }
    263             }
    264             caca_draw_line(sc->cv, 0, top - 1, width - 1, top - 1, ' ');
    265             skip += 1;
    266         }
    267 
    268         /* Single Shift Select of G3 Character Set (SS2: 0x8f): affects next
    269            character only */
    270         else if (buffer[i] == '\033' && buffer[i + 1] == 'O')
    271         {
    272             sc->conv_state.ss = 3;
    273             skip += 1;
    274         }
    275 
    276         /* LOCKING-SHIFT TWO (LS2), ISO 2022, ECMA-48 (1986), ISO 6429 : 1988 */
    277         else if (buffer[i] == '\033' && buffer[i + 1] == 'n')
    278         {
    279             sc->conv_state.glr[0] = 2;
    280             skip += 1;
    281         }
    282 
    283         /* LOCKING-SHIFT THREE (LS3) ISO 2022, ECMA-48 (1986), ISO 6429 : 1988
    284          */
    285         else if (buffer[i] == '\033' && buffer[i + 1] == 'o')
    286         {
    287             sc->conv_state.glr[0] = 3;
    288             skip += 1;
    289         }
    290 
    291         /* RESET TO INITIAL STATE (RIS), ECMA-48 (1986), ISO 6429 : 1988 */
    292         else if (buffer[i] == '\033' && buffer[i + 1] == 'c')
    293         {
    294             sc->dfg = CACA_DEFAULT;
    295             sc->dbg = CACA_DEFAULT;
    296 
    297             caca_set_color_ansi(sc->cv, sc->dfg, sc->dbg);
    298             sc->clearattr = caca_get_attr(sc->cv, -1, -1);
    299             ansi_parse_grcm(sc, 1, &dummy);
    300 
    301             reset_conv_state(sc);
    302             skip += 1;
    303         }
    304 
    305         /* Coding Method Delimiter (CMD), ECMA-48 (1991), ISO/IEC 6429:1992
    306            (ISO IR 189) */
    307         else if (buffer[i] == '\033' && buffer[i + 1] == 'd')
    308         {
    309             reset_conv_state(sc);
    310             skip += 1;
    311         }
    312 
    313         /* GZDM4, G0-Designators, multi, 94^n chars [grandfathered short form
    314            from ISO 2022:1986] */
    315         else if (buffer[i] == '\033' && buffer[i + 1] == '$'
    316                  && (buffer[i + 2] >= '@') && (buffer[i + 2] <= 'C'))
    317         {
    318             sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 2]);
    319             skip += 2;
    320         }
    321 
    322         /* GnDMx Gn-Designators, 9x^n chars; need one more char to distinguish
    323            these */
    324         else if (buffer[i] == '\033' && buffer[i + 1] == '$'
    325                  && (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++)
    427                 {
    428                     for (k = 0; k < width; k++)
    429                     {
    430                         caca_put_char(sc->cv, k, j, 'E');
    431                     }
    432                 }
    433                 x = 0;
    434                 y = 0;
    435                 skip += 2;
    436                 break;
    437 
    438             default:
    439                 debug("Unknow private sequence 'ESC#%c'\n", buffer[i + 2]);
    440                 continue;
    441             }
    442 
    443         }
    444         /* Interpret escape commands, as per Standard ECMA-48 "Control
    445            Functions for Coded Character Sets", 5.4. Control sequences. */
    446         else if (buffer[i] == '\033' && buffer[i + 1] == '[')
    447         {
    448             unsigned int argc = 0, argv[101];
    449             unsigned int param, inter, junk, final;
    450 
    451             if (buffer[i + 2] == '?')
    452             {
    453                 debug("CSI? %c%c%c%c%c\n",
    454                       buffer[i + 3], buffer[i + 4], buffer[i + 5],
    455                       buffer[i + 6], buffer[i + 7]);
    456             }
    457 
    458             /* Compute offsets to parameter bytes, intermediate bytes and to
    459                the final byte. Only the final byte is mandatory, there can be
    460                zero of the others. 0 param=2 inter final final+1
    461                +-----+------------------+---------------------+-----------------+
    462                | CSI | parameter bytes | intermediate bytes | final byte | | |
    463                0x30 - 0x3f | 0x20 - 0x2f | 0x40 - 0x7e | | ^[[ | 0123456789:;<=>?
    464                | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ |
    465                +-----+------------------+---------------------+-----------------+ */
    466             param = 2;
    467 
    468             /* vttest use to interleave control characters (\014 CR or \010
    469                BS) into CSI sequences, either directly after ESC[ or after
    470                param. Can't find anything related to this in any documentation
    471                nor XTerm sources, thought. */
    472 
    473             for (junk = param; i + junk < size; junk++)
    474                 if (buffer[i + junk] < 0x20)
    475                 {
    476                     handle_single_char(buffer[i + junk], &x, &y, screen_list,
    477                                        sc);
    478                 }
    479                 else
    480                 {
    481                     break;
    482                 }
    483 
    484             /* Intermediate offset */
    485             for (inter = junk; i + inter < size; inter++)
    486                 if (buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f)
    487                 {
    488                     break;
    489                 }
    490             /* Interleaved character */
    491             for (junk = inter; i + junk < size; junk++)
    492                 if (buffer[i + junk] < 0x20)
    493                 {
    494                     handle_single_char(buffer[i + junk], &x, &y, screen_list,
    495                                        sc);
    496                 }
    497                 else
    498                 {
    499                     break;
    500                 }
    501 
    502             /* Final Byte offset */
    503             for (final = junk; i + final < size; final++)
    504                 if (buffer[i + final] < 0x20 || buffer[i + final] > 0x2f)
    505                 {
    506                     break;
    507                 }
    508             if (i + final >= size
    509                 || buffer[i + final] < 0x40 || buffer[i + final] > 0x7e)
    510             {
    511                 debug("ansi Invalid Final Byte (%d %c)\n", buffer[i + final],
    512                       buffer[i + final]);
    513                 break;          /* Invalid Final Byte */
    514             }
    515 
    516             skip += final;
    517 
    518             /* Sanity checks */
    519             if (param < inter && buffer[i + param] >= 0x3c)
    520             {
    521                 /* Private sequence, only parse what we know */
    522                 debug("ansi import: private sequence \"^[[%.*s\"",
    523                       final - param + 1, buffer + i + param);
    524                                 /* FIXME better parsing */
    525                 if (buffer[i + 2] == '?')
    526                 {
    527                     char arg[5];
    528                     int a = 0;
    529                     int c, p;
    530                     for (p = 0; p < 4; p++)
    531                     {
    532                         if (buffer[i + 3 + p] >= '0'
    533                             && buffer[i + 3 + p] <= '9')
    534                         {
    535                             arg[a] = buffer[i + 3 + p];
    536                             arg[a + 1] = 0;
    537                             a++;
    538                             debug("private a now '%s'\n", arg);
    539                         }
    540                         else
    541                         {
    542                             break;
    543                         }
    544                     }
    545                     c = buffer[i + 3 + 4];
    546                     int Pm = atoi(arg);
    547                     debug("private mouse : command %c, arg %d", c, Pm);
    548                     if (c == 'h')       /* DECSET DEC Private Mode Set */
    549                     {
    550                        
    551                         switch (Pm)
    552                         {
    553                             /* FIXME Handle different modes */
    554                         case 1000:     /* Send Mouse X & Y on button press
    555                                            and release.  */
    556                         case 1001:     /* Use Hilite Mouse Tracking.  */
    557                         case 1002:     /* Use Cell Motion Mouse Tracking. */
    558                         case 1003:     /* Use All Motion Mouse Tracking.  */
    559                             sc->report_mouse = 1;
    560                             break;
    561                         default:
    562                             break;
    563                         }
    564                     }
    565                     else if (c == 'l')  /* DECRST DEC Private Mode Reset */
    566                     {
    567                         Pm = atoi(arg);
    568                         switch (Pm)
    569                         {
    570                                 /* FIXME Handle different modes */
    571                             case 1000:     /* Send Mouse X & Y on button press
    572                                             and release.  */
    573                             case 1001:     /* Use Hilite Mouse Tracking.  */
    574                             case 1002:     /* Use Cell Motion Mouse Tracking. */
    575                             case 1003:     /* Use All Motion Mouse Tracking.  */
    576                                 sc->report_mouse = 0;
    577                                 break;
    578                             default:
    579                                 break;
    580                         }
    581                     }
    582                 }
    583                 continue;       /* Private sequence, skip it entirely */
    584             }
    585 
    586             if (final - param > 100)
    587                 continue;       /* Suspiciously long sequence, skip it */
    588 
    589             /* Parse parameter bytes as per ECMA-48 5.4.2: Parameter string
    590                format */
    591             if (param < inter)
    592             {
    593                 argv[0] = 0;
    594                 for (j = param; j < inter; j++)
    595                 {
    596                     if (buffer[i + j] == ';')
    597                         argv[++argc] = 0;
    598                     else if (buffer[i + j] >= '0' && buffer[i + j] <= '9')
    599                         argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0');
    600                 }
    601                 argc++;
    602             }
    603 
    604             /* Interpret final byte. The code representations are given in
    605                ECMA-48 5.4: Control sequences, and the code definitions are
    606                given in ECMA-48 8.3: Definition of control functions. */
    607             debug("ansi import: command '%c'", buffer[i + final]);
    608             switch (buffer[i + final])
    609             {
    610             case 'A':          /* CUU (0x41) - Cursor Up */
    611                 y -= argc ? argv[0] : 1;
    612                 if (y < 0)
    613                     y = 0;
    614                 break;
    615             case 'B':          /* CUD (0x42) - Cursor Down */
    616                 y += argc ? argv[0] : 1;
    617                 break;
    618             case 'C':          /* CUF (0x43) - Cursor Right */
    619                 x += argc ? argv[0] : 1;
    620                 break;
    621             case 'D':          /* CUB (0x44) - Cursor Left */
    622                 x -= argc ? argv[0] : 1;
    623                 if (x < 0)
    624                     x = 0;
    625                 break;
    626             case 'G':          /* CHA (0x47) - Cursor Character Absolute */
    627                 x = (argc && argv[0] > 0) ? argv[0] - 1 : 0;
    628                 break;
    629             case 'H':          /* CUP (0x48) - Cursor Position */
    630                 x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0;
    631                 y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0;
    632                 debug("ansi CUP : Cursor at %dx%d\n", x, y);
    633                 break;
    634             case 'J':          /* ED (0x4a) - Erase In Page */
    635                 savedattr = caca_get_attr(sc->cv, -1, -1);
    636                 caca_set_attr(sc->cv, sc->clearattr);
    637                 if (!argc || argv[0] == 0)
    638                 {
    639                     caca_draw_line(sc->cv, x, y, width, y, ' ');
    640                     caca_fill_box(sc->cv, 0, y + 1, width, height - 1, ' ');
    641                 }
    642                 else if (argv[0] == 1)
    643                 {
    644                     caca_fill_box(sc->cv, 0, 0, width, y, ' ');
    645                     caca_draw_line(sc->cv, 0, y, x, y, ' ');
    646                 }
    647                 else if (argv[0] == 2)
    648                 {
    649                     // x = y = 0;
    650                     caca_fill_box(sc->cv, 0, 0, width, height, ' ');
    651                 }
    652                 caca_set_attr(sc->cv, savedattr);
    653                 break;
    654             case 'K':          /* EL (0x4b) - Erase In Line */
    655                 debug("ansi EL : cursor at %dx%d\n", x, y);
    656                 if (!argc || argv[0] == 0)
    657                 {
    658                     caca_draw_line(sc->cv, x, y, width, y, ' ');
    659                 }
    660                 else if (argv[0] == 1)
    661                 {
    662                     caca_draw_line(sc->cv, 0, y, x, y, ' ');
    663                 }
    664                 else if (argv[0] == 2)
    665                 {
    666                     caca_draw_line(sc->cv, 0, y, width, y, ' ');
    667                 }
    668                 break;
    669             case 'L':          /* IL - Insert line */
    670                 {
    671                     unsigned int nb_lines = argc ? argv[0] : 1;
    672                     for (j = bottom - 1; j >= (unsigned int)y + nb_lines; j--)
    673                     {
    674                         for (k = 0; k < width; k++)
    675                         {
    676                             caca_put_char(sc->cv, k, j,
    677                                           caca_get_char(sc->cv, k,
    678                                                         j - nb_lines));
    679                             caca_put_attr(sc->cv, k, j,
    680                                           caca_get_attr(sc->cv, k,
    681                                                         j - nb_lines));
    682                         }
    683                         caca_draw_line(sc->cv, 0, j - nb_lines, width,
    684                                        j - nb_lines, ' ');
    685                     }
    686                 }
    687                 break;
    688             case 'P':          /* DCH (0x50) - Delete Character */
    689                 if (!argc || argv[0] == 0)
    690                     argv[0] = 1;        /* echo -ne 'foobar\r\e[0P\n' */
    691 
    692                 for (j = x; (unsigned int)(j + argv[0]) < width; j++)
    693                 {
    694                     caca_put_char(sc->cv, j, y,
    695                                   caca_get_char(sc->cv, j + argv[0], y));
    696                     caca_put_attr(sc->cv, j, y,
    697                                   caca_get_attr(sc->cv, j + argv[0], y));
    698                 }
    699                 break;
    700 #if 0
    701                 savedattr = caca_get_attr(sc->cv, -1, -1);
    702                 caca_set_attr(sc->cv, sc->clearattr);
    703                 for (; (unsigned int)j < width; j++)
    704                     caca_put_char(sc->cv, j, y, ' ');
    705                 caca_set_attr(sc->cv, savedattr);
    706 #endif
    707             case 'X':          /* ECH (0x58) - Erase Character */
    708                 if (argc && argv[0])
    709                 {
    710                     savedattr = caca_get_attr(sc->cv, -1, -1);
    711                     caca_set_attr(sc->cv, sc->clearattr);
    712                     caca_draw_line(sc->cv, x, y, x + argv[0] - 1, y, ' ');
    713                     caca_set_attr(sc->cv, savedattr);
    714                 }
    715             case 'c':          /* DA -- Device Attributes */
    716                 /*
    717                    0 Base VT100, no options 1 Processor options (STP) 2
    718                    Advanced video option (AVO) 3 AVO and STP 4 Graphics
    719                    processor option (GPO) 5 GPO and STP 6 GPO and AVO 7 GPO,
    720                    STP, and AVO */
    721                 /* Warning, argument is Pn */
    722                 debug("ansi Got command c, argc %d, argv[0] (%d)\n", argc,
    723                       argv[0], argv[0]);
    724                 if (!argc || argv[0] == 0)
    725                 {
    726                     send_ansi_sequence(screen_list, "\x1b[?1;0c");
    727                 }
    728                 else
    729                 {
    730                     switch (argv[0])
    731                     {
    732                     case 1:
    733                         send_ansi_sequence(screen_list, "\x1b[?\x1;\x1c");
    734                         break;
    735                     case 2:
    736                         send_ansi_sequence(screen_list, "\x1b[?\x1;\x2c");
    737                         break;
    738                     case 3:
    739                         send_ansi_sequence(screen_list, "\x1b[?\x1;\x3c");
    740                         break;
    741                     case 4:
    742                         send_ansi_sequence(screen_list, "\x1b[?\x1;\x4c");
    743                         break;
    744                     case 5:
    745                         send_ansi_sequence(screen_list, "\x1b[?\x1;\x5c");
    746                         break;
    747                     case 6:
    748                         send_ansi_sequence(screen_list, "\x1b[?\x1;\x6c");
    749                         break;
    750                     case 7:
    751                         send_ansi_sequence(screen_list, "\x1b[?\x1;\x7c");
    752                         break;
    753                     default:
    754                         debug("Unsupported DA option '%d'\n", argv[0]);
    755                         break;
    756                     }
    757                 }
    758                 break;
    759             case 'd':          /* VPA (0x64) - Line Position Absolute */
    760                 y = (argc && argv[0] > 0) ? argv[0] - 1 : 0;
    761                 break;
    762             case 'f':          /* HVP (0x66) - Character And Line Position */
    763                 x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0;
    764                 y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0;
    765                 break;
    766             case 'g':          /* TBC -- Tabulation Clear */
    767                 break;
    768             case 'r':          /* FIXME */
    769                 if (argc == 2)  /* DCSTBM - Set top and bottom margin */
    770                 {
    771                     debug("DCSTBM %d %d", argv[0], argv[1]);
    772                     top = argv[0];
    773                     bottom = argv[1];
    774                 }
    775                 else
    776                     debug("ansi import: command r with %d params", argc);
    777                 break;
    778             case 'h':          /* SM (0x68) - FIXME */
    779                 debug("ansi import: set mode %i", argc ? (int)argv[0] : -1);
    780                 break;
    781             case 'l':          /* RM (0x6c) - FIXME */
    782                 debug("ansi import: reset mode %i", argc ? (int)argv[0] : -1);
    783                 break;
    784             case 'm':          /* SGR (0x6d) - Select Graphic Rendition */
    785                 if (argc)
    786                     ansi_parse_grcm(sc, argc, argv);
    787                 else
    788                     ansi_parse_grcm(sc, 1, &dummy);
    789                 break;
    790             case 'n':
    791                 debug("ansi command n, argc %d, argv[0] %d\n", argc, argv[0]);
    792                 if (!argc)
    793                     break;
    794 
    795                 switch (argv[0])
    796                 {
    797                 case 5:
    798                     /* Term ok */
    799                     send_ansi_sequence(screen_list, "\x1b[0n");
    800                     break;
    801                 case 6:
    802                     /* Cursor Position */
    803                     sprintf(b, "\x1b[%d;%dR", y + 1, x + 1);
    804                     send_ansi_sequence(screen_list, b);
    805                     break;
    806                 }
    807 
    808                 break;
    809             case 's':          /* Private (save cursor position) */
    810                 save_x = x;
    811                 save_y = y;
    812                 break;
    813             case 'u':          /* Private (reload cursor position) */
    814                 x = save_x;
    815                 y = save_y;
    816                 break;
    817             default:
    818                 debug("ansi import: unknown command \"^[%.*s\"",
    819                       final - param + 1, buffer + i + param);
    820                 break;
    821             }
    822         }
    823 
    824         /* Parse OSC stuff. */
    825         else if (buffer[i] == '\033' && buffer[i + 1] == ']')
    826         {
    827             char *string;
    828             unsigned int command = 0;
    829             unsigned int mode = 2, semicolon, final;
    830 
    831             for (semicolon = mode; i + semicolon < size; semicolon++)
    832             {
    833                 if (buffer[i + semicolon] < '0' || buffer[i + semicolon] > '9')
    834                     break;
    835                 command = 10 * command + (buffer[i + semicolon] - '0');
    836             }
    837 
    838             if (i + semicolon >= size || buffer[i + semicolon] != ';')
    839                 break;          /* Invalid Mode */
    840 
    841             for (final = semicolon + 1; i + final < size; final++)
    842                 if (buffer[i + final] < 0x20)
    843                     break;
    844 
    845             if (i + final >= size || buffer[i + final] != '\a')
    846                 break;          /* Not enough data or no bell found */
    847             /* FIXME: XTerm also reacts to <ESC><backslash> and <ST> */
    848             /* FIXME: differenciate between not enough data (try again) and
    849                invalid data (print shit) */
    850 
    851             skip += final;
    852 
    853             string = malloc(final - (semicolon + 1) + 1);
    854             memcpy(string, buffer + i + (semicolon + 1),
    855                    final - (semicolon + 1));
    856             string[final - (semicolon + 1)] = '\0';
    857             debug("ansi import: got OSC command %i string '%s'", command,
    858                   string);
    859             if (command == 0 || command == 2)
    860             {
    861                 if (sc->title)
    862                     free(sc->title);
    863                 sc->title = string;
    864             }
    865             else
    866                 free(string);
    867         }
    868 
    869         /* Get the character we’re going to paste */
    870         else
    871         {
    872             size_t bytes;
    873 
    874             if (i + 6 < size)
    875             {
    876                 ch = caca_utf8_to_utf32((char const *)(buffer + i), &bytes);
    877             }
    878             else
    879             {
    880                 /* Add a trailing zero to what we're going to read */
    881                 char tmp[7];
    882                 memcpy(tmp, buffer + i, size - i);
    883                 tmp[size - i] = '\0';
    884                 ch = caca_utf8_to_utf32(tmp, &bytes);
    885             }
    886 
    887             if (!bytes)
    888             {
    889                 /* If the Unicode is invalid, assume it was latin1. */
    890                 ch = buffer[i];
    891                 bytes = 1;
    892             }
    893 
    894             /* very incomplete ISO-2022 implementation tailored to DEC ACS */
    895             if (sc->conv_state.cs == '@')
    896             {
    897                 if (((ch > ' ') && (ch <= '~'))
    898                     &&
    899                     (sc->
    900                      conv_state.gn[sc->conv_state.ss ? sc->
    901                                    conv_state.gn[sc->conv_state.ss] : sc->
    902                                    conv_state.glr[0]] == '0'))
    903                 {
    904                     ch = dec_acs(ch);
    905                 }
    906                 else if (((ch > 0x80) && (ch < 0xff))
    907                          && (sc->conv_state.gn[sc->conv_state.glr[1]] == '0'))
    908                 {
    909                     ch = dec_acs(ch + ' ' - 0x80);
    910                 }
    911             }
    912             sc->conv_state.ss = 0;      /* no single-shift (GL) */
    913 
    914             wch = caca_utf32_is_fullwidth(ch) ? 2 : 1;
    915 
    916             skip += bytes - 1;
    917         }
    918 
    919         /* Wrap long lines or grow horizontally */
    920         while ((unsigned int)x + wch > width)
    921         {
    922             x -= width;
    923             y++;
    924         }
    925 
    926         /* Scroll or grow vertically */
    927         if ((unsigned int)y >= bottom)
    928         {
    929             int lines = (y - bottom) + 1;
    930 
    931             savedattr = caca_get_attr(sc->cv, -1, -1);
    932 
    933             for (j = top - 1; j + lines < bottom; j++)
    934             {
    935                 for (k = 0; k < width; k++)
    936                 {
    937                     caca_put_char(sc->cv, k, j,
    938                                   caca_get_char(sc->cv, k, j + lines));
    939                     caca_put_attr(sc->cv, k, j,
    940                                   caca_get_attr(sc->cv, k, j + lines));
    941                 }
    942             }
    943             caca_set_attr(sc->cv, sc->clearattr);
    944             caca_fill_box(sc->cv, 0, bottom - lines, width, bottom - 1, ' ');
    945             y -= lines;
    946             caca_set_attr(sc->cv, savedattr);
    947         }
    948 
    949         /* Now paste our character, if any */
    950         if (wch)
    951         {
    952             caca_put_char(sc->cv, x, y, ch);
    953             x += wch;
    954         }
    955     }
    956 
    957     caca_gotoxy(sc->cv, x, y);
    958 
    959     if (i)
    960         sc->changed = 1;
    961     return i;
    962 }
    963 
    964 /* Coding Method Delimiter (CMD), ECMA-48 (1991), ISO/IEC 6429:1992 (ISO IR
    965    189) */
    966 
    967 static void reset_conv_state(struct screen *sc)
    968 {
    969     sc->conv_state.cs = '@';    /* ISO-2022 coding system */
    970     sc->conv_state.cn[0] = '@'; /* ISO 646 C0 control charset */
    971     sc->conv_state.cn[1] = 'C'; /* ISO 6429-1983 C1 control charset */
    972     sc->conv_state.glr[0] = 0;  /* G0 in GL */
    973     sc->conv_state.glr[1] = 2;  /* G2 in GR */
    974     sc->conv_state.gn[0] = 'B'; /* US-ASCII G0 charset */
    975     sc->conv_state.gn[1] = '0'; /* DEC ACS G1 charset */
    976     sc->conv_state.gn[2] = LITERAL2CHAR('.', 'A');      /* ISO 8859-1 G2
    977                                                            charset */
    978     sc->conv_state.gn[3] = LITERAL2CHAR('.', 'A');      /* ISO 8859-1 G3
    979                                                            charset */
    980     sc->conv_state.ss = 0;      /* no single-shift (GL) */
    981     sc->conv_state.ctrl8bit = 1;
    982 }
    983 
    984 /* XXX : ANSI loader helper */
    985 
    986 static void ansi_parse_grcm(struct screen *sc,
    987                             unsigned int argc, unsigned int const *argv)
    988 {
    989     static uint8_t const ansi2caca[] = {
    990         CACA_BLACK, CACA_RED, CACA_GREEN, CACA_BROWN,
    991         CACA_BLUE, CACA_MAGENTA, CACA_CYAN, CACA_LIGHTGRAY
    992     };
    993 
    994     unsigned int j;
    995     uint8_t efg, ebg;           /* Effective (libcaca) fg/bg */
    996 
    997     for (j = 0; j < argc; j++)
    998     {
    999         /* Defined in ECMA-48 8.3.117: SGR - SELECT GRAPHIC RENDITION */
    1000         if (argv[j] >= 30 && argv[j] <= 37)
    1001             sc->fg = ansi2caca[argv[j] - 30];
    1002         else if (argv[j] >= 40 && argv[j] <= 47)
    1003             sc->bg = ansi2caca[argv[j] - 40];
    1004         else if (argv[j] >= 90 && argv[j] <= 97)
    1005             sc->fg = ansi2caca[argv[j] - 90] + 8;
    1006         else if (argv[j] >= 100 && argv[j] <= 107)
    1007             sc->bg = ansi2caca[argv[j] - 100] + 8;
    1008         else
    1009             switch (argv[j])
    1010             {
    1011             case 0:            /* default rendition */
    1012                 sc->fg = sc->dfg;
    1013                 sc->bg = sc->dbg;
    1014                 sc->bold = sc->blink = sc->italics = sc->negative
    1015                     = sc->concealed = sc->underline = sc->faint = sc->strike
    1016                     = sc->proportional = 0;
    1017                 break;
    1018             case 1:            /* bold or increased intensity */
    1019                 sc->bold = 1;
    1020                 break;
    1021             case 2:            /* faint, decreased intensity or second colour
    1022                                  */
    1023                 sc->faint = 1;
    1024                 break;
    1025             case 3:            /* italicized */
    1026                 sc->italics = 1;
    1027                 break;
    1028             case 4:            /* singly underlined */
    1029                 sc->underline = 1;
    1030                 break;
    1031             case 5:            /* slowly blinking (less then 150 per minute) */
    1032             case 6:            /* rapidly blinking (150 per minute or more) */
    1033                 sc->blink = 1;
    1034                 break;
    1035             case 7:            /* negative image */
    1036                 sc->negative = 1;
    1037                 break;
    1038             case 8:            /* concealed characters */
    1039                 sc->concealed = 1;
    1040                 break;
    1041             case 9:            /* crossed-out (characters still legible but
    1042                                    marked as to be deleted */
    1043                 sc->strike = 1;
    1044                 break;
    1045             case 21:           /* doubly underlined */
    1046                 sc->underline = 1;
    1047                 break;
    1048             case 22:           /* normal colour or normal intensity (neither
    1049                                    bold nor faint) */
    1050                 sc->bold = sc->faint = 0;
    1051                 break;
    1052             case 23:           /* not italicized, not fraktur */
    1053                 sc->italics = 0;
    1054                 break;
    1055             case 24:           /* not underlined (neither singly nor doubly) */
    1056                 sc->underline = 0;
    1057                 break;
    1058             case 25:           /* steady (not blinking) */
    1059                 sc->blink = 0;
    1060                 break;
    1061             case 26:           /* (reserved for proportional spacing as
    1062                                    specified in CCITT Recommendation T.61) */
    1063                 sc->proportional = 1;
    1064                 break;
    1065             case 27:           /* positive image */
    1066                 sc->negative = 0;
    1067                 break;
    1068             case 28:           /* revealed characters */
    1069                 sc->concealed = 0;
    1070                 break;
    1071             case 29:           /* not crossed out */
    1072                 sc->strike = 0;
    1073                 break;
    1074             case 38:           /* (reserved for future standardization,
    1075                                    intended for setting character foreground
    1076                                    colour as specified in ISO 8613-6 [CCITT
    1077                                    Recommendation T.416]) */
    1078                 break;
    1079             case 39:           /* default display colour
    1080                                    (implementation-defined) */
    1081                 sc->fg = sc->dfg;
    1082                 break;
    1083             case 48:           /* (reserved for future standardization,
    1084                                    intended for setting character background
    1085                                    colour as specified in ISO 8613-6 [CCITT
    1086                                    Recommendation T.416]) */
    1087                 break;
    1088             case 49:           /* default background colour
    1089                                    (implementation-defined) */
    1090                 sc->bg = sc->dbg;
    1091                 break;
    1092             case 50:           /* (reserved for cancelling the effect of the
    1093                                    rendering aspect established by parameter
    1094                                    value 26) */
    1095                 sc->proportional = 0;
    1096                 break;
    1097             default:
    1098                 debug("ansi import: unknown sgr %i", argv[j]);
    1099                 break;
    1100             }
    1101     }
    1102 
    1103     if (sc->concealed)
    1104     {
    1105         efg = ebg = CACA_TRANSPARENT;
    1106     }
    1107     else
    1108     {
    1109         efg = sc->negative ? sc->bg : sc->fg;
    1110         ebg = sc->negative ? sc->fg : sc->bg;
    1111 
    1112         if (sc->bold)
    1113         {
    1114             if (efg < 8)
    1115                 efg += 8;
    1116             else if (efg == CACA_DEFAULT)
    1117                 efg = CACA_WHITE;
    1118         }
    1119     }
    1120 
    1121     caca_set_color_ansi(sc->cv, efg, ebg);
    1122 }
    112333
    112434int create_pty(char *cmd, unsigned int w, unsigned int h, int *cpid)
Note: See TracChangeset for help on using the changeset viewer.