fopencookie(3)

الاسم
fopencookie - فتح دفق مخصص

المكتبة
مكتبة سي المعيارية (libc، -lc)

موجز
#define _GNU_SOURCE         /* See feature_test_macros(7) */
#define _FILE_OFFSET_BITS 64
#include <stdio.h>

FILE *fopencookie(void *restrict cookie, const char *restrict mode,
                  cookie_io_functions_t io_funcs);

الوصف
تسمح الدالة fopencookie() للمبرمج بإنشاء تنفيذ مخصص لدفق إدخال/إخراج قياسي. يمكن لهذا التنفيذ تخزين بيانات الدفق في موقع يختاره بنفسه؛ على سبيل المثال، تُستخدم fopencookie() لتنفيذ fmemopen(3)، التي توفر واجهة دفق للبيانات المخزنة في مخزن مؤقت في الذاكرة.

لإنشاء دفق مخصص، يجب على المبرمج:

•   تنفيذ أربع دوال "خطافية" تُستخدم داخليًا بواسطة مكتبة الإدخال/الإخراج القياسية عند تنفيذ الإدخال/الإخراج على الدفق.

•   تحديد نوع بيانات "كعكة" (cookie)، وهي بنية توفر معلومات الحفظ والسجلات (مثل مكان تخزين البيانات) التي تُستخدم من قِبل دالات الخطاف (hook functions) المذكورة سابقاً. لا تحوز حزمة الإدخال/الإخراج القياسية أي معرفة بمحتويات هذه الكعكة (لذا تُعرّف بالنوع void * عند تمريرها إلى الدالة fopencookie())، ولكنها تمرر الكعكة تلقائياً بصفتها وسيطاً أولاً عند استدعاء دالات الخطاف.

•   استدعاء fopencookie() لفتح دفق جديد وربط الخبيئة ودوال الخطاف بهذا الدفق.

تخدم الدالة fopencookie() غرضًا مشابهًا لـ fopen(3): فهي تفتح دفقًا جديدًا وتُعيد مؤشرًا إلى كائن FILE يُستخدم للتعامل مع ذلك الدفق.

الوسيط cookie هو مؤشر إلى هيكل الخبيئة الخاص بالمستدعي الذي سيُربط بالدفق الجديد. يُوفر هذا المؤشر كوسيط أول عندما تستدعي مكتبة الإدخال/الإخراج القياسية أيًا من دوال الخطاف الموصوفة أدناه.

يخدم الوسيط mode نفس الغرض كما في fopen(3). الأوضاع التالية مدعومة: r، w، a، r+، w+، و a+. انظر fopen(3) للتفاصيل.

الوسيط io_funcs هو هيكل يحتوي على أربعة حقول تشير إلى دوال الخطاف المعرفة من قبل المبرمج والتي تُستخدم لتنفيذ هذا الدفق. يُعرف الهيكل كالتالي

    typedef struct {
        cookie_read_function_t  *read;
        cookie_write_function_t *write;
        cookie_seek_function_t  *seek;
        cookie_close_function_t *close;
    } cookie_io_functions_t;

الحقول الأربعة هي كالتالي:

cookie_read_function_t *read
    تنفذ هذه الدالة عمليات القراءة للدفق. عند استدعائها، تتلقى ثلاثة وسائط:

        ssize_t read(void *cookie, char *buf, size_t size);

    الوسيطان buf و size هما، على التوالي، مخزن يمكن وضع بيانات الإدخال فيه وحجم ذلك المخزن. كنتيجة للدالة، يجب أن تُعيد دالة read عدد البايتات المنسوخة إلى buf، أو 0 عند نهاية الملف، أو -1 عند الخطأ. يجب أن تُحدّث دالة read إزاحة الدفق بشكل مناسب.

    إذا كان *read مؤشرًا فارغًا، فإن القراءات من الدفق المخصص تُعيد دائمًا نهاية الملف.

cookie_write_function_t *write
    تنفذ هذه الدالة عمليات الكتابة للدفق. عند استدعائها، تستقبل ثلاث وسائط:

        ssize_t write(void *cookie, const char *buf, size_t size);

    الوسيطان buf و size هما، على التوالي، مخزن بيانات سيُخرج إلى الدفق وحجم ذلك المخزن. كنتيجة لدالتها، يجب على دالة write أن تُرجع عدد البايتات المنسوخة من buf، أو 0 عند الخطأ. (يجب ألا تُرجع الدالة قيمة سالبة.) يجب على دالة write أن تُحدّث إزاحة الدفق بشكل مناسب.

    إذا كان *write مؤشرًا فارغًا، فسيُتجاهل الإخراج إلى الدفق.

cookie_seek_function_t *seek
    تنفذ هذه الدالة عمليات البحث في الدفق. عند استدعائها، تستقبل ثلاث وسائط:

        int seek(void *cookie, off_t *offset, int whence);

    يحدد الوسيط *offset إزاحة الملف الجديدة اعتمادًا على أي من القيم الثلاث التالية المُقدمة في whence:

    SEEK_SET
        يجب ضبط إزاحة الدفق على *offset بايت من بداية الدفق.

    SEEK_CUR
        يجب إضافة *offset إلى إزاحة الدفق الحالية.

    SEEK_END
        يجب ضبط إزاحة الدفق على حجم الدفق زائد *offset.

    قبل الإرجاع، يجب على دالة seek أن تُحدّث *offset للإشارة إلى إزاحة الدفق الجديدة.

    كنتيجة لدالتها، يجب على دالة seek أن تُرجع 0 عند النجاح، و -1 عند الخطأ.

    إذا كان *seek مؤشرًا فارغًا، فمن غير الممكن تنفيذ عمليات بحث على الدفق.

cookie_close_function_t *close
    تغلق هذه الدالة الدفق. يمكن لدالة الخطاف أن تفعل أشياء مثل تحرير المخازن المُخصصة للدفق. عند استدعائها، تستقبل وسيطًا واحدًا:

        int close(void *cookie);

    الوسيط cookie هو الكعكة التي قدمها المبرمج عند استدعاء fopencookie().

    كنتيجة لدالتها، يجب على دالة close أن تُرجع 0 عند النجاح، و EOF عند الخطأ.

    إذا كان *close NULL، فلن يُنفذ أي إجراء خاص عند إغلاق الدفق.

قيمة الإرجاع
عند النجاح، تُرجع fopencookie() مؤشرًا إلى التدفق الجديد. عند الخطأ، يُرجع NULL.

السمات
للاطلاع على شرح للمصطلحات المستخدمة في هذا القسم، انظر attributes(7).
الواجهة | السمة | القيمة
fopencookie() | سلامة الخيوط | MT-Safe

المعايير
GNU.

أمثلة
البرنامج أدناه يُنفذ تدفقًا مخصصًا وظيفته مشابهة (ولكن ليست مطابقة) لتلك المتاحة عبر fmemopen(3). يُنفذ تدفقًا تُخزّن بياناته في مخزن مؤقت للذاكرة. يكتب البرنامج وسائط سطر الأوامر إلى التدفق، ثم يبحث عبر التدفق قارئًا حرفين من كل خمسة أحرف ويكتبها إلى المخرجات القياسية. جلسة الصدفة التالية تُظهر استخدام البرنامج:

    $ ./a.out 'hello world'
    /he/
    / w/
    /d/
    Reached end of file

لاحظ أن نسخة أكثر عمومية من البرنامج أدناه يُمكن تحسينها للتعامل بشكل أكثر متانة مع حالات خطأ متنوعة (مثل، فتح تدفق باستخدام كعكة لديها بالفعل تدفق مفتوح؛ إغلاق تدفق أُغلق بالفعل).

  مصدر البرنامج
    #define _GNU_SOURCE
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <unistd.h>

    #define INIT_BUF_SIZE 4

    struct memfile_cookie {
        char   *buf;        /* Dynamically sized buffer for data */
        size_t  allocated;  /* Size of buf */
        size_t  endpos;     /* Number of characters in buf */
        off_t   offset;     /* Current file offset in buf */
    };

    static ssize_t
    memfile_write(void *c, const char *buf, size_t size)
    {
        char *new_buff;
        struct memfile_cookie *cookie = c;

        /* Buffer too small? Keep doubling size until big enough.  */

        while (size + cookie->offset > cookie->allocated) {
            new_buff = realloc(cookie->buf, cookie->allocated * 2);
            if (new_buff == NULL)
                return -1;
            cookie->allocated *= 2;
            cookie->buf = new_buff;
        }

        memcpy(cookie->buf + cookie->offset, buf, size);

        cookie->offset += size;
        if (cookie->offset > cookie->endpos)
            cookie->endpos = cookie->offset;

        return size;
    }

    static ssize_t
    memfile_read(void *c, char *buf, size_t size)
    {
        ssize_t xbytes;
        struct memfile_cookie *cookie = c;

        /* Fetch minimum of bytes requested and bytes available.  */

        xbytes = size;
        if (cookie->offset + size > cookie->endpos)
            xbytes = cookie->endpos - cookie->offset;
        if (xbytes < 0)     /* offset may be past endpos */
            xbytes = 0;

        memcpy(buf, cookie->buf + cookie->offset, xbytes);

        cookie->offset += xbytes;
        return xbytes;
    }

    static int
    memfile_seek(void *c, off_t *offset, int whence)
    {
        off_t new_offset;
        struct memfile_cookie *cookie = c;

        if (whence == SEEK_SET)
            new_offset = *offset;
        else if (whence == SEEK_END)
            new_offset = cookie->endpos + *offset;
        else if (whence == SEEK_CUR)
            new_offset = cookie->offset + *offset;
        else
            return -1;

        if (new_offset < 0)
            return -1;

        cookie->offset = new_offset;
        *offset = new_offset;
        return 0;
    }

    static int
    memfile_close(void *c)
    {
        struct memfile_cookie *cookie = c;

        free(cookie->buf);
        cookie->allocated = 0;
        cookie->buf = NULL;

        return 0;
    }

    int
    main(int argc, char *argv[])
    {
        cookie_io_functions_t  memfile_func = {
            .read  = memfile_read,
            .write = memfile_write,
            .seek  = memfile_seek,
            .close = memfile_close
        };
        FILE *stream;
        struct memfile_cookie mycookie;
        size_t nread;
        char buf[1000];

        /* Set up the cookie before calling fopencookie().  */

        mycookie.buf = malloc(INIT_BUF_SIZE);
        if (mycookie.buf == NULL) {
            perror("malloc");
            exit(EXIT_FAILURE);
        }

        mycookie.allocated = INIT_BUF_SIZE;
        mycookie.offset = 0;
        mycookie.endpos = 0;

        stream = fopencookie(&mycookie, "w+", memfile_func);
        if (stream == NULL) {
            perror("fopencookie");
            exit(EXIT_FAILURE);
        }

        /* Write command-line arguments to our file.  */

        for (size_t j = 1; j < argc; j++)
            if (fputs(argv[j], stream) == EOF) {
                perror("fputs");
                exit(EXIT_FAILURE);
            }

        /* Read two bytes out of every five, until EOF.  */

        for (long p = 0; ; p += 5) {
            if (fseek(stream, p, SEEK_SET) == -1) {
                perror("fseek");
                exit(EXIT_FAILURE);
            }
            nread = fread(buf, 1, 2, stream);
            if (nread == 0) {
                if (ferror(stream) != 0) {
                    fprintf(stderr, "fread failed\n");
                    exit(EXIT_FAILURE);
                }
                printf("Reached end of file\n");
                break;
            }

            printf("/%.*s/\n", (int) nread, buf);
        }

        free(mycookie.buf);

        exit(EXIT_SUCCESS);
    }

ملاحظات
يجب تعريف _FILE_OFFSET_BITS على أنه 64 في الكود الذي يستخدم seek غير فارغ أو الذي يأخذ عنوان fopencookie، إذا كان الكود يُقصد به أن يكون محمولاً إلى منصات x86 و ARM التقليدية ذات 32 بت حيث عرض off_t المبدئي هو 32 بت.

انظر أيضًا
fclose(3), fmemopen(3), fopen(3), fseek(3)

ترجمة
تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 (https://www.gnu.org/licenses/gpl-3.0.html) أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.