Changeset 891


Ignore:
Timestamp:
Apr 26, 2006, 11:56:26 AM (14 years ago)
Author:
Sam Hocevar
Message:
  • More robust ANSI sequence argument parser. Detects private sequences and intermediate bytes.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcaca/trunk/cucul/import.c

    r890 r891  
    201201}
    202202
    203 #define IS_ALPHA(x) (x>='A' && x<='z')
    204 #define END_ARG 0x1337
    205 static int parse_tuple(unsigned int *, unsigned char const *, int);
    206 static void manage_modifiers(int, uint8_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *);
     203static void manage_modifiers(int, uint8_t *, uint8_t *, uint8_t *,
     204                             uint8_t *, uint8_t *, uint8_t *);
    207205
    208206static cucul_canvas_t *import_ansi(void const *data, unsigned int size)
     
    210208    cucul_canvas_t *cv;
    211209    unsigned char const *buffer = (unsigned char const*)data;
    212     unsigned int i;
     210    unsigned int i, j;
    213211    int x = 0, y = 0;
    214     int width = 80, height = 25;
     212    unsigned int width = 80, height = 25;
    215213    int save_x = 0, save_y = 0;
    216214    unsigned int skip;
    217     int j;
    218215    uint8_t fg, bg, save_fg, save_bg, bold, reverse;
    219216
     
    243240        }
    244241
    245         if(buffer[i] == '\x1b' && buffer[i + 1] == '[')  /* ESC code */
     242        /* Interpret escape commands, as per Standard ECMA-48 "Control
     243         * Functions for Coded Character Sets", 5.4. Control sequences. */
     244        if(buffer[i] == '\x1b' && buffer[i + 1] == '[')
    246245        {
    247246            unsigned int argv[1024]; /* Should be enough. Will it be? */
    248247            unsigned int argc = 0;
    249             unsigned char c = '\0';
    250 
    251             i++; // ESC
    252             i++; // [
    253 
    254             for(j = i; j < (int)size; j++)
    255                 if(IS_ALPHA(buffer[j]))
     248            unsigned int param, inter, final;
     249
     250            /* Offset to parameter bytes */
     251            param = 2;
     252
     253            /* Offset to intermediate bytes: skip parameter bytes */
     254            for(inter = param; i + inter < size; inter++)
     255                if(buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f)
     256                    break;
     257
     258            /* Offset to final byte: skip intermediate bytes */
     259            for(final = inter; i + final < size; final++)
     260                if(buffer[i + final] < 0x20 || buffer[i + final] > 0x2f)
     261                    break;
     262
     263            if(buffer[i + final] < 0x40 || buffer[i + final] > 0x7e)
     264                break; /* Invalid Final Byte */
     265
     266            skip += final;
     267
     268            if(param < inter && buffer[i + param] >= 0x3c)
     269            {
     270                //fprintf(stderr, "private sequence \"^[[%.*s\"\n",
     271                //                final - param + 1, buffer + i + param);
     272                continue; /* Private sequence, skip it entirely */
     273            }
     274
     275            /* Parse parameter bytes, if any */
     276            if(param < inter)
     277            {
     278                argv[0] = 0;
     279                for(j = param; j < inter; j++)
    256280                {
    257                     c = buffer[j];
    258                     break;
     281                    if(buffer[i + j] == ';')
     282                        argv[++argc] = 0;
     283                    else if(buffer[i + j] >= '0' && buffer[i + j] <= '9')
     284                        argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0');
    259285                }
    260 
    261             skip += parse_tuple(argv, buffer + i, size - i);
    262 
    263             while(argv[argc] != END_ARG)
    264                 argc++;  /* Gruik */
    265 
    266             switch(c)
     286                argc++;
     287            }
     288
     289            /* Interpret final byte */
     290            switch(buffer[i + final])
    267291            {
    268292            case 'f':
    269293            case 'H':
    270                 switch(argc)
    271                 {
    272                     case 0: x = y = 0; break;
    273                     case 1: y = argv[0] - 1; x = 0; break;
    274                     case 2: y = argv[0] - 1; x = argv[1] - 1; break;
    275                 }
     294                x = (argc > 1) ? argv[1] - 1 : 0;
     295                y = (argc > 0) ? argv[0] - 1 : 0;
    276296                break;
    277297            case 'A':
     
    310330                break;
    311331            case 'm':
    312                 for(j = 0; j < (int)argc; j++)
     332                for(j = 0; j < argc; j++)
    313333                    manage_modifiers(argv[j], &fg, &bg,
    314334                                     &save_fg, &save_bg, &bold, &reverse);
     
    331351        /* We're going to paste a character. First make sure the canvas
    332352         * is big enough. */
    333         if(x >= width)
     353        if((unsigned int)x >= width)
    334354        {
    335355            x = 0;
     
    337357        }
    338358
    339         if(y >= height)
     359        if((unsigned int)y >= height)
    340360        {
    341361            height = y + 1;
     
    351371}
    352372
    353 /* XXX : ANSI loader helpers */
    354 
    355 static int parse_tuple(unsigned int *ret, unsigned char const *buffer, int size)
    356 {
    357     int i = 0;
    358     int j = 0;
    359     int t = 0;
    360     unsigned char nbr[1024];
    361 
    362     ret[0] = END_ARG;
    363 
    364     for(i = 0; i < size; i++)
    365     {
    366         if(IS_ALPHA(buffer[i]))
    367         {
    368             if(j != 0)
    369             {
    370                 ret[t] = atoi((char*)nbr);
    371                 t++;
    372             }
    373             ret[t] = END_ARG;
    374             j = 0;
    375             return i;
    376         }
    377 
    378         if(buffer[i] != ';')
    379         {
    380             nbr[j] = buffer[i];
    381             nbr[j + 1] = 0;
    382             j++;
    383         }
    384         else
    385         {
    386             ret[t] = atoi((char*)nbr);
    387             t++;
    388             ret[t] = END_ARG;
    389             j = 0;
    390         }
    391     }
    392     return size;
    393 }
     373/* XXX : ANSI loader helper */
    394374
    395375static void manage_modifiers(int i, uint8_t *fg, uint8_t *bg, uint8_t *save_fg,
Note: See TracChangeset for help on using the changeset viewer.