Changeset 1426 for libcaca


Ignore:
Timestamp:
Nov 21, 2006, 7:35:04 AM (14 years ago)
Author:
Sam Hocevar
Message:
  • Improved ANSI importer so that it supports a lot more of what is needed for basic vt220 emulation.
File:
1 edited

Legend:

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

    r1384 r1426  
    4848    uint8_t efg, ebg; /* Effective (libcucul) fg/bg */
    4949    uint8_t dfg, dbg; /* Default fg/bg */
    50     uint8_t bold, negative, concealed;
     50    uint8_t bold, blink, italics, negative, concealed, underline;
    5151};
    5252
     
    349349    struct ansi_grcm grcm;
    350350    unsigned char const *buffer = (unsigned char const*)data;
    351     unsigned int i, j, skip, dummy = 0;
    352     unsigned int width = 0, height = 0, wch = 1;
    353     uint32_t savedattr, resizeattr;
    354     unsigned long int ch;
     351    unsigned int i, j, skip, growx = 0, growy = 0, dummy = 0;
     352    unsigned int width, height;
     353    uint32_t savedattr, clearattr;
    355354    int x = 0, y = 0, save_x = 0, save_y = 0;
    356355
    357     cucul_set_canvas_size(cv, 0, 0);
    358356    if(utf8)
    359357    {
     358        width = cv->width;
     359        height = cv->height;
     360        growx = !width;
     361        growy = !height;
     362        x = cv->frames[cv->frame].x;
     363        y = cv->frames[cv->frame].y;
    360364        grcm.dfg = CUCUL_DEFAULT;
    361365        grcm.dbg = CUCUL_TRANSPARENT;
     
    363367    else
    364368    {
     369        cucul_set_canvas_size(cv, width = 80, height = 0);
     370        growx = 0;
     371        growy = 1;
    365372        grcm.dfg = CUCUL_LIGHTGRAY;
    366373        grcm.dbg = CUCUL_BLACK;
    367         cucul_set_color_ansi(cv, CUCUL_LIGHTGRAY, CUCUL_BLACK);
    368     }
    369 
    370     resizeattr = cucul_get_attr(cv, -1, -1);
    371 
     374    }
     375
     376    savedattr = cucul_get_attr(cv, -1, -1);
     377    cucul_set_color_ansi(cv, grcm.dfg, grcm.dbg);
     378    clearattr = cucul_get_attr(cv, -1, -1);
     379
     380    if(utf8)
     381        cucul_set_attr(cv, savedattr);
     382
     383    /* FIXME: this is not right, we should store the grcm information as a
     384     * persistent structure within the canvas. */
    372385    ansi_parse_grcm(cv, &grcm, 1, &dummy);
    373386
    374387    for(i = 0; i < size; i += skip)
    375388    {
     389        uint32_t ch = 0;
     390        int wch = 0;
     391
    376392        skip = 1;
    377393
    378         /* Wrap long lines */
    379         if((unsigned int)x >= 80)
     394        if(!utf8 && buffer[i] == '\x1a' && i + 7 < size
     395           && !memcmp(buffer + i + 1, "SAUCE00", 7))
     396            break; /* End before SAUCE data */
     397
     398        else if(buffer[i] == '\r')
     399        {
     400            x = 0;
     401        }
     402
     403        else if(buffer[i] == '\n')
    380404        {
    381405            x = 0;
     
    383407        }
    384408
    385         if(buffer[i] == '\x1a' && size - i >= 8
    386            && !memcmp(buffer + i + 1, "SAUCE00", 7))
    387             break; /* End before SAUCE data */
    388 
    389         if(buffer[i] == '\r')
    390             continue; /* DOS sucks */
    391 
    392         if(buffer[i] == '\n')
    393         {
    394             x = 0;
    395             y++;
    396             continue;
     409        else if(buffer[i] == '\t')
     410        {
     411            x = (x + 7) & ~7;
     412        }
     413
     414        else if(buffer[i] == '\x08')
     415        {
     416            if(x > 0)
     417                x--;
     418        }
     419
     420        else if(buffer[i] == '\x1b' && buffer[i + 1] == ']'
     421                 && buffer[i + 2] == '0' && buffer[i + 3] == ';')
     422        {
     423            for(j = i + 4; j < size; j++)
     424                if(buffer[j] == '\x07' || buffer[j] == '\x1b'
     425                   || buffer[j] == '\r' || buffer[j] == '\n')
     426                    break;
     427
     428            if(j < size && buffer[j] == '\x07')
     429            {
     430                char *title = malloc(j - i - 4 + 1);
     431                memcpy(title, buffer + i + 4, j - i - 4);
     432                title[j - i - 4] = '\0';
     433                debug("ansi import: got display title '%s'", title);
     434                skip += j - i;
     435                free(title);
     436            }
     437        }
     438
     439        /* If there are not enough characters to parse the escape sequence,
     440         * wait until the next try. We require 3. */
     441        else if(buffer[i] == '\x1b' && i + 2 >= size)
     442            break;
     443
     444        /* XXX: What the fuck is this shit? */
     445        else if(buffer[i] == '\x1b' && buffer[i + 1] == '('
     446                 && buffer[i + 2] == 'B')
     447        {
     448            skip += 2;
    397449        }
    398450
    399451        /* Interpret escape commands, as per Standard ECMA-48 "Control
    400452         * Functions for Coded Character Sets", 5.4. Control sequences. */
    401         if(buffer[i] == '\x1b' && buffer[i + 1] == '[')
     453        else if(buffer[i] == '\x1b' && buffer[i + 1] == '[')
    402454        {
    403455            unsigned int argc = 0, argv[101];
     
    424476                    break;
    425477
    426             if(buffer[i + final] < 0x40 || buffer[i + final] > 0x7e)
     478            if(i + final >= size
     479                || buffer[i + final] < 0x40 || buffer[i + final] > 0x7e)
    427480                break; /* Invalid Final Byte */
    428481
     
    432485            if(param < inter && buffer[i + param] >= 0x3c)
    433486            {
    434                 fprintf(stderr, "private sequence \"^[[%.*s\"\n",
    435                         final - param + 1, buffer + i + param);
     487                /* Private sequence, only parse what we know */
     488                debug("ansi import: private sequence \"^[[%.*s\"",
     489                      final - param + 1, buffer + i + param);
    436490                continue; /* Private sequence, skip it entirely */
    437491            }
     
    460514            switch(buffer[i + final])
    461515            {
    462             case 'f': /* CUP - Cursor Position */
    463             case 'H': /* HVP - Character And Line Position */
     516            case 'H': /* CUP (0x48) - Cursor Position */
    464517                x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0;
    465518                y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0;
    466519                break;
    467             case 'A': /* CUU - Cursor Up */
     520            case 'A': /* CUU (0x41) - Cursor Up */
    468521                y -= argc ? argv[0] : 1;
    469522                if(y < 0)
    470523                    y = 0;
    471524                break;
    472             case 'B': /* CUD - Cursor Down */
     525            case 'B': /* CUD (0x42) - Cursor Down */
    473526                y += argc ? argv[0] : 1;
    474527                break;
    475             case 'C': /* CUF - Cursor Right */
     528            case 'C': /* CUF (0x43) - Cursor Right */
    476529                x += argc ? argv[0] : 1;
    477530                break;
    478             case 'D': /* CUB - Cursor Left */
     531            case 'D': /* CUB (0x44) - Cursor Left */
    479532                x -= argc ? argv[0] : 1;
    480533                if(x < 0)
    481534                    x = 0;
    482535                break;
     536            case 'G': /* CHA (0x47) - Cursor Character Absolute */
     537                x = (argc && argv[0] > 0) ? argv[0] - 1 : 0;
     538                break;
     539            case 'J': /* ED (0x4a) - Erase In Page */
     540                savedattr = cucul_get_attr(cv, -1, -1);
     541                cucul_set_attr(cv, clearattr);
     542                if(!argc || argv[0] == 0)
     543                {
     544                    cucul_draw_line(cv, x, y, width, y, ' ');
     545                    cucul_fill_box(cv, 0, y + 1, width - 1, height - 1, ' ');
     546                }
     547                else if(argv[0] == 1)
     548                {
     549                    cucul_fill_box(cv, 0, 0, width - 1, y - 1, ' ');
     550                    cucul_draw_line(cv, 0, y, x, y, ' ');
     551                }
     552                else if(argv[0] == 2)
     553                    //x = y = 0;
     554                    cucul_fill_box(cv, 0, 0, width - 1, height - 1, ' ');
     555                cucul_set_attr(cv, savedattr);
     556                break;
     557            case 'K': /* EL (0x4b) - Erase In Line */
     558                if(!argc || argv[0] == 0)
     559                    cucul_draw_line(cv, x, y, width, y, ' ');
     560                else if(argv[0] == 1)
     561                    cucul_draw_line(cv, 0, y, x, y, ' ');
     562                else if(argv[0] == 2)
     563                    if((unsigned int)x < width)
     564                        cucul_draw_line(cv, x, y, width - 1, y, ' ');
     565                //x = width;
     566                break;
     567            case 'P': /* DCH (0x50) - Delete Character */
     568                if(!argc || argv[0] == 0)
     569                    argv[0] = 1; /* echo -ne 'foobar\r\e[0P\n' */
     570                for(j = 0; (unsigned int)(j + argv[0]) < width; j++)
     571                {
     572                    cucul_put_char(cv, j, y,
     573                                   cucul_get_char(cv, j + argv[0], y));
     574                    cucul_put_attr(cv, j, y,
     575                                   cucul_get_attr(cv, j + argv[0], y));
     576                }
     577#if 0
     578                savedattr = cucul_get_attr(cv, -1, -1);
     579                cucul_set_attr(cv, clearattr);
     580                for( ; (unsigned int)j < width; j++)
     581                    cucul_put_char(cv, j, y, ' ');
     582                cucul_set_attr(cv, savedattr);
     583#endif
     584            case 'X': /* ECH (0x58) - Erase Character */
     585                if(argc && argv[0])
     586                {
     587                    savedattr = cucul_get_attr(cv, -1, -1);
     588                    cucul_set_attr(cv, clearattr);
     589                    cucul_draw_line(cv, x, y, x + argv[0] - 1, y, ' ');
     590                    cucul_set_attr(cv, savedattr);
     591                }
     592            case 'd': /* VPA (0x64) - Line Position Absolute */
     593                y = (argc && argv[0] > 0) ? argv[0] - 1 : 0;
     594                break;
     595            case 'f': /* HVP (0x66) - Character And Line Position */
     596                x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0;
     597                y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0;
     598                break;
     599            case 'h': /* SM (0x68) - FIXME */
     600                debug("ansi import: set mode %i", argc ? (int)argv[0] : -1);
     601                break;
     602            case 'l': /* RM (0x6c) - FIXME */
     603                debug("ansi import: reset mode %i", argc ? (int)argv[0] : -1);
     604                break;
     605            case 'm': /* SGR (0x6d) - Select Graphic Rendition */
     606                ansi_parse_grcm(cv, &grcm, argc, argv);
     607                break;
    483608            case 's': /* Private (save cursor position) */
    484609                save_x = x;
     
    489614                y = save_y;
    490615                break;
    491             case 'J': /* ED - Erase In Page */
    492                 if(argv[0] == 2)
    493                     x = y = 0;
    494                 break;
    495             case 'K': /* EL - Erase In Line */
    496                 if(width < 80)
    497                 {
    498                     savedattr = cucul_get_attr(cv, -1, -1);
    499                     cucul_set_attr(cv, resizeattr);
    500                     cucul_set_canvas_size(cv, width = 80, height);
    501                     cucul_set_attr(cv, savedattr);
    502                 }
    503                 for(j = x; j < 80; j++)
    504                     cucul_put_char(cv, j, y, ' ');
    505                 x = 80;
    506                 break;
    507             case 'm': /* SGR - Select Graphic Rendition */
    508                 ansi_parse_grcm(cv, &grcm, argc, argv);
    509                 break;
    510616            default:
    511                 fprintf(stderr, "unknown command %c\n", buffer[i + final]);
    512                 break;
    513             }
    514 
    515             continue;
     617                debug("ansi import: unknown command \"^[[%.*s\"",
     618                      final - param + 1, buffer + i + param);
     619                break;
     620            }
    516621        }
    517622
    518623        /* Get the character we’re going to paste */
    519         if(utf8)
     624        else if(utf8)
    520625        {
    521626            unsigned int bytes;
     
    544649        {
    545650            ch = cucul_cp437_to_utf32(buffer[i]);
    546         }
    547 
    548         /* Make sure the canvas is big enough. */
    549         if((unsigned int)x + wch > width)
     651            wch = 1;
     652        }
     653
     654        /* Wrap long lines or grow horizontally */
     655        while((unsigned int)x + wch > width)
     656        {
     657            if(growx)
     658            {
     659                savedattr = cucul_get_attr(cv, -1, -1);
     660                cucul_set_attr(cv, clearattr);
     661                cucul_set_canvas_size(cv, width = x + wch, height);
     662                cucul_set_attr(cv, savedattr);
     663            }
     664            else
     665            {
     666                x -= width;
     667                y++;
     668            }
     669        }
     670
     671        /* Scroll or grow vertically */
     672        if((unsigned int)y >= height)
    550673        {
    551674            savedattr = cucul_get_attr(cv, -1, -1);
    552             cucul_set_attr(cv, resizeattr);
    553             cucul_set_canvas_size(cv, width = x + wch, height);
     675            cucul_set_attr(cv, clearattr);
     676            if(growy)
     677            {
     678                cucul_set_canvas_size(cv, width, height = y + 1);
     679            }
     680            else
     681            {
     682                int lines = (y - height) + 1;
     683
     684                for(j = 0; j + lines < height; j++)
     685                {
     686                    memcpy(cv->attrs + j * cv->width,
     687                           cv->attrs + (j + lines) * cv->width, cv->width * 4);
     688                    memcpy(cv->chars + j * cv->width,
     689                           cv->chars + (j + lines) * cv->width, cv->width * 4);
     690                }
     691                cucul_fill_box(cv, 0, height - lines,
     692                                   cv->width - 1, height - 1, ' ');
     693                y -= lines;
     694            }
    554695            cucul_set_attr(cv, savedattr);
    555696        }
    556697
    557         if((unsigned int)y >= height)
    558         {
    559             savedattr = cucul_get_attr(cv, -1, -1);
    560             cucul_set_attr(cv, resizeattr);
    561             cucul_set_canvas_size(cv, width, height = y + 1);
    562             cucul_set_attr(cv, savedattr);
    563         }
    564 
    565         /* Now paste our character */
    566         cucul_put_char(cv, x, y, ch);
    567         x += wch;
    568     }
    569 
    570     if((unsigned int)y > height)
     698        /* Now paste our character, if any */
     699        if(wch)
     700        {
     701            cucul_put_char(cv, x, y, ch);
     702            x += wch;
     703        }
     704    }
     705
     706    if(growy && (unsigned int)y > height)
    571707    {
    572708        savedattr = cucul_get_attr(cv, -1, -1);
    573         cucul_set_attr(cv, resizeattr);
     709        cucul_set_attr(cv, clearattr);
    574710        cucul_set_canvas_size(cv, width, height = y);
    575711        cucul_set_attr(cv, savedattr);
    576712    }
    577713
    578     return size;
     714    cv->frames[cv->frame].x = x;
     715    cv->frames[cv->frame].y = y;
     716
     717    if(utf8)
     718        cucul_set_attr(cv, savedattr);
     719
     720    return i;
    579721}
    580722
     
    608750            g->fg = g->dfg;
    609751            g->bg = g->dbg;
    610             g->bold = g->negative = g->concealed = 0;
     752            g->bold = g->blink = g->italics = 0;
     753            g->negative = g->concealed = g->underline = 0;
    611754            break;
    612755        case 1: /* bold or increased intensity */
    613756            g->bold = 1;
    614757            break;
     758        case 2: /* faint, decreased intensity or second colour */
     759            break;
     760        case 3: /* italicized */
     761            g->italics = 1;
     762            break;
    615763        case 4: /* singly underlined */
     764            g->underline = 1;
    616765            break;
    617766        case 5: /* slowly blinking (less then 150 per minute) */
     767        case 6: /* rapidly blinking (150 per minute or more) */
     768            g->blink = 1;
    618769            break;
    619770        case 7: /* negative image */
     
    623774            g->concealed = 1;
    624775            break;
    625         case 22: /* normal colour or normal intensity (neither bold nor faint) */
     776        case 9: /* crossed-out (characters still legible but marked as to be
     777                 * deleted */
     778            break;
     779        case 21: /* doubly underlined */
     780            g->underline = 1;
     781            break;
     782        case 22: /* normal colour or normal intensity (neither bold nor
     783                  * faint) */
    626784            g->bold = 0;
     785            break;
     786        case 23: /* not italicized, not fraktur */
     787            g->italics = 0;
     788            break;
     789        case 24: /* not underlined (neither singly nor doubly) */
     790            g->underline = 0;
     791            break;
     792        case 25: /* steady (not blinking) */
     793            g->blink = 0;
     794            break;
     795        case 26: /* (reserved for proportional spacing as specified in CCITT
     796                  * Recommendation T.61) */
     797            break;
     798        case 27: /* positive image */
     799            g->negative = 0;
    627800            break;
    628801        case 28: /* revealed characters */
    629802            g->concealed = 0;
    630803            break;
     804        case 29: /* not crossed out */
     805            break;
     806        case 38: /* (reserved for future standardization, intended for setting
     807                  * character foreground colour as specified in ISO 8613-6
     808                  * [CCITT Recommendation T.416]) */
     809            break;
    631810        case 39: /* default display colour (implementation-defined) */
    632811            g->fg = g->dfg;
    633812            break;
     813        case 48: /* (reserved for future standardization, intended for setting
     814                  * character background colour as specified in ISO 8613-6
     815                  * [CCITT Recommendation T.416]) */
     816            break;
    634817        case 49: /* default background colour (implementation-defined) */
    635818            g->bg = g->dbg;
    636819            break;
     820        case 50: /* (reserved for cancelling the effect of the rendering
     821                  * aspect established by parameter value 26) */
     822            break;
    637823        default:
    638             fprintf(stderr, "unknown sgr %i\n", argv[j]);
     824            debug("ansi import: unknown sgr %i", argv[j]);
    639825            break;
    640826        }
Note: See TracChangeset for help on using the changeset viewer.