summaryrefslogtreecommitdiff
path: root/man/ru/mpu_fopencookie.3
blob: 057278ce12a2807be6d8f922260d54f32480c2f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
.TH MPU_FOPENCOOKIE 3 "Сентябрь 2026" "libmpuio" "Руководство программиста LIBMPUIO"
.SH ИМЯ
mpu_fopencookie \- открыть произвольный callback-объект как поток LIBMPUIO
.SH ОБЗОР
.nf
#include <libmpuio.h>

typedef ssize_t mpu_cookie_read_function_t( void *cookie, char *buf,
                                            size_t size );
typedef ssize_t mpu_cookie_write_function_t( void *cookie, const char *buf,
                                             size_t size );
typedef int     mpu_cookie_seek_function_t( void *cookie, off_t *position,
                                            int whence );
typedef int     mpu_cookie_close_function_t( void *cookie );

typedef struct mpu_cookie_io_functions_t
{
  mpu_cookie_read_function_t  *read;
  mpu_cookie_write_function_t *write;
  mpu_cookie_seek_function_t  *seek;
  mpu_cookie_close_function_t *close;
} mpu_cookie_io_functions_t;

mpu_FILE *mpu_fopencookie( void *cookie, const char *mode,
                           mpu_cookie_io_functions_t io_functions );
.fi
.SH ОПИСАНИЕ
.B mpu_fopencookie
создаёт поток LIBMPUIO, внешний байтовый транспорт которого предоставляется
callback-функциями вызывающей стороны.  Непрозрачный указатель
.I cookie
сохраняется потоком и передаётся без изменений каждой callback-функции.
.PP
Cookie-backend является третьим независимым backend LIBMPUIO.  Он не заменяет
ни файловый backend на основе дескрипторов, ни нативный строковый backend UCS-2,
используемый
.BR mpu_fmemopen (3)
и
.BR mpu_open_memstream (3).
Все три backend используют общие механизмы
.B mpu_FILE
для форматирования, буферизации, блокировки и состояния через внутреннюю
абстракцию FILE_plus/jump-table.
.PP
Синтаксис
.I mode
совпадает со строгой грамматикой r/w/a с необязательными + и b, принимаемой
.BR mpu_fopen (3).
Режим чтения требует ненулевую callback-функцию
.IR read ,
а режим записи \- ненулевую callback-функцию
.IR write .
Режим append дополнительно требует
.IR seek ,
чтобы LIBMPUIO могла размещать каждую новую последовательность вывода в
логическом конце.
.SH CALLBACK-ФУНКЦИИ
Callback-функция
.I read
копирует не более
.I size
внешних байтов в
.I buf
и возвращает число полученных байтов.  Ноль означает конец ввода.  Отрицательное
значение означает ошибку и должно оставлять полезное значение в
.BR errno .
Возврат большего числа байтов, чем было запрошено, трактуется как ошибка I/O.
.PP
Callback-функция
.I write
потребляет не более
.I size
байтов из
.I buf
и возвращает число принятых байтов.  Отрицательное значение означает ошибку.
Возврат нуля для ненулевого запроса либо значения больше запрошенного трактуется
как
.BR EIO .
LIBMPUIO может вызывать callback многократно для завершения буферизованного
вывода.
.PP
Callback-функция
.I seek
получает запрошенную позицию в
.I *position
и одно из значений
.BR MPU_SEEK_SET ,
.BR MPU_SEEK_CUR
или
.BR MPU_SEEK_END .
При успехе она записывает новую внешнюю байтовую позицию обратно в
.I *position
и возвращает ноль.  Ненулевой результат означает ошибку.  Если callback seek
не предоставлена, операции позиционирования завершаются с
.BR ESPIPE .
.PP
Необязательная callback-функция
.I close
вызывается один раз из
.BR mpu_fclose (3).
Ноль означает успех; ненулевой результат делает close неуспешным.
Сам пользовательский cookie остаётся определяемым вызывающей стороной:
LIBMPUIO освобождает только свой приватный дескриптор callback, но не объект,
на который указывает
.IR cookie .
.SH МОДЕЛЬ ТЕКСТА И СЫРЫХ БАЙТОВ
Callback-функции cookie ориентированы на байты.  Они работают на той же границе
внешнего представления, что и файловый backend.  Поэтому текстовые функции,
например
.BR mpu_fgetc (3),
.BR mpu_fputs (3)
и форматированный I/O, декодируют или кодируют UTF-8 между callback-функциями и
строгим UCS-2
.BR __mpu_char16_t .
Некорректный UTF-8, суррогатные значения и скалярные значения выше U+FFFF
сохраняют обычную для LIBMPUIO семантику
.BR EILSEQ .
.PP
.BR mpu_fread (3)
и
.BR mpu_fwrite (3)
работают непосредственно с байтовым потоком callback и не выполняют
преобразование текста.
.SH БУФЕРИЗАЦИЯ
Cookie-потоки используют обычный механизм буферизации LIBMPUIO и поддерживают
.BR mpu_setvbuf (3),
.BR mpu_setbuf (3)
и
.BR mpu_setlinebuf (3).
Поэтому размеры передач callback не обязаны совпадать с отдельными публичными
вызовами чтения/записи.
.PP
Если читаемый update-поток имеет непрочитанный буферизованный ввод, переход к
выводу требует callback seek, чтобы перед записью восстановить нижележащий
объект в логическую позицию.
.SH ПОЗИЦИОНИРОВАНИЕ
Если
.I seek
предоставлена,
.BR mpu_fseek (3),
.BR mpu_fseeko (3),
.BR mpu_ftell (3),
.BR mpu_ftello (3),
.BR mpu_fgetpos (3)
и
.BR mpu_fsetpos (3)
работают во внешних байтовых позициях.  Упреждающее чтение в буфер, ожидающий
вывод и pushback UCS-2 учитываются теми же правилами логической позиции, что и
для реальных UTF-8-файлов.
.PP
Cookie-потоки не имеют POSIX-дескриптора; поэтому
.BR mpu_fileno (3)
завершается с
.BR EBADF .
.SH ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
.B mpu_fopencookie
возвращает новый поток при успехе и NULL при ошибке.
.SH ОШИБКИ
.B EINVAL
возвращается для недопустимого режима или набора callback, который не может
обеспечить запрошенный режим доступа.  Режим append без callback seek также
отвергается.
.B ESPIPE
возвращается при запросе позиционирования для непозиционируемого cookie.
.B EIO
используется для невозможных значений числа переданных байтов callback.
В остальных случаях ошибки callback сохраняют её значение
.B errno
и, где требуется, устанавливают индикатор ошибки потока.
.PP
Callback, сообщающая об ошибке, отвечает за установку
.B errno
в причину этой ошибки.  В частности, значение errno неудачной callback close
сохраняется mpu_fclose(), если это первая ошибка на пути закрытия.
.SH ПОТОКОБЕЗОПАСНОСТЬ
Обычные операции над cookie-потоком захватывают стандартный рекурсивный mutex
потока.  Это сериализует доступ LIBMPUIO к набору callback одного потока, но не
делает пользовательский cookie-объект безопасным относительно несвязанного
прямого доступа или доступа через другой поток.
.SH ПРИМЕЧАНИЯ
В отличие от реализации, строящей memory streams поверх публичного cookie API,
LIBMPUIO намеренно сохраняет три независимых backend:
.IP 1. 3
файловый backend \- нативный внешний файловый I/O UTF-8;
.IP 2. 3
строковый backend \- нативный I/O памяти UCS-2;
.IP 3. 3
cookie-backend \- произвольный пользовательский байтовый I/O.
.PP
В частности,
.B mpu_fmemopen
не реализован через
.BR mpu_fopencookie .
Оба являются клиентами более низкоуровневой внутренней абстракции
FILE_plus/jump-table.
.SH РЕЕНТЕРАБЕЛЬНОСТЬ CALLBACK
LIBMPUIO не удерживает блокировку глобального списка потоков во время вызова
cookie-callback read, write, seek или close.  Поэтому callback может создавать
или закрывать другие потоки LIBMPUIO без взаимной блокировки глобального обхода
всех потоков.  Потоки, уже захваченные таким обходом, удерживаются внутренней
ссылкой жизненного цикла до тех пор, пока обход их не пройдёт.
.PP
Callback не должна рекурсивно закрывать или иным образом повторно входить в тот
же cookie-поток, backend-операция которого сейчас выполняется.
.SH ПРИМЕР
Следующая небольшая программа создаёт cookie-поток только для записи, который
перенаправляет внешние байты в стандартный вывод и одновременно подсчитывает
их.  Пример показывает границу текстового представления LIBMPUIO: formatter
считает символы UCS-2, а callback cookie видит закодированные байты UTF-8.
.PP
.nf
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>

#include <libmpuio.h>

struct counting_sink
{
  size_t bytes;
};

static ssize_t
counting_write( void *cookie, const char *buf, size_t size )
{
  struct counting_sink *sink = cookie;
  size_t done = 0;

  while( done < size )
  {
    ssize_t n = write(STDOUT_FILENO, buf + done, size - done);

    if( n < 0 )
    {
      if (errno == EINTR)
        continue;
      return -1;
    }
    if( n == 0 )
    {
      errno = EIO;
        return -1;
    }
    done += (size_t)n;
  }

  sink->bytes += done;
  return (ssize_t)done;
}

int
main(void)
{
  struct counting_sink sink = { 0 };
  mpu_cookie_io_functions_t io = {
    .read  = NULL,
    .write = counting_write,
    .seek  = NULL,
    .close = NULL
  };
  mpu_FILE *fp;
  int       nchars;

  __mpu_init();

  fp = mpu_fopencookie( &sink, "w", io );
  if( fp == NULL )
    return 1;

  nchars = mpu_fprintf( fp,
                      MPU_UCS2("value = %d, pi = %c\\n"),
                      42, (int)0x03c0 );
  if( nchars < 0 || mpu_fclose(fp) != 0 )
    return 1;

  mpu_printf( MPU_UCS2("UCS-2 chars: %d, UTF-8 bytes: %ju\\n"),
              nchars, (uintmax_t)sink.bytes );

  __mpu_free_context();
  return 0;
}
.fi
.PP
Для приведённой форматированной строки число символов равно 19, тогда как
callback наблюдает 20 внешних байтов, поскольку U+03C0 кодируется двухбайтовой
последовательностью UTF-8.  В примере намеренно используется непозиционируемый
cookie только для записи; для режима
.B "w"
callback seek не требуется.
.SH СМ. ТАКЖЕ
.BR libmpuio (3),
.BR mpu_fopen (3),
.BR mpu_fmemopen (3),
.BR mpu_fread (3),
.BR mpu_fseek (3),
.BR mpu_printf (3),
.BR mpu_scanf (3)