Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/ui/src/paint.c

    r214aefb r1eaead4  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2023 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3838#include <gfx/context.h>
    3939#include <gfx/render.h>
     40#include <gfx/text.h>
     41#include <ui/accel.h>
    4042#include <ui/paint.h>
     43#include <stdlib.h>
     44#include <str.h>
    4145#include "../private/resource.h"
     46
     47/** Single box characters */
     48static ui_box_chars_t single_box_chars = {
     49        {
     50                { "\u250c", "\u2500", "\u2510" },
     51                { "\u2502", " ",      "\u2502" },
     52                { "\u2514", "\u2500", "\u2518" }
     53        }
     54};
     55
     56/** Double box characters */
     57static ui_box_chars_t double_box_chars = {
     58        {
     59                { "\u2554", "\u2550", "\u2557" },
     60                { "\u2551", " ",      "\u2551" },
     61                { "\u255a", "\u2550", "\u255d" }
     62        }
     63};
     64
     65/** Single horizontal brace characters */
     66static ui_brace_chars_t single_hbrace_chars = {
     67        .start = "\u251c",
     68        .middle = "\u2500",
     69        .end = "\u2524"
     70};
     71
     72/** Double horizontal brace characters */
     73static ui_brace_chars_t double_hbrace_chars = {
     74        .start = "\u2560",
     75        .middle = "\u2550",
     76        .end = "\u2563"
     77};
    4278
    4379/** Paint bevel.
     
    4985 * @param thickness Bevel thickness in pixels
    5086 * @param inside Place to store rectangle of the interior or @c NULL
    51  * @reutrn EOK on success or an error code
     87 * @return EOK on success or an error code
    5288 */
    5389errno_t ui_paint_bevel(gfx_context_t *gc, gfx_rect_t *rect,
     
    107143        }
    108144
    109         if (inside != NULL) {
    110                 inside->p0.x = rect->p0.x + thickness;
    111                 inside->p0.y = rect->p0.y + thickness;
    112                 inside->p1.x = rect->p1.x - thickness;
    113                 inside->p1.y = rect->p1.y - thickness;
    114         }
     145        if (inside != NULL)
     146                ui_paint_get_bevel_inside(gc, rect, thickness, inside);
    115147
    116148        return EOK;
    117149error:
    118150        return rc;
     151}
     152
     153/** Get bevel interior rectangle.
     154 *
     155 * Get the bevel interior rectangle without painting it.
     156 *
     157 * @param gc Graphic context
     158 * @param rect Rectangle to paint into
     159 * @param thickness Bevel thickness in pixels
     160 * @param inside Place to store rectangle of the interior
     161 */
     162void ui_paint_get_bevel_inside(gfx_context_t *gc, gfx_rect_t *rect,
     163    gfx_coord_t thickness, gfx_rect_t *inside)
     164{
     165        inside->p0.x = rect->p0.x + thickness;
     166        inside->p0.y = rect->p0.y + thickness;
     167        inside->p1.x = rect->p1.x - thickness;
     168        inside->p1.y = rect->p1.y - thickness;
    119169}
    120170
     
    147197error:
    148198        return rc;
     199}
     200
     201/** Get inset frame interior rectangle.
     202 *
     203 * This allows one to get the interior rectangle without actually painting
     204 * the inset frame.
     205 *
     206 * @param resource UI resource
     207 * @param rect Rectangle to paint onto
     208 * @param inside Place to store inside rectangle or @c NULL
     209 */
     210void ui_paint_get_inset_frame_inside(ui_resource_t *resource, gfx_rect_t *rect,
     211    gfx_rect_t *inside)
     212{
     213        ui_paint_get_bevel_inside(resource->gc, rect, 2, inside);
    149214}
    150215
     
    295360}
    296361
     362/** Paint upward pointing triangle.
     363 *
     364 * @param gc Graphic context
     365 * @param pos Center position
     366 * @param n Length of triangle side
     367 * @return EOK on success or an error code
     368 */
     369errno_t ui_paint_up_triangle(gfx_context_t *gc, gfx_coord2_t *pos,
     370    gfx_coord_t n)
     371{
     372        gfx_coord_t i;
     373        errno_t rc;
     374        gfx_rect_t rect;
     375
     376        for (i = 0; i < n; i++) {
     377                rect.p0.x = pos->x - i;
     378                rect.p0.y = pos->y - n / 2 + i;
     379                rect.p1.x = pos->x + i + 1;
     380                rect.p1.y = pos->y - n / 2 + i + 1;
     381                rc = gfx_fill_rect(gc, &rect);
     382                if (rc != EOK)
     383                        return rc;
     384        }
     385
     386        return EOK;
     387}
     388
     389/** Paint downward pointing triangle.
     390 *
     391 * @param gc Graphic context
     392 * @param pos Center position
     393 * @param n Length of triangle side
     394 * @return EOK on success or an error code
     395 */
     396errno_t ui_paint_down_triangle(gfx_context_t *gc, gfx_coord2_t *pos,
     397    gfx_coord_t n)
     398{
     399        gfx_coord_t i;
     400        errno_t rc;
     401        gfx_rect_t rect;
     402
     403        for (i = 0; i < n; i++) {
     404                rect.p0.x = pos->x - i;
     405                rect.p0.y = pos->y + n / 2 - i;
     406                rect.p1.x = pos->x + i + 1;
     407                rect.p1.y = pos->y + n / 2 - i + 1;
     408                rc = gfx_fill_rect(gc, &rect);
     409                if (rc != EOK)
     410                        return rc;
     411        }
     412
     413        return EOK;
     414}
     415
     416/** Paint left pointing triangle.
     417 *
     418 * @param gc Graphic context
     419 * @param pos Center position
     420 * @param n Length of triangle side
     421 * @return EOK on success or an error code
     422 */
     423errno_t ui_paint_left_triangle(gfx_context_t *gc, gfx_coord2_t *pos,
     424    gfx_coord_t n)
     425{
     426        gfx_coord_t i;
     427        errno_t rc;
     428        gfx_rect_t rect;
     429
     430        for (i = 0; i < n; i++) {
     431                rect.p0.x = pos->x - n / 2 + i;
     432                rect.p0.y = pos->y - i;
     433                rect.p1.x = pos->x - n / 2 + i + 1;
     434                rect.p1.y = pos->y + i + 1;
     435                rc = gfx_fill_rect(gc, &rect);
     436                if (rc != EOK)
     437                        return rc;
     438        }
     439
     440        return EOK;
     441}
     442
     443/** Paint right pointing triangle.
     444 *
     445 * @param gc Graphic context
     446 * @param pos Center position
     447 * @param n Length of triangle side
     448 * @return EOK on success or an error code
     449 */
     450errno_t ui_paint_right_triangle(gfx_context_t *gc, gfx_coord2_t *pos,
     451    gfx_coord_t n)
     452{
     453        gfx_coord_t i;
     454        errno_t rc;
     455        gfx_rect_t rect;
     456
     457        for (i = 0; i < n; i++) {
     458                rect.p0.x = pos->x + n / 2 - i;
     459                rect.p0.y = pos->y - i;
     460                rect.p1.x = pos->x + n / 2 - i + 1;
     461                rect.p1.y = pos->y + i + 1;
     462                rc = gfx_fill_rect(gc, &rect);
     463                if (rc != EOK)
     464                        return rc;
     465        }
     466
     467        return EOK;
     468}
     469
     470/** Paint diagonal cross (X).
     471 *
     472 * @param gc Graphic context
     473 * @param pos Center position
     474 * @param n Length of each leg
     475 * @param w Pen width
     476 * @param h Pen height
     477 * @return EOK on success or an error code
     478 */
     479errno_t ui_paint_cross(gfx_context_t *gc, gfx_coord2_t *pos,
     480    gfx_coord_t n, gfx_coord_t w, gfx_coord_t h)
     481{
     482        gfx_coord_t i;
     483        gfx_rect_t rect;
     484        errno_t rc;
     485
     486        rect.p0.x = pos->x;
     487        rect.p0.y = pos->y;
     488        rect.p1.x = pos->x + w;
     489        rect.p1.y = pos->y + h;
     490        rc = gfx_fill_rect(gc, &rect);
     491        if (rc != EOK)
     492                return rc;
     493
     494        for (i = 1; i < n; i++) {
     495                rect.p0.x = pos->x - i;
     496                rect.p0.y = pos->y - i;
     497                rect.p1.x = pos->x - i + w;
     498                rect.p1.y = pos->y - i + h;
     499                rc = gfx_fill_rect(gc, &rect);
     500                if (rc != EOK)
     501                        return rc;
     502
     503                rect.p0.x = pos->x - i;
     504                rect.p0.y = pos->y + i;
     505                rect.p1.x = pos->x - i + w;
     506                rect.p1.y = pos->y + i + h;
     507                rc = gfx_fill_rect(gc, &rect);
     508                if (rc != EOK)
     509                        return rc;
     510
     511                rect.p0.x = pos->x + i;
     512                rect.p0.y = pos->y - i;
     513                rect.p1.x = pos->x + i + w;
     514                rect.p1.y = pos->y - i + h;
     515                rc = gfx_fill_rect(gc, &rect);
     516                if (rc != EOK)
     517                        return rc;
     518
     519                rect.p0.x = pos->x + i;
     520                rect.p0.y = pos->y + i;
     521                rect.p1.x = pos->x + i + w;
     522                rect.p1.y = pos->y + i + h;
     523                rc = gfx_fill_rect(gc, &rect);
     524                if (rc != EOK)
     525                        return rc;
     526        }
     527
     528        return EOK;
     529}
     530
     531/** Paint minimize icon.
     532 *
     533 * @param resource UI resource
     534 * @param pos Center position
     535 * @param w Icon width
     536 * @param h Icon height
     537 * @return EOK on success or an error code
     538 */
     539errno_t ui_paint_minicon(ui_resource_t *resource, gfx_coord2_t *pos,
     540    gfx_coord_t w, gfx_coord_t h)
     541{
     542        gfx_rect_t rect;
     543        errno_t rc;
     544
     545        rc = gfx_set_color(resource->gc, resource->btn_text_color);
     546        if (rc != EOK)
     547                return rc;
     548
     549        rect.p0.x = pos->x - w / 2;
     550        rect.p0.y = pos->y + h / 2 - 2;
     551        rect.p1.x = rect.p0.x + w;
     552        rect.p1.y = rect.p0.y + 2;
     553        rc = gfx_fill_rect(resource->gc, &rect);
     554        if (rc != EOK)
     555                return rc;
     556
     557        return EOK;
     558}
     559
     560/** Paint maximize icon.
     561 *
     562 * @param resource UI resource
     563 * @param pos Center position
     564 * @param w Icon width
     565 * @param h Icon height
     566 * @return EOK on success or an error code
     567 */
     568errno_t ui_paint_maxicon(ui_resource_t *resource, gfx_coord2_t *pos,
     569    gfx_coord_t w, gfx_coord_t h)
     570{
     571        gfx_rect_t rect;
     572        errno_t rc;
     573
     574        rc = gfx_set_color(resource->gc, resource->btn_text_color);
     575        if (rc != EOK)
     576                return rc;
     577
     578        rect.p0.x = pos->x - w / 2;
     579        rect.p0.y = pos->y - h / 2;
     580        rect.p1.x = rect.p0.x + w;
     581        rect.p1.y = rect.p0.y + h;
     582        rc = gfx_fill_rect(resource->gc, &rect);
     583        if (rc != EOK)
     584                return rc;
     585
     586        rc = gfx_set_color(resource->gc, resource->btn_face_color);
     587        if (rc != EOK)
     588                return rc;
     589
     590        rect.p0.x += 1;
     591        rect.p0.y += 2;
     592        rect.p1.x -= 1;
     593        rect.p1.y -= 1;
     594        rc = gfx_fill_rect(resource->gc, &rect);
     595        if (rc != EOK)
     596                return rc;
     597
     598        return EOK;
     599}
     600
     601/** Paint unmaximize icon.
     602 *
     603 * Unmaximize icon consists of two overlapping window icons.
     604 *
     605 * @param resource UI resource
     606 * @param pos Center position
     607 * @param w Window icon width
     608 * @param h Window icon height
     609 * @param dw Horizontal distance between window icon centers
     610 * @param dh Vertical distance between window icon centers
     611 * @return EOK on success or an error code
     612 */
     613errno_t ui_paint_unmaxicon(ui_resource_t *resource, gfx_coord2_t *pos,
     614    gfx_coord_t w, gfx_coord_t h, gfx_coord_t dw, gfx_coord_t dh)
     615{
     616        gfx_coord2_t p;
     617        errno_t rc;
     618
     619        p.x = pos->x + dw / 2;
     620        p.y = pos->y - dh / 2;
     621        rc = ui_paint_maxicon(resource, &p, w, h);
     622        if (rc != EOK)
     623                return rc;
     624
     625        p.x = pos->x - dw / 2;
     626        p.y = pos->y + dh / 2;
     627        rc = ui_paint_maxicon(resource, &p, w, h);
     628        if (rc != EOK)
     629                return rc;
     630
     631        return EOK;
     632}
     633
     634/** Paint a custom text box.
     635 *
     636 * Paint a text box using user-provided box chars.
     637 *
     638 * @param resource UI resource
     639 * @param rect Rectangle inside which to paint the box
     640 * @param style Box style
     641 * @param boxc Box characters
     642 * @param color Color
     643 * @return EOK on success or an error code
     644 */
     645errno_t ui_paint_text_box_custom(ui_resource_t *resource, gfx_rect_t *rect,
     646    ui_box_chars_t *boxc, gfx_color_t *color)
     647{
     648        errno_t rc;
     649        gfx_text_fmt_t fmt;
     650        gfx_rect_t srect;
     651        gfx_coord2_t pos;
     652        gfx_coord2_t dim;
     653        size_t bufsz;
     654        size_t off;
     655        int i;
     656        gfx_coord_t y;
     657        char *str = NULL;
     658
     659        gfx_rect_points_sort(rect, &srect);
     660        gfx_rect_dims(&srect, &dim);
     661
     662        /* Is rectangle large enough to hold box? */
     663        if (dim.x < 2 || dim.y < 2)
     664                return EOK;
     665
     666        gfx_text_fmt_init(&fmt);
     667        fmt.font = resource->font;
     668        fmt.color = color;
     669
     670        bufsz = str_size(boxc->c[0][0]) +
     671            str_size(boxc->c[0][1]) * (dim.x - 2) +
     672            str_size(boxc->c[0][2]) + 1;
     673
     674        str = malloc(bufsz);
     675        if (str == NULL)
     676                return ENOMEM;
     677
     678        /* Top edge and corners */
     679
     680        str_cpy(str, bufsz, boxc->c[0][0]);
     681        off = str_size(boxc->c[0][0]);
     682
     683        for (i = 1; i < dim.x - 1; i++) {
     684                str_cpy(str + off, bufsz - off, boxc->c[0][1]);
     685                off += str_size(boxc->c[0][1]);
     686        }
     687
     688        str_cpy(str + off, bufsz - off, boxc->c[0][2]);
     689        off += str_size(boxc->c[0][2]);
     690        str[off] = '\0';
     691
     692        pos = rect->p0;
     693        rc = gfx_puttext(&pos, &fmt, str);
     694        if (rc != EOK)
     695                goto error;
     696
     697        /* Vertical edges */
     698        for (y = rect->p0.y + 1; y < rect->p1.y - 1; y++) {
     699                pos.y = y;
     700
     701                pos.x = rect->p0.x;
     702                rc = gfx_puttext(&pos, &fmt, boxc->c[1][0]);
     703                if (rc != EOK)
     704                        goto error;
     705
     706                pos.x = rect->p1.x - 1;
     707                rc = gfx_puttext(&pos, &fmt, boxc->c[1][2]);
     708                if (rc != EOK)
     709                        goto error;
     710        }
     711
     712        /* Bottom edge and corners */
     713
     714        str_cpy(str, bufsz, boxc->c[2][0]);
     715        off = str_size(boxc->c[2][0]);
     716
     717        for (i = 1; i < dim.x - 1; i++) {
     718                str_cpy(str + off, bufsz - off, boxc->c[2][1]);
     719                off += str_size(boxc->c[2][1]);
     720        }
     721
     722        str_cpy(str + off, bufsz - off, boxc->c[2][2]);
     723        off += str_size(boxc->c[2][2]);
     724        str[off] = '\0';
     725
     726        pos.x = rect->p0.x;
     727        pos.y = rect->p1.y - 1;
     728        rc = gfx_puttext(&pos, &fmt, str);
     729        if (rc != EOK)
     730                goto error;
     731
     732        free(str);
     733        return EOK;
     734error:
     735        if (str != NULL)
     736                free(str);
     737        return rc;
     738}
     739
     740/** Paint a text box.
     741 *
     742 * Paint a text box with the specified style.
     743 *
     744 * @param resource UI resource
     745 * @param rect Rectangle inside which to paint the box
     746 * @param style Box style
     747 * @param color Color
     748 * @return EOK on success or an error code
     749 */
     750errno_t ui_paint_text_box(ui_resource_t *resource, gfx_rect_t *rect,
     751    ui_box_style_t style, gfx_color_t *color)
     752{
     753        ui_box_chars_t *boxc = NULL;
     754
     755        switch (style) {
     756        case ui_box_single:
     757                boxc = &single_box_chars;
     758                break;
     759        case ui_box_double:
     760                boxc = &double_box_chars;
     761                break;
     762        }
     763
     764        if (boxc == NULL)
     765                return EINVAL;
     766
     767        return ui_paint_text_box_custom(resource, rect, boxc, color);
     768}
     769
     770/** Paint a text horizontal brace.
     771 *
     772 * @param resource UI resource
     773 * @param rect Rectangle inside which to paint the brace (height should
     774 *             be 1).
     775 * @param style Box style
     776 * @param color Color
     777 * @return EOK on success or an error code
     778 */
     779errno_t ui_paint_text_hbrace(ui_resource_t *resource, gfx_rect_t *rect,
     780    ui_box_style_t style, gfx_color_t *color)
     781{
     782        errno_t rc;
     783        gfx_text_fmt_t fmt;
     784        gfx_rect_t srect;
     785        gfx_coord2_t pos;
     786        gfx_coord2_t dim;
     787        size_t bufsz;
     788        size_t off;
     789        int i;
     790        char *str = NULL;
     791        ui_brace_chars_t *hbc = NULL;
     792
     793        gfx_rect_points_sort(rect, &srect);
     794        gfx_rect_dims(&srect, &dim);
     795
     796        /* Is rectangle large enough to hold brace? */
     797        if (dim.x < 2 || dim.y < 1)
     798                return EOK;
     799
     800        switch (style) {
     801        case ui_box_single:
     802                hbc = &single_hbrace_chars;
     803                break;
     804        case ui_box_double:
     805                hbc = &double_hbrace_chars;
     806                break;
     807        }
     808
     809        if (hbc == NULL)
     810                return EINVAL;
     811
     812        gfx_text_fmt_init(&fmt);
     813        fmt.font = resource->font;
     814        fmt.color = color;
     815
     816        bufsz = str_size(hbc->start) +
     817            str_size(hbc->middle) * (dim.x - 2) +
     818            str_size(hbc->end) + 1;
     819
     820        str = malloc(bufsz);
     821        if (str == NULL)
     822                return ENOMEM;
     823
     824        str_cpy(str, bufsz, hbc->start);
     825        off = str_size(hbc->start);
     826
     827        for (i = 1; i < dim.x - 1; i++) {
     828                str_cpy(str + off, bufsz - off, hbc->middle);
     829                off += str_size(hbc->middle);
     830        }
     831
     832        str_cpy(str + off, bufsz - off, hbc->end);
     833        off += str_size(hbc->end);
     834        str[off] = '\0';
     835
     836        pos = rect->p0;
     837        rc = gfx_puttext(&pos, &fmt, str);
     838        if (rc != EOK)
     839                goto error;
     840
     841        free(str);
     842        return EOK;
     843error:
     844        if (str != NULL)
     845                free(str);
     846        return rc;
     847}
     848
     849/** Fill rectangle with text character.
     850 *
     851 * @param resource UI resource
     852 * @param rect Rectangle
     853 * @param color Color
     854 * @param gchar Character to fill with
     855 * @return EOK on success or an error code
     856 */
     857errno_t ui_paint_text_rect(ui_resource_t *resource, gfx_rect_t *rect,
     858    gfx_color_t *color, const char *gchar)
     859{
     860        gfx_coord2_t pos;
     861        gfx_text_fmt_t fmt;
     862        gfx_rect_t srect;
     863        gfx_coord_t w, i;
     864        char *buf;
     865        size_t gcharsz;
     866        errno_t rc;
     867
     868        gfx_rect_points_sort(rect, &srect);
     869
     870        gfx_text_fmt_init(&fmt);
     871        fmt.font = resource->font;
     872        fmt.color = color;
     873        fmt.halign = gfx_halign_left;
     874        fmt.valign = gfx_valign_top;
     875
     876        w = srect.p1.x - srect.p0.x;
     877        if (w == 0)
     878                return EOK;
     879
     880        gcharsz = str_size(gchar);
     881
     882        buf = malloc(w * gcharsz + 1);
     883        if (buf == NULL)
     884                return ENOMEM;
     885
     886        for (i = 0; i < w; i++)
     887                str_cpy(buf + i * gcharsz, (w - i) * gcharsz + 1, gchar);
     888        buf[w * gcharsz] = '\0';
     889
     890        pos.x = srect.p0.x;
     891        for (pos.y = srect.p0.y; pos.y < srect.p1.y; pos.y++) {
     892                rc = gfx_puttext(&pos, &fmt, buf);
     893                if (rc != EOK)
     894                        goto error;
     895        }
     896
     897        free(buf);
     898        return EOK;
     899error:
     900        free(buf);
     901        return rc;
     902}
     903
     904/** Initialize UI text formatting structure.
     905 *
     906 * UI text formatting structure must always be initialized using this function
     907 * first.
     908 *
     909 * @param fmt UI text formatting structure
     910 */
     911void ui_text_fmt_init(ui_text_fmt_t *fmt)
     912{
     913        memset(fmt, 0, sizeof(ui_text_fmt_t));
     914}
     915
     916/** Compute UI text width.
     917 *
     918 * @param font Font
     919 * @param str String
     920 * @return Text width
     921 */
     922gfx_coord_t ui_text_width(gfx_font_t *font, const char *str)
     923{
     924        gfx_coord_t w;
     925        gfx_coord_t tw;
     926        const char *sp;
     927
     928        /* Text including tildes */
     929        w = gfx_text_width(font, str);
     930        tw = gfx_text_width(font, "~");
     931
     932        /* Subtract width of singular tildes */
     933        sp = str;
     934        while (*sp != '\0') {
     935                if (*sp == '~' && sp[1] != '~')
     936                        w -= tw;
     937                ++sp;
     938        }
     939
     940        return w;
     941}
     942
     943/** Paint text (with highlighting markup).
     944 *
     945 * Paint some text with highlighted sections enclosed with tilde characters
     946 * ('~'). A literal tilde can be printed with "~~". Text can be highlighted
     947 * with an underline or different color, based on display capabilities.
     948 *
     949 * @param pos Anchor position
     950 * @param fmt Text formatting
     951 * @param str String containing '~' markup
     952 *
     953 * @return EOK on success or an error code
     954 */
     955errno_t ui_paint_text(gfx_coord2_t *pos, ui_text_fmt_t *fmt, const char *str)
     956{
     957        gfx_coord2_t tpos;
     958        gfx_text_fmt_t tfmt;
     959        char *buf;
     960        char *endptr;
     961        const char *sp;
     962        errno_t rc;
     963
     964        /* Break down string into list of (non)highlighted parts */
     965        rc = ui_accel_process(str, &buf, &endptr);
     966        if (rc != EOK)
     967                return rc;
     968
     969        gfx_text_fmt_init(&tfmt);
     970        tfmt.font = fmt->font;
     971        tfmt.color = fmt->color;
     972        tfmt.halign = fmt->halign;
     973        tfmt.width = fmt->width;
     974        tfmt.valign = fmt->valign;
     975        tfmt.underline = false;
     976
     977        tpos = *pos;
     978        sp = buf;
     979        while (sp != endptr) {
     980                /* Print the current string */
     981                rc = gfx_puttext(&tpos, &tfmt, sp);
     982                if (rc != EOK)
     983                        goto error;
     984
     985                gfx_text_cont(&tpos, &tfmt, sp, &tpos, &tfmt);
     986                tfmt.underline = !tfmt.underline;
     987                tfmt.color = tfmt.underline ? fmt->hgl_color : fmt->color;
     988
     989                /* Skip to the next string */
     990                while (*sp != '\0')
     991                        ++sp;
     992                ++sp;
     993        }
     994
     995        free(buf);
     996        return EOK;
     997error:
     998        free(buf);
     999        return rc;
     1000}
     1001
    2971002/** @}
    2981003 */
Note: See TracChangeset for help on using the changeset viewer.