Ignore:
Timestamp:
Apr 27, 2006, 4:15:23 PM (15 years ago)
Author:
Sam Hocevar
Message:
  • Completed return value and errno handling in libcucul API.
File:
1 edited

Legend:

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

    r918 r920  
    2020
    2121#if !defined(__KERNEL__)
     22#   if defined(HAVE_ERRNO_H)
     23#       include <errno.h>
     24#   endif
    2225#   include <stdio.h>
    2326#   include <stdlib.h>
     
    4447/** \brief Import a buffer into a canvas
    4548 *
    46  *  This function imports a libcucul buffer (cucul_load_memory()/cucul_load_file())
    47  *  into an internal libcucul canvas.
     49 *  This function imports a libcucul buffer as returned by cucul_load_memory()
     50 *  or cucul_load_file() into an internal libcucul canvas.
    4851 *
    4952 *  Valid values for \c format are:
     
    5457 *
    5558 *  \li \c "caca": import native libcaca files.
     59 *
     60 *  If an error occurs, NULL is returned and \b errno is set accordingly:
     61 *  - \c ENOMEM Not enough memory to allocate canvas.
     62 *  - \c EINVAL Invalid format requested.
    5663 *
    5764 *  \param buffer A \e libcucul buffer containing the data to be loaded
     
    6471    char const *buf = (char const*)buffer->data;
    6572
    66     if(buffer->size == 0 || buffer->data == NULL)
    67         return NULL;
    68 
    6973    if(!strcasecmp("caca", format))
    7074        return import_caca(buffer->data, buffer->size);
     
    7680    /* Autodetection */
    7781    if(!strcasecmp("", format))
    78         {
    79             unsigned int i=0;
    80             /* if 4 first letters are CACA */
    81             if(buffer->size >= 4 &&
    82                buf[0] == 'C' && buf[1] == 'A' && buf[2] == 'C' && buf[3] != 'A')
    83                 return import_caca(buffer->data, buffer->size);
    84 
    85             /* If we find ESC[ argv, we guess it's an ANSI file */
    86             while(i < buffer->size - 1)
    87                 {
    88                     if((buf[i] == 0x1b) && (buf[i+1] == '['))
    89                         return import_ansi(buffer->data, buffer->size);
    90                     i++;
    91                 }
    92 
    93             /* Otherwise, import it as text */
    94             return import_text(buffer->data, buffer->size);
    95         }
     82    {
     83        unsigned int i;
     84
     85        /* If 4 first letters are CACA */
     86        if(buffer->size >= 4 &&
     87           buf[0] == 'C' && buf[1] == 'A' && buf[2] == 'C' && buf[3] != 'A')
     88            return import_caca(buffer->data, buffer->size);
     89
     90        /* If we find ESC[ argv, we guess it's an ANSI file */
     91        for(i = 0; i < buffer->size - 1; i++)
     92            if((buf[i] == 0x1b) && (buf[i + 1] == '['))
     93                return import_ansi(buffer->data, buffer->size);
     94
     95        /* Otherwise, import it as text */
     96        return import_text(buffer->data, buffer->size);
     97    }
     98
     99#if defined(HAVE_ERRNO_H)
     100    errno = EINVAL;
     101#endif
    96102    return NULL;
    97103}
     
    103109 *  the import format, to be used with cucul_import_canvas(), and a string
    104110 *  containing the natural language description for that import format.
     111 *
     112 *  This function never fails.
    105113 *
    106114 *  \return An array of strings.
     
    131139
    132140    if(size < 16)
    133         return NULL;
     141        goto invalid_caca;
    134142
    135143    if(buf[0] != 'C' || buf[1] != 'A' || buf[2] != 'C' || buf[3] != 'A')
    136         return NULL;
     144        goto invalid_caca;
    137145
    138146    if(buf[4] != 'C' || buf[5] != 'A' || buf[6] != 'N' || buf[7] != 'V')
    139         return NULL;
     147        goto invalid_caca;
    140148
    141149    width = ((uint32_t)buf[8] << 24) | ((uint32_t)buf[9] << 16)
     
    145153
    146154    if(!width || !height)
     155        goto invalid_caca;
     156
     157    if(size != 16 + width * height * 8)
     158        goto invalid_caca;
     159
     160    cv = cucul_create_canvas(width, height);
     161
     162    if(!cv)
     163    {
     164#if defined(HAVE_ERRNO_H)
     165        errno = ENOMEM;
     166#endif
    147167        return NULL;
    148 
    149     if(size != 16 + width * height * 8)
    150         return NULL;
    151 
    152     cv = cucul_create_canvas(width, height);
    153 
    154     if(!cv)
    155         return NULL;
     168    }
    156169
    157170    for(n = height * width; n--; )
     
    168181
    169182    return cv;
     183
     184invalid_caca:
     185#if defined(HAVE_ERRNO_H)
     186    errno = EINVAL;
     187#endif
     188    return NULL;
    170189}
    171190
     
    177196
    178197    cv = cucul_create_canvas(width, height);
     198    if(!cv)
     199    {
     200#if defined(HAVE_ERRNO_H)
     201        errno = ENOMEM;
     202#endif
     203        return NULL;
     204    }
     205
    179206    cucul_set_color(cv, CUCUL_COLOR_DEFAULT, CUCUL_COLOR_TRANSPARENT);
    180207
    181208    for(i = 0; i < size; i++)
    182         {
    183             unsigned char ch = *text++;
    184 
    185             if(ch == '\r')
    186                 continue;
    187 
    188             if(ch == '\n')
    189                 {
    190                     x = 0;
    191                     y++;
    192                     continue;
    193                 }
    194 
    195             if(x >= width || y >= height)
    196                 {
    197                     if(x >= width)
    198                         width = x + 1;
    199 
    200                     if(y >= height)
    201                         height = y + 1;
    202 
    203                     cucul_set_canvas_size(cv, width, height);
    204                 }
    205 
    206             cucul_putchar(cv, x, y, ch);
    207             x++;
    208         }
     209    {
     210        unsigned char ch = *text++;
     211
     212        if(ch == '\r')
     213            continue;
     214
     215        if(ch == '\n')
     216        {
     217            x = 0;
     218            y++;
     219            continue;
     220        }
     221
     222        if(x >= width || y >= height)
     223        {
     224            if(x >= width)
     225                width = x + 1;
     226
     227            if(y >= height)
     228                height = y + 1;
     229
     230            cucul_set_canvas_size(cv, width, height);
     231        }
     232
     233        cucul_putchar(cv, x, y, ch);
     234        x++;
     235    }
    209236
    210237    return cv;
     
    221248
    222249    cv = cucul_create_canvas(width, height);
     250    if(!cv)
     251    {
     252#if defined(HAVE_ERRNO_H)
     253        errno = ENOMEM;
     254#endif
     255        return NULL;
     256    }
     257
    223258    ansi_parse_grcm(cv, &grcm, 1, &dummy);
    224259
    225260    for(i = 0; i < size; i += skip)
    226         {
    227             skip = 1;
    228 
    229             /* Wrap long lines */
    230             if((unsigned int)x >= width)
     261    {
     262        skip = 1;
     263
     264        /* Wrap long lines */
     265        if((unsigned int)x >= width)
     266        {
     267            x = 0;
     268            y++;
     269        }
     270
     271        if(buffer[i] == '\x1a' && size - i >= 8
     272           && !memcmp(buffer + i + 1, "SAUCE00", 7))
     273            break; /* End before SAUCE data */
     274
     275        if(buffer[i] == '\r')
     276            continue; /* DOS sucks */
     277
     278        if(buffer[i] == '\n')
     279        {
     280            x = 0;
     281            y++;
     282            continue;
     283        }
     284
     285        /* Interpret escape commands, as per Standard ECMA-48 "Control
     286         * Functions for Coded Character Sets", 5.4. Control sequences. */
     287        if(buffer[i] == '\x1b' && buffer[i + 1] == '[')
     288        {
     289            unsigned int argc = 0, argv[101];
     290            unsigned int param, inter, final;
     291
     292        /* Compute offsets to parameter bytes, intermediate bytes and
     293         * to the final byte. Only the final byte is mandatory, there
     294         * can be zero of the others.
     295         * 0  param=2             inter                 final           final+1
     296         * +-----+------------------+---------------------+-----------------+
     297         * | CSI | parameter bytes  | intermediate bytes  |   final byte    |
     298         * |     |   0x30 - 0x3f    |    0x20 - 0x2f      |   0x40 - 0x7e   |
     299         * | ^[[ | 0123456789:;<=>? | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ |
     300         * +-----+------------------+---------------------+-----------------+
     301         */
     302            param = 2;
     303
     304            for(inter = param; i + inter < size; inter++)
     305                if(buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f)
     306                    break;
     307
     308            for(final = inter; i + final < size; final++)
     309                if(buffer[i + final] < 0x20 || buffer[i + final] > 0x2f)
     310                    break;
     311
     312            if(buffer[i + final] < 0x40 || buffer[i + final] > 0x7e)
     313                break; /* Invalid Final Byte */
     314
     315            skip += final;
     316
     317            /* Sanity checks */
     318            if(param < inter && buffer[i + param] >= 0x3c)
     319            {
     320                fprintf(stderr, "private sequence \"^[[%.*s\"\n",
     321                        final - param + 1, buffer + i + param);
     322                continue; /* Private sequence, skip it entirely */
     323            }
     324
     325            if(final - param > 100)
     326                continue; /* Suspiciously long sequence, skip it */
     327
     328            /* Parse parameter bytes as per ECMA-48 5.4.2: Parameter string
     329             * format */
     330            if(param < inter)
     331            {
     332                argv[0] = 0;
     333                for(j = param; j < inter; j++)
    231334                {
     335                    if(buffer[i + j] == ';')
     336                        argv[++argc] = 0;
     337                    else if(buffer[i + j] >= '0' && buffer[i + j] <= '9')
     338                        argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0');
     339                }
     340                argc++;
     341            }
     342
     343            /* Interpret final byte. The code representations are given in
     344             * ECMA-48 5.4: Control sequences, and the code definitions are
     345             * given in ECMA-48 8.3: Definition of control functions. */
     346            switch(buffer[i + final])
     347            {
     348            case 'f': /* CUP - Cursor Position */
     349            case 'H': /* HVP - Character And Line Position */
     350                x = (argc > 1) ? argv[1] - 1 : 0;
     351                y = (argc > 0) ? argv[0] - 1 : 0;
     352                break;
     353            case 'A': /* CUU - Cursor Up */
     354                y -= argc ? argv[0] : 1;
     355                if(y < 0)
     356                    y = 0;
     357                break;
     358            case 'B': /* CUD - Cursor Down */
     359                y += argc ? argv[0] : 1;
     360                break;
     361            case 'C': /* CUF - Cursor Right */
     362                x += argc ? argv[0] : 1;
     363                break;
     364            case 'D': /* CUB - Cursor Left */
     365                x -= argc ? argv[0] : 1;
     366                if(x < 0)
    232367                    x = 0;
    233                     y++;
    234                 }
    235 
    236             if(buffer[i] == '\x1a' && size - i >= 8
    237                && !memcmp(buffer + i + 1, "SAUCE00", 7))
    238                 break; /* End before SAUCE data */
    239 
    240             if(buffer[i] == '\r')
    241                 continue; /* DOS sucks */
    242 
    243             if(buffer[i] == '\n')
    244                 {
    245                     x = 0;
    246                     y++;
    247                     continue;
    248                 }
    249 
    250             /* Interpret escape commands, as per Standard ECMA-48 "Control
    251              * Functions for Coded Character Sets", 5.4. Control sequences. */
    252             if(buffer[i] == '\x1b' && buffer[i + 1] == '[')
    253                 {
    254                     unsigned int argc = 0, argv[101];
    255                     unsigned int param, inter, final;
    256 
    257                     /* Compute offsets to parameter bytes, intermediate bytes and
    258                      * to the final byte. Only the final byte is mandatory, there
    259                      * can be zero of the others.
    260                      * 0  param=2             inter                 final           final+1
    261                      * +-----+------------------+---------------------+-----------------+
    262                      * | CSI | parameter bytes  | intermediate bytes  |   final byte    |
    263                      * |     |   0x30 - 0x3f    |    0x20 - 0x2f      |   0x40 - 0x7e   |
    264                      * | ^[[ | 0123456789:;<=>? | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ |
    265                      * +-----+------------------+---------------------+-----------------+
    266                      */
    267                     param = 2;
    268 
    269                     for(inter = param; i + inter < size; inter++)
    270                         if(buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f)
    271                             break;
    272 
    273                     for(final = inter; i + final < size; final++)
    274                         if(buffer[i + final] < 0x20 || buffer[i + final] > 0x2f)
    275                             break;
    276 
    277                     if(buffer[i + final] < 0x40 || buffer[i + final] > 0x7e)
    278                         break; /* Invalid Final Byte */
    279 
    280                     skip += final;
    281 
    282                     /* Sanity checks */
    283                     if(param < inter && buffer[i + param] >= 0x3c)
    284                         {
    285                             fprintf(stderr, "private sequence \"^[[%.*s\"\n",
    286                                     final - param + 1, buffer + i + param);
    287                             continue; /* Private sequence, skip it entirely */
    288                         }
    289 
    290                     if(final - param > 100)
    291                         continue; /* Suspiciously long sequence, skip it */
    292 
    293                     /* Parse parameter bytes as per ECMA-48 5.4.2: Parameter string
    294                      * format */
    295                     if(param < inter)
    296                         {
    297                             argv[0] = 0;
    298                             for(j = param; j < inter; j++)
    299                                 {
    300                                     if(buffer[i + j] == ';')
    301                                         argv[++argc] = 0;
    302                                     else if(buffer[i + j] >= '0' && buffer[i + j] <= '9')
    303                                         argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0');
    304                                 }
    305                             argc++;
    306                         }
    307 
    308                     /* Interpret final byte. The code representations are given in
    309                      * ECMA-48 5.4: Control sequences, and the code definitions are
    310                      * given in ECMA-48 8.3: Definition of control functions. */
    311                     switch(buffer[i + final])
    312                         {
    313                         case 'f': /* CUP - Cursor Position */
    314                         case 'H': /* HVP - Character And Line Position */
    315                             x = (argc > 1) ? argv[1] - 1 : 0;
    316                             y = (argc > 0) ? argv[0] - 1 : 0;
    317                             break;
    318                         case 'A': /* CUU - Cursor Up */
    319                             y -= argc ? argv[0] : 1;
    320                             if(y < 0)
    321                                 y = 0;
    322                             break;
    323                         case 'B': /* CUD - Cursor Down */
    324                             y += argc ? argv[0] : 1;
    325                             break;
    326                         case 'C': /* CUF - Cursor Right */
    327                             x += argc ? argv[0] : 1;
    328                             break;
    329                         case 'D': /* CUB - Cursor Left */
    330                             x -= argc ? argv[0] : 1;
    331                             if(x < 0)
    332                                 x = 0;
    333                             break;
    334                         case 's': /* Private (save cursor position) */
    335                             save_x = x;
    336                             save_y = y;
    337                             break;
    338                         case 'u': /* Private (reload cursor positin) */
    339                             x = save_x;
    340                             y = save_y;
    341                             break;
    342                         case 'J': /* ED - Erase In Page */
    343                             if(argv[0] == 2)
    344                                 x = y = 0;
    345                             break;
    346                         case 'K': /* EL - Erase In Line */
    347                             for(j = x; j < width; j++)
    348                                 _cucul_putchar32(cv, j, y, (uint32_t)' ');
    349                             x = width;
    350                             break;
    351                         case 'm': /* SGR - Select Graphic Rendition */
    352                             ansi_parse_grcm(cv, &grcm, argc, argv);
    353                             break;
    354                         default:
    355                             fprintf(stderr, "unknown command %c\n", buffer[i + final]);
    356                             break;
    357                         }
    358 
    359                     continue;
    360                 }
    361 
    362             /* We're going to paste a character. First make sure the canvas
    363              * is big enough. */
    364             if((unsigned int)y >= height)
    365                 {
    366                     height = y + 1;
    367                     cucul_set_canvas_size(cv, width, height);
    368                 }
    369 
    370             /* Now paste our character */
    371             _cucul_putchar32(cv, x, y, _cucul_cp437_to_utf32(buffer[i]));
    372             x++;
    373         }
     368                break;
     369            case 's': /* Private (save cursor position) */
     370                save_x = x;
     371                save_y = y;
     372                break;
     373            case 'u': /* Private (reload cursor positin) */
     374                x = save_x;
     375                y = save_y;
     376                break;
     377            case 'J': /* ED - Erase In Page */
     378                if(argv[0] == 2)
     379                    x = y = 0;
     380                break;
     381            case 'K': /* EL - Erase In Line */
     382                for(j = x; j < width; j++)
     383                    _cucul_putchar32(cv, j, y, (uint32_t)' ');
     384                x = width;
     385                break;
     386            case 'm': /* SGR - Select Graphic Rendition */
     387                ansi_parse_grcm(cv, &grcm, argc, argv);
     388                break;
     389            default:
     390                fprintf(stderr, "unknown command %c\n", buffer[i + final]);
     391                break;
     392            }
     393
     394            continue;
     395        }
     396
     397        /* We're going to paste a character. First make sure the canvas
     398         * is big enough. */
     399        if((unsigned int)y >= height)
     400        {
     401            height = y + 1;
     402            cucul_set_canvas_size(cv, width, height);
     403        }
     404
     405        /* Now paste our character */
     406        _cucul_putchar32(cv, x, y, _cucul_cp437_to_utf32(buffer[i]));
     407        x++;
     408    }
    374409
    375410    return cv;
     
    382417{
    383418    static uint8_t const ansi2cucul[] =
    384         {
    385             CUCUL_COLOR_BLACK, CUCUL_COLOR_RED,
    386             CUCUL_COLOR_GREEN, CUCUL_COLOR_BROWN,
    387             CUCUL_COLOR_BLUE, CUCUL_COLOR_MAGENTA,
    388             CUCUL_COLOR_CYAN, CUCUL_COLOR_LIGHTGRAY
    389         };
     419    {
     420        CUCUL_COLOR_BLACK, CUCUL_COLOR_RED,
     421        CUCUL_COLOR_GREEN, CUCUL_COLOR_BROWN,
     422        CUCUL_COLOR_BLUE, CUCUL_COLOR_MAGENTA,
     423        CUCUL_COLOR_CYAN, CUCUL_COLOR_LIGHTGRAY
     424    };
    390425
    391426    unsigned int j;
     
    393428
    394429    for(j = 0; j < argc; j++)
    395         {
    396             /* Defined in ECMA-48 8.3.117: SGR - SELECT GRAPHIC RENDITION */
    397             if(argv[j] >= 30 && argv[j] <= 37)
    398                 g->fg = ansi2cucul[argv[j] - 30];
    399             else if(argv[j] >= 40 && argv[j] <= 47)
    400                 g->bg = ansi2cucul[argv[j] - 40];
    401             else if(argv[j] >= 90 && argv[j] <= 97)
    402                 g->fg = ansi2cucul[argv[j] - 90] + 8;
    403             else if(argv[j] >= 100 && argv[j] <= 107)
    404                 g->bg = ansi2cucul[argv[j] - 100] + 8;
    405             else switch(argv[j])
    406                 {
    407                 case 0: /* default rendition */
    408                     g->fg = CUCUL_COLOR_DEFAULT;
    409                     g->bg = CUCUL_COLOR_DEFAULT;
    410                     g->bold = g->negative = g->concealed = 0;
    411                     break;
    412                 case 1: /* bold or increased intensity */
    413                     g->bold = 1;
    414                     break;
    415                 case 4: /* singly underlined */
    416                     break;
    417                 case 5: /* slowly blinking (less then 150 per minute) */
    418                     break;
    419                 case 7: /* negative image */
    420                     g->negative = 1;
    421                     break;
    422                 case 8: /* concealed characters */
    423                     g->concealed = 1;
    424                     break;
    425                 case 22: /* normal colour or normal intensity (neither bold nor faint) */
    426                     g->bold = 0;
    427                     break;
    428                 case 28: /* revealed characters */
    429                     g->concealed = 0;
    430                     break;
    431                 case 39: /* default display colour (implementation-defined) */
    432                     g->fg = CUCUL_COLOR_DEFAULT;
    433                     break;
    434                 case 49: /* default background colour (implementation-defined) */
    435                     g->bg = CUCUL_COLOR_DEFAULT;
    436                     break;
    437                 default:
    438                     fprintf(stderr, "unknown sgr %i\n", argv[j]);
    439                     break;
    440                 }
    441         }
     430    {
     431        /* Defined in ECMA-48 8.3.117: SGR - SELECT GRAPHIC RENDITION */
     432        if(argv[j] >= 30 && argv[j] <= 37)
     433            g->fg = ansi2cucul[argv[j] - 30];
     434        else if(argv[j] >= 40 && argv[j] <= 47)
     435            g->bg = ansi2cucul[argv[j] - 40];
     436        else if(argv[j] >= 90 && argv[j] <= 97)
     437            g->fg = ansi2cucul[argv[j] - 90] + 8;
     438        else if(argv[j] >= 100 && argv[j] <= 107)
     439            g->bg = ansi2cucul[argv[j] - 100] + 8;
     440        else switch(argv[j])
     441        {
     442        case 0: /* default rendition */
     443            g->fg = CUCUL_COLOR_DEFAULT;
     444            g->bg = CUCUL_COLOR_DEFAULT;
     445            g->bold = g->negative = g->concealed = 0;
     446            break;
     447        case 1: /* bold or increased intensity */
     448            g->bold = 1;
     449            break;
     450        case 4: /* singly underlined */
     451            break;
     452        case 5: /* slowly blinking (less then 150 per minute) */
     453            break;
     454        case 7: /* negative image */
     455            g->negative = 1;
     456            break;
     457        case 8: /* concealed characters */
     458            g->concealed = 1;
     459            break;
     460        case 22: /* normal colour or normal intensity (neither bold nor faint) */
     461            g->bold = 0;
     462            break;
     463        case 28: /* revealed characters */
     464            g->concealed = 0;
     465            break;
     466        case 39: /* default display colour (implementation-defined) */
     467            g->fg = CUCUL_COLOR_DEFAULT;
     468            break;
     469        case 49: /* default background colour (implementation-defined) */
     470            g->bg = CUCUL_COLOR_DEFAULT;
     471            break;
     472        default:
     473            fprintf(stderr, "unknown sgr %i\n", argv[j]);
     474            break;
     475        }
     476    }
    442477
    443478    if(g->concealed)
    444         {
    445             myfg = mybg = CUCUL_COLOR_TRANSPARENT;
    446         }
     479    {
     480        myfg = mybg = CUCUL_COLOR_TRANSPARENT;
     481    }
    447482    else
    448         {
    449             myfg = g->negative ? g->bg : g->fg;
    450             mybg = g->negative ? g->fg : g->bg;
    451 
    452             if(g->bold)
    453                 {
    454                     if(myfg < 8)
    455                         myfg += 8;
    456                     else if(myfg == CUCUL_COLOR_DEFAULT)
    457                         myfg = CUCUL_COLOR_WHITE;
    458                 }
    459         }
     483    {
     484        myfg = g->negative ? g->bg : g->fg;
     485        mybg = g->negative ? g->fg : g->bg;
     486
     487        if(g->bold)
     488        {
     489            if(myfg < 8)
     490                myfg += 8;
     491            else if(myfg == CUCUL_COLOR_DEFAULT)
     492                myfg = CUCUL_COLOR_WHITE;
     493        }
     494    }
    460495
    461496    cucul_set_color(cv, myfg, mybg);
Note: See TracChangeset for help on using the changeset viewer.