SDK Multiplataforma en C logo

SDK Multiplataforma en C

Streams

❮ Anterior
Siguiente ❯

El agua puede fluir, arrastrarse, gotear o estrellarse, sé agua amigo mío. Bruce Lee


Funciones

Stream*stm_from_block (...)
Stream*stm_memory (...)
Stream*stm_from_file (...)
Stream*stm_to_file (...)
Stream*stm_append_file (...)
Stream*stm_socket (...)
voidstm_close (...)
endian_tstm_get_write_endian (...)
endian_tstm_get_read_endian (...)
voidstm_set_write_endian (...)
voidstm_set_read_endian (...)
unicode_tstm_get_write_utf (...)
unicode_tstm_get_read_utf (...)
voidstm_set_write_utf (...)
voidstm_set_read_utf (...)
bool_tstm_is_memory (...)
uint64_tstm_bytes_written (...)
uint64_tstm_bytes_readed (...)
uint32_tstm_col (...)
uint32_tstm_row (...)
uint32_tstm_token_col (...)
uint32_tstm_token_row (...)
const char_t*stm_token_lexeme (...)
voidstm_token_escapes (...)
voidstm_token_spaces (...)
voidstm_token_comments (...)
sstate_tstm_state (...)
ferror_tstm_file_err (...)
serror_tstm_sock_err (...)
voidstm_corrupt (...)
String*stm_str (...)
const byte_t*stm_buffer (...)
uint32_tstm_buffer_size (...)
voidstm_write (...)
voidstm_write_char (...)
uint32_tstm_printf (...)
uint32_tstm_writef (...)
voidstm_write_bool (...)
voidstm_write_i8 (...)
voidstm_write_i16 (...)
voidstm_write_i32 (...)
voidstm_write_i64 (...)
voidstm_write_u8 (...)
voidstm_write_u16 (...)
voidstm_write_u32 (...)
voidstm_write_u64 (...)
voidstm_write_r32 (...)
voidstm_write_r64 (...)
voidstm_write_enum (...)
uint32_tstm_read (...)
uint32_tstm_read_char (...)
const char_t*stm_read_chars (...)
const char_t*stm_read_line (...)
const char_t*stm_read_trim (...)
token_tstm_read_token (...)
int8_tstm_read_i8_tok (...)
int16_tstm_read_i16_tok (...)
int32_tstm_read_i32_tok (...)
int64_tstm_read_i64_tok (...)
uint8_tstm_read_u8_tok (...)
uint16_tstm_read_u16_tok (...)
uint32_tstm_read_u32_tok (...)
uint64_tstm_read_u64_tok (...)
real32_tstm_read_r32_tok (...)
real64_tstm_read_r64_tok (...)
bool_tstm_read_bool (...)
int8_tstm_read_i8 (...)
int16_tstm_read_i16 (...)
int32_tstm_read_i32 (...)
int64_tstm_read_i64 (...)
uint8_tstm_read_u8 (...)
uint16_tstm_read_u16 (...)
uint32_tstm_read_u32 (...)
uint64_tstm_read_u64 (...)
real32_tstm_read_r32 (...)
real64_tstm_read_r64 (...)
typestm_read_enum (...)
voidstm_skip (...)
voidstm_skip_bom (...)
voidstm_skip_token (...)
voidstm_flush (...)
voidstm_pipe (...)
voidstm_lines (...)
voidstm_next (...)

Tipos y Constantes

Stream*kSTDIN
Stream*kSTDOUT
Stream*kSTDERR
Stream*kDEVNULL

Un stream es un flujo de datos que corre desde un origen a un destino. Piensa en una llamada telefónica. Tenemos un origen (la persona que habla), un destino (la persona que escucha) y un canal (la propia línea). En programación, el stream es el equivalente a la línea telefónica, es la tubería que une la aplicación con un origen o destino de datos (Figura 1) y por la que circula información binaria, secuencias de bits. Al igual que ocurre con cualquier otro canal de comunicación, la información es volátil, disponible por un tiempo muy limitado. Una vez que llega al receptor, desaparece.

Dibujo de un proceso conectando su E/S mediante streams.
Figura 1: Los streams conectan al proceso con la máquina y con el mundo.

En esencia, son tres las operaciones elementales a realizar cuando trabajamos con streams: Crear el canal, leer datos y escribir datos.

  • Utiliza stm_memory para crear un stream de lectura/escritura en memoria.
  • Utiliza stm_read_r32 para leer un float desde el stream.
  • Utiliza stm_write_r32 para escribir un float en el stream.
  • Utiliza stm_close para cerrar el canal y liberar los recursos (destructor).

1. Tipos de stream

En realidad, es más correcto hablar de tipos de interlocutores (origen y destino) que de tipos de stream. Desde la perspectiva del programador, un stream es un tipo abstracto que presenta la misma funcionalidad independientemente de los extremos que conecta. Por tanto, al hablar de tipo de stream nos estamos refiriendo al tipo de constructor.

1.1. File stream

En File streams (Figura 2), el origen es la memoria del proceso y el destino un archivo en disco. Lo contrario también puede ocurrir: que el origen sea el archivo y el destino la memoria, dependerá de como creemos el canal. No será posible realizar operaciones de escritura en un archivo abierto para lectura o viceversa (Listado 1). Internamente, el stream se encargará del acceso al sistema de ficheros, como vimos en Archivos y directorios.

Dibujo de un proceso accediendo a disco mediante streams.
Figura 2: Los File streams permiten la comunicación con el sistema de archivos.
Listado 1: Ejemplo de escritura en un archivo.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Stream *stm = stm_to_file("C:\Users\user\john\out.txt", NULL);
if (stm != NULL)
{
    stm_writef(stm, "One ");
    stm_writef(stm, "Two ");
    stm_writef(stm, "Three");
    stm_writef(stm, ".");
    stm_close(&stm);
    // 'out.txt' is closed = "One Two Three."
}

1.2. Socket stream

  • Utiliza stm_socket para crear un canal de comunicación con un proceso remoto.

Un socket es un canal de comunicación entre dos procesos a través de Internet (Figura 3). A diferencia de los file streams, los sockets permiten la comunicación bidireccional (full-duplex), es decir, ambos extremos pueden enviar y recibir información. La secuencia de intercambio de mensajes entre interlocutores está determinada por el protocolo (Listado 2), siendo HTTP, FTP, SMTP o LDAP algunos de los más utilizados para las transmisiones por Internet. Ver Sockets.

Dibujo de un proceso accediendo accediendo a Internet mediante streams.
Figura 3: Un socket stream abre un canal de comunicación por Internet.
Listado 2: Descarga de una página web, mediante el protocolo HTTP.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
uint32_t ip = bsocket_url_ip("www.myserver.com", NULL);
Socket *socket = bsocket_connect(ip, 80, 0, NULL);
if (socket != NULL)
{
    Stream *stm = stm_socket(socket);
    stm_writef(stm, "GET /mypage.html HTTP/1.1\r\n");
    stm_writef(stm, "Host: www.myserver.com\r\n");
    stm_writef(stm, "\r\n");
    stm_lines(line, stm)
        bstd_printf(line);
        bstd_printf("\n");
    stm_next(line, stm)

    // Socket will be closed too
    stm_close(&stm);
}

1.3. Block stream

Los block streams se utilizan para leer datos con formato a partir de un bloque de memoria genérico (Figura 4) (Listado 3). Esta zona de memoria se considera de solo lectura y no será modificada, por lo que no se permitirán operaciones de escritura en este tipo de streams. Cuando se llegue al final del bloque, se activará el estado ekSTEND.

Listado 3: Leer datos desde un bloque de memoria.
1
2
3
4
5
6
7
8
9
const byte_t *data = ...
uint32_t size = ...
ArrPt(String) *lines = arrpt_create(String);
Stream *stm = stm_from_block(data, size);
while(stm_state(stm) == ekSTOK)
{
    String *line = str_c(stm_read_line(stm));
    arrpt_append(lines, line);
}
Dibujo de un proceso leyendo desde un bloque de memoria mediante streams.
Figura 4: Con block streams leeremos datos con formato desde áreas de memoria.

1.4. Memory stream

Los memory streams son canales de lectura/escritura que permiten implementar el modelo productor/consumidor (Figura 5). En primer lugar, la información llega al stream mediante operaciones de escritura y se almacena en un búfer interno de memoria. Posteriormente, dicha información puede ser leída por otra función, hebra o proceso. Tras cada lectura la información leída desaparecerá del canal. El concepto es similar al de las tuberías (IPC-Pipes), con la salvedad de que no existe un límite de tamaño para el búfer, sino que crecerá bajo demanda. Las operaciones de lectura y escritura se pueden ir simultaneando en función del protocolo establecido.

Listado 4: Uso de streams en memoria (productor/consumidor).
 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
// Main thread
Stream *stm = stm_memory(2048);
while(true)
{
    UserEvent event;
    if (event_incomming(&event))
    {
        bmutex_lock(mutex);
        stm_write_u32(stm, event.code);
        stm_write_u32(stm, event.userid);
        str_write(stm, str_event.name);
        bmutex_unlock(mutex);

        if (event.last == TRUE)
            break;
    }
}

bmutex_lock(mutex);
stm_close(&stm);
bmutex_unlock(mutex);

...
// Other thread
bool_t next = TRUE;
while(next)
{

    bmutex_lock(mutex);
    if (stm != NULL)
    {
        if (stm_buffer_size(stm) > 0)
        {
            UserEvent event;
            event.code = stm_write_u32(stm);
            event.userid = stm_write_u32(stm);
            str_event.name = str_read(stm);
            ...
        }
    }
    else
    {
        next = FALSE;
    }
    bmutex_unlock(mutex);
    bthread_sleep(50);
}
Dibujo de un proceso compartiendo datos entre hebras mediante streams.
Figura 5: Modelo productor/consumidor implementado con memory streams.
A pesar que este tipo de stream soporta operaciones de lectura y escritura no se considera full-duplex. La lectura se hace sobre datos escritos previamente, pero no puede "contestar" al interlocutor. No es una "conversación".

1.5. Standard stream

  • Utiliza kSTDIN para leer de la entrada estándar.
  • Utiliza kSTDOUT para escribir en la salida estándar.
  • Utiliza kSTDERR para escribir en la salida de errores.

La E/S Estándar puede ser gestionada mediante streams utilizando tres objetos predefinidos (Figura 6) (Listado 5). Estos objetos se crean al iniciar el programa y se liberarán automáticamente al terminar.

Dibujo de un proceso accediendo a la E/S estándar mediante streams.
Figura 6: Acceso a la E/S estándar a través de streams.
Listado 5: Ejemplo básico de E/S estándar.
1
2
3
4
5
real64_t value;
const char_t *line;
value = stm_read_r64(kSTDIN);
line = stm_read_line(kSTDIN);
stm_printf(kSTDOUT, "Value = %.4f", value);

1.6. Null stream

  • Utiliza kDEVNULL para escribir en un sumidero que ignorará todos los datos recibidos.

En ocasiones puede ser útil disponer de un "sumidero" que ignore todas las operaciones de escritura (Figura 7) (Listado 6). Piensa en tareas de depuración donde queramos activar o desactivar la salida de información pero que borrar o comentar el código sea engorroso. La idea es similar al /dev/null de Unix.

Dibujo de un proceso escribiendo en un canal nulo.
Figura 7: Con null streams se ignorará todo lo que se escriba.
Listado 6: Escritura en un stream nulo.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#if defined __ASSERTS__
Stream *stm = kSTDOUT;
#else
Stream *stm = kDEVNULL;
#endif

...
i_large_dump_func(obj1, stm);
...
// More debug functions
stm_printf(stm, "More debug data...\n");
...
i_other_dump_func(obj2, stm);
No es posible leer desde kDEVNULL.

1.7. Stream binario

Por un stream siempre viajan datos binarios genéricos como flujo de bytes. Como estos datos sean interpretados depende de los interlocutores y de su protocolo de comunicación. Pero al hacer énfasis en "datos binarios" nos referimos a que los valores numéricos se escriben en el canal tal y como aparecen en los registros de la CPU utilizando el código binario, complemento a dos o IEEE754 (Figura 8). En tipos multi-byte debemos tener en cuenta el Orden de bytes. En stream.h se definen varias funciones para leer y escribir tipos binarios.

Canal de comunicación con datos binarios.
Figura 8: Números en formato binario.

1.8. Stream de texto

  • Utiliza stm_printf para escribir texto en un stream.
  • Utiliza stm_read_char para leer un carácter desde un stream.
  • Utiliza stm_read_line para leer una línea de texto desde un stream.
  • Utiliza stm_col para obtener el número de columna del último carácter leído.
  • Utiliza stm_row para obtener el número de fila del último carácter leído.

Los streams de texto son un caso particular donde se asume que la información binaria representa códigos de caracteres Unicode (codepoints) (Figura 9) (Listado 7). Esto significa que el contenido del stream será legible directamente por un humano, pero requerirá un post-proceso (parsing) en destino para interpretar dichos textos y traducirlos a binario. No hay que hacer nada especial al crear un stream para indicar que es de tipo texto, tan solo hay que utilizar las funciones adecuadas.

Dibujo de un proceso grabando texto en disco mediante streams.
Figura 9: En streams de texto la información se puede leer directamente.
Listado 7: Lectura de un archivo de texto mediante streams.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Stream *stm = stm_from_file("/home/fran/Desktop/text.txt", NULL);
const char_t *line = stm_read_line(stm);
while(line != NULL)
{
    // Do something with 'line'
    textview_writef(text, line);
    textview_writef(text, "\n");

    // Read next line
    line = stm_read_line(stm);
}

stm_close(&stm);

stm_read_line y demás funciones de lectura nos devolverán el texto siempre en UTF8. Pero si los datos dentro del stream estuvieran en otro formato, deberemos utilizar stm_set_read_utf, con el fin de realizar la conversión correctamente. Ver Codificaciones UTF.

Por otro lado, stm_printf también recibe el texto en UTF8, pero es posible que el receptor lo necesite en otro formato. Utilizaremos stm_set_write_utf para establecer la codificación de salida. Nosotros escribiremos en UTF8, pero al canal se enviará en UTF16 o UTF32.

Los streams no tienen porqué ser de texto o binarios "puros". Pueden combinar ambos tipos de representaciones.

2. Tokens

Al leer desde streams de texto, se hace necesaria una interpretación (parsing) del contenido con el fin de trasladar los datos a variables de memoria (en binario). El primer paso es fragmentar el texto en símbolos (o palabras) denominados tokens. Internamente, los streams incorporan un sencillo analizador léxico que reconoce los tokens propios del lenguaje C, muy comunes en infinidad de gramáticas y formatos de archivo (Figura 10). Está implementado como una máquina de estados finitos y nos facilitará enormemente el procesamiento de estos flujos de texto. En (Listado 8) vemos el código necesario para leer uno a uno todos los tokens de un archivo .c. El resultado de procesar el archivo (Listado 9) lo tenemos en (Listado 10).

Representación de los diferentes tokens que forman una sentencia.
Figura 10: Descomposición de un texto en tokens.
Listado 8: Lectura de los tokens de un archivo en C.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Stream *stm = stm_from_file("source.c", NULL);
token_t token;

while ((token = stm_read_token(lex)) != ekTEOF)
{
    switch (token) {
    case ekTIDENT:
        // It's an IDENTIFIER
        ...

    case ekTREAL:
        // It's a REAL NUMBER
        ...
    }
}
Listado 9: Archivo source.c.
1
2
3
4
5
6
7
void func(int a)
{
    int i;
    char *str = "Hello";

    i = 5 + 2.5;
}
Listado 10: Análisis léxico de source.c.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Token           Lexeme
-----           ------
ekTIDENT        "void"
ekTIDENT        "func"
ekTOPENPAR      "("
ekTIDENT        "int"
ekTIDENT        "a"
ekTCLOSPAR      ")"
ekTOPENCURL     "{"
ekTIDENT        "int"
ekTIDENT        "i"
ekTSCOLON       ";"
ekTIDENT        "char"
ekTASTERK       "*"
ekTIDENT        "str"
ekTEQUALS       "="
ekTSTRING       ""Hello""
ekTSCOLON       ";"
ekTIDENT        "i"
ekTEQUALS       "="
ekTINTEGER      "5"
ekTPLUS         "+"
ekTREAL         "2.5"
ekTSCOLON       ";"

2.1. Identificadores

Un identificador es una "palabra" alfanumérica que debe comenzar por una letra o '_' y contiene números, letras o '_'. Se utiliza para nombrar variables, funciones, palabras reservadas, etc. No permiten espacios ni símbolos. (Listado 11) (Figura 11).

Listado 11: Identificadores correctos e incorrectos.
1
2
OK: while cos _reSult a56B _06_t aG h9 _12AcVb
NO: 045 ?er "_5G _tg(
Autómata finito que reconoce un identificador en C.
Figura 11: Autómata finito que reconoce un identificador.

Se pueden reservar ciertos identificadores para que actúen como palabras clave del lenguaje. Por ejemplo for, while o if son palabras clave de C y no podrán ser utilizadas para el nombrado de variables o funciones. Al ser de propósito general, nuestro escáner no reconoce ningún tipo de palabra reservada, sino hay que etiquetarla expresamente tras leer el token (Listado 12).

Listado 12: Reconociendo la palabra clave while.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
while ((token = stm_read_token(stm)) != ekTEOF)
{
    if (token == ekTIDENT)
    {
        const char_t *lex = stm_token_lexeme(stm, NULL);

        if (str_equ_c(lex, "while") == TRUE)
            token = ekTRESERVED;
    }
}

2.2. Cadenas

Una cadena de texto es una serie de caracteres Unicode puestos entre comillas ("") (Figura 12). El analizador reconoce las secuencias de escape de C para representar códigos no imprimibles o caracteres no disponibles en el teclado (Listado 13).

  • Utiliza stm_token_escapes para hacer efectivas las secuencias de escape al leer cadenas.
  • Listado 13: Secuencias de escape aceptadas en ekTSTRING.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    \a      07  Alert (Beep, Bell) (added in C89)
    \b      08  Backspace
    \f      0C  Formfeed Page Break
    \n      0A  Newline (Line Feed)
    \r      0D  Carriage Return
    \t      09  Horizontal Tab
    \v      0B  Vertical Tab
    \\      5C  Backslash
    \'      27  Single quotation mark
    \"      22  Double quotation mark
    \?      3F  Question mark (used to avoid trigraphs)
    \nnn        Octal number
    \xhh        Hexadecimal number
    \Uhhhhhhhh  Unicode code point
    \uhhhh      Unicode code point
    
    Autómata finito que reconoce una cadena de texto.
    Figura 12: Autómata finito que reconoce una cadena de texto.

2.3. Números

En el caso de tokens numéricos la cosa se complica un poco debido a las diferentes bases numéricas y a la representación exponencial de números reales (Figura 13). La resumimos brevemente, aunque es común a muchos lenguajes de programación (C incluido).

  • Si el número empieza por 0 será considerado octal (base 8), por lo tanto, las cifras siguientes están limitadas a 0-7, pe: 043, 001, 0777.
  • Si el número empieza por 0x se considerará hexadecimal (base 16) con cifras 0-9 a-f A-F, pe: 0x4F, 0XAA5, 0x01EAC.
  • En el momento que aparezca un punto decimal '.' se considerará número real. El punto inicial es válido, pe: .56.
  • Un número entero o real permite notación exponencial con el carácter 'e' ('E'), pe: 12.4e2, .56e3, 1e4.
  • Autómata finito que reconoce números en diferentes bases.
    Figura 13: Autómata finito que reconoce números.

2.4. Símbolos

Los símbolos son tokens de un solo carácter que representan casi la totalidad de signos de puntuación US-ASCII y que suelen utilizarse como operadores, separadores o limitadores dentro de las gramáticas (Listado 14) (Figura 14).

Listado 14: Símbolos reconocidos como tokens individuales.
1
< > , . ; : ( ) [ ] { } + - * = $ % # & ' " ^ ! ? | / \ @
Autómata finito que reconoce los símbolos más, menos, asterisco e igual.
Figura 14: Autómata finito que reconoce algunos símbolos.

2.5. Comentarios

Por defecto los comentarios de C /* Comment */ o de C++ // Comment son ignorados por stm_read_token.


3. Ventajas de los streams

A pesar que es posible leer o escribir directamente en los canales E/S (Memoria, Archivos y directorios, Sockets, E/S Estándar), hacerlo a través de objetos Stream tiene ciertas ventajas. Por esto recomendamos utilizarlos en lugar de las API de bajo nivel por los siguientes motivos:

3.1. Unificar la serialización

Los streams ofrecen una interfaz uniforme, independientemente del origen y destino de los datos (Figura 15). Para la serialización de objetos tan solo debemos escribir un lector y un escritor, sin preocuparnos si objeto será guardado en disco, transmitido por Internet o almacenado temporalmente en memoria (Listado 15).

Listado 15: (De)serialización de un objeto mediante streams.
 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
typedef struct _product_t
{
    type_t type;
    String *code;
    String *description;
    Image *image64;
    real32_t price;
} Product;

void product_write(Stream *stm, Product *product)
{
    stm_write_enum(stm, product->type, type_t);
    str_write(stm, product->code);
    str_write(stm, product->description);
    image_write(stm, product->image64);
    stm_write_r32(stm, product->price);
}

void product_read(Stream *stm, Product *product)
{
    product->type = stm_read_enum(stm, type_t);
    product->code = str_read(stm);
    product->description = str_read(stm);
    product->image64 = image_read(stm);
    product->price = stm_read_r32(stm);
}
Unificación de canales E/S gracias a los streams.
Figura 15: Por medio de streams manejamos todos los canales E/S con la misma interfaz.

3.2. Mayor elegancia

Los canales E/S solo trabajan con bloques de bytes. Los streams implementan funciones de alto nivel para textos y tipos binarios. Esto hará nuestro código mucho más legible (Listado 16).

Listado 16: Escritura de un objeto en disco directamente o a través de un stream.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
void product_write(File *file, Product *product)
{
    uint32_t size = str_len(product->description);
    const char_t *data = tc(product->description);
    bfile_write(file, (byte_t*)&product->id, sizeof(uint32_t), NULL, NULL);
    bfile_write(file, (byte_t*)&product->price, sizeof(real64_t), NULL, NULL);
    bfile_write(file, (byte_t*)&size, sizeof(uint32_t), NULL, NULL);
    bfile_write(file, (byte_t*)data, size, NULL, NULL);
}

void product_write(Stream *stream, Product *product)
{
    stm_write_u32(stream, product->id);
    stm_write_r64(stream, product->price);
    str_write(stream, product->description);
}

3.3. Mayor productividad

Relacionada con la anterior, los streams pueden "parsear" cadenas de texto directamente. Se pueden obtener caracteres, líneas o tokens sin tener que escanear la entrada carácter a carácter (Listado 17).

Listado 17: Leer una línea de texto directamente o a través de un stream.
 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
String *getline(File *file)
{
    /* Potentially unsafe. */
    /* Risk of buffer overflow. */
    char_t buffer[MAXBUFF];
    uint32_t i = 0;
    char_t c;

    bfile_read(file, (byte_t*)&c, 1, NULL, NULL);
    while (c != '\n')
    {
        buffer[i] = c;
        i += 1;
        bfile_read(file, (byte_t*)&c, 1, NULL, NULL);
    }

    buffer[i] = '\0';
    return str_c(buffer);
}

String *getline(Stream *stream)
{
    /* Totally safe. */
    /* 'line' is managed by dynamic cache. */
    const char_t *line = stm_read_line(stream);
    return str_c(line);
}

3.4. Mayor rendimiento

File streams y standard streams implementan una caché interna. Esto permite acceder menos veces al canal con un mayor volumen de datos, lo que implica mayor velocidad de proceso (Figura 16).

  • Utiliza stm_flush para vaciar la caché y volcar los datos en el canal.
  • Dibujo de los streams utilizando caché de datos.
    Figura 16: Los streams implementan memoria caché, lo que incrementa el rendimiento.

3.5. Orden de bytes

  • Utiliza stm_set_write_endian para establecer el endianness del canal de salida. Los datos pasarán de CPU endian a Stream endian antes de ser escritos.
  • Utiliza stm_set_read_endian para establecer el endianness del canal de entrada. Los datos pasarán de Stream endian a CPU endian en el momento de ser leídos.

Al leer o escribir datos binarios de un canal E/S hay que prestar especial atención al orden de los bytes en tipos de datos de 16, 32 o 64 bits lo que se conoce como endianness. En máquinas litte endian, como es el caso de la familia de procesadores Intel x86/x64, el byte de menor orden se ubicará en la dirección de memoria más baja. En el caso de los big endian (Motorola 68000, PowerPC) ocurre al contrario, irá en en la más alta. Por ejemplo, si escribimos un entero de 32-bits en un archivo o socket desde una máquina little endian y lo leemos desde una big endian los datos estarán corrompidos al alterar el orden interno de bits (Figura 17). Los objetos Stream ajustan automáticamente el endianness en cada operación de lectura/escritura. Por defecto se establece ekLITEND, salvo en sockets que será ekBIGEND por ser el convenio aceptado para las comunicaciones en red. No obstante, puede cambiarse si es necesario.

Dibujo de streams teniendo en cuenta el orden de bytes.
Figura 17: Debemos tener en cuenta el endianness a la hora de compartir datos entre máquinas de diferente arquitectura.
El endianness no influye en las cadenas de texto UTF-8, pero sí en las UTF-16 y UTF-32.

4. Estado del stream

  • Utiliza stm_state para conocer el estado actual del canal.
  • Utiliza stm_file_err para obtener información extendida del error en streams de disco.
  • Utiliza stm_sock_err para obtener información extendida del error en sockets.
  • Utiliza stm_corrupt para marcar un stream como ekSTCORRUPT. En ocasiones es el propia aplicación la que detecta que el dato no es correcto (pe. fuera de rango).
  • Utiliza stm_bytes_written para obtener el número total de bytes escritos en el stream.
  • Utiliza stm_bytes_readed para obtener el número total de bytes leídos del stream.

Un stream puede verse afectado por dos tipos de problemas. Por un lado la corrupción de datos que queda patente cuando leemos datos binarios desde el stream (Listado 18). Un claro ejemplo sería leer un booleano mediante stm_read_bool y obtener un valor de 129 cuando, evidentemente, este valor debería ser 0 (TRUE) ó 1 (FALSE). Normalmente, un stream se corrompe debido a la falta de coordinación entre el escritor y el lector y, por lo general, se debe a un error de programación. Esta situación debe resolverse depurando y corrigiendo la serialización de objetos o revisando el protocolo de datos. Por otro lado, pueden existir errores "físicos" en el canal (archivo eliminado, perdida de conexión a Internet, permisos, etc). En ambos casos el stream quedará invalidado y serán ignoradas las operaciones subsecuentes de lectura o escritura que efectuemos sobre el mismo. También podemos preguntar la cantidad total de bytes leídos y/o escritos en el canal, en el caso que necesitemos saber si existe información disponible para lectura.

Listado 18: Comprobación del estado del stream.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
uint32_t nw = stm_bytes_written(stm);
uint32_t nr = stm_bytes_readed(stm);
if (nw - nr > 0)
{
    if (stm_state(stm) == ekSTOK)
    {
        uint32_t v1 = stm_read_u32(stm);
        real32_t v2 = stm_read_r32(stm);
        ...
    }
    else
    {
        // Error in stream
    }
}
else
{
    // No data in stream
}
❮ Anterior
Siguiente ❯

kSTDIN

Stream* kSTDIN;

Stream conectado a la entrada estándar stdin.


kSTDOUT

Stream* kSTDOUT;

Stream conectado a la salida estándar stdout.


kSTDERR

Stream* kSTDERR;

Stream conectado a la salida de errores stderr.


kDEVNULL

Stream* kDEVNULL;

Stream de escritura nulo. Será ignorado todo el contenido que se mande por este canal.


stm_from_block ()

Crea un stream de lectura a partir de un bloque de memoria ya existente.

Stream*
stm_from_block(const byte_t *data,
               const uint32_t size);
data

Puntero al bloque de memoria.

size

Tamaño en bytes del bloque de memoria.

Retorna

El objeto stream.

Observaciones

El bloque original no será modificado (solo lectura). Cuando se alcance el final del bloque stm_state devolverá ekSTEND. Block stream.


stm_memory ()

Crea un stream de lectura/escritura en memoria.

Stream*
stm_memory(const uint32_t size);
size

Tamaño inicial del búfer (en bytes). Crecerá si es necesario.

Retorna

El objeto stream.

Observaciones

Puede utilizarse como tubería interna para el intercambio de información entre funciones o hilos. Se comporta como un búfer FIFO (First In Fist Out). Para acceso multi-hilo debe estar protegido con un Mutex. Memory stream.


stm_from_file ()

Crea un stream para leer desde un archivo en disco.

Stream*
stm_from_file(const char_t *pathname,
              ferror_t *error);
pathname

Pathname del archivo. Filename y pathname.

error

Código de error si la función falla. Puede ser NULL.

Retorna

El objeto stream o NULL si falla la apertura del archivo.

Observaciones

File stream.


stm_to_file ()

Crea un stream para escribir datos a un archivo en disco.

Stream*
stm_to_file(const char_t *pathname,
            ferror_t *error);
pathname

Pathname del archivo. Filename y pathname.

error

Código de error si la función falla. Puede ser NULL.

Retorna

El objeto stream o NULL si falla la creación del archivo.

Observaciones

Si el archivo ya existe será sobrescrito. File stream.


stm_append_file ()

Crea un stream para escribir datos al final de un archivo existente.

Stream*
stm_append_file(const char_t *pathname,
                ferror_t *error);
pathname

Pathname del archivo. Filename y pathname.

error

Código de error si la función falla. Puede ser NULL.

Retorna

El objeto stream o NULL si falla la apertura del archivo.

Observaciones

Fallará si el archivo no existe (no lo crea). File stream.


stm_socket ()

Crea un stream a partir de un socket.

Stream*
stm_socket(Socket *socket);
socket

Socket cliente o servidor.

Retorna

El objeto stream.

Observaciones

Permite utilizar la funcionalidad de los streams para leer o escribir en un proceso remoto. El socket debe haber sido previamente creado con bsocket_connect (cliente) o bsocket_accept (servidor). El stream cerrará el socket en stm_close. No se debe llamar a bsocket_close. Ver Socket stream.


stm_close ()

Cierra el stream. Todos los recursos como descriptores de archivos o sockets serán liberados. Previamente al cierre, se escribirán en el canal los datos en caché stm_flush.

void
stm_close(Stream **stm);
stm

El objeto stream. Será puesto a NULL tras la destrucción.


stm_get_write_endian ()

Obtiene el orden de bytes actual al escribir en el stream.

endian_t
stm_get_write_endian(const Stream *stm);
stm

El objeto stream.

Retorna

El Orden de bytes.


stm_get_read_endian ()

Obtiene el orden de bytes actual al leer del stream.

endian_t
stm_get_read_endian(const Stream *stm);
stm

El objeto stream.

Retorna

El Orden de bytes.


stm_set_write_endian ()

Establece el orden de bytes al escribir en el stream, a partir de ahora.

void
stm_set_write_endian(Stream *stm,
                     const endian_t endian);
stm

El objeto stream.

endian

El Orden de bytes.

Observaciones

Por defecto es ekLITEND, salvo en sockets que será ekBIGEND.


stm_set_read_endian ()

Establece el orden de bytes al leer del stream, a partir de ahora.

void
stm_set_read_endian(Stream *stm,
                    const endian_t endian);
stm

El objeto stream.

endian

El Orden de bytes.

Observaciones

Por defecto es ekLITEND, salvo en sockets que será ekBIGEND.


stm_get_write_utf ()

Obtiene la codificación UTF con la que se están escribiendo los textos en el stream.

unicode_t
stm_get_write_utf(const Stream *stm);
stm

El objeto stream.

Retorna

Codificaciones UTF.

Observaciones

Ver Stream de texto.


stm_get_read_utf ()

Obtiene la codificación UTF con la que se están leyendo los textos en el stream.

unicode_t
stm_get_read_utf(const Stream *stm);
stm

El objeto stream.

Retorna

Codificaciones UTF.

Observaciones

Ver Stream de texto.


stm_set_write_utf ()

Establece la codificación UTF al escribir textos en el stream, a partir de ahora.

void
stm_set_write_utf(Stream *stm,
                  const unicode_t format);
stm

El objeto stream.

format

Codificaciones UTF.

Observaciones

Ver Stream de texto.


stm_set_read_utf ()

Establece la codificación UTF al leer textos en el stream, a partir de ahora.

void
stm_set_read_utf(Stream *stm,
                 const unicode_t format);
stm

El objeto stream.

format

Codificaciones UTF.

Observaciones

Ver Stream de texto.


stm_is_memory ()

Obtiene si es un stream residente en memoria.

bool_t
stm_is_memory(const Stream *stm);
stm

El objeto stream.

Retorna

TRUE si ha sido creado mediante stm_from_block o stm_memory.


stm_bytes_written ()

Obtiene el total de bytes escritos en el stream desde su creación.

uint64_t
stm_bytes_written(const Stream *stm);
stm

El objeto stream.

Retorna

El número total de bytes escritos.


stm_bytes_readed ()

Obtiene el total de bytes leídos desde el stream desde su creación.

uint64_t
stm_bytes_readed(const Stream *stm);
stm

El objeto stream.

Retorna

El número total de bytes leídos.


stm_col ()

Obtiene la columna en streams de texto.

uint32_t
stm_col(const Stream *stm);
stm

El objeto stream.

Retorna

Número de columna.

Observaciones

Cuando leemos caracteres en streams de texto con stm_read_char o derivadas, se contabilizan las columnas y filas de forma similar a como lo hacen los editores de texto. Esta información puede ser útil a la hora de mostrar avisos o mensajes de error. En streams mixtos (binarios + texto), la cuenta se detiene al leer datos binarios y continúa cuando se retoma la lectura del texto. Ver Stream de texto.


stm_row ()

Obtiene la fila en streams de texto.

uint32_t
stm_row(const Stream *stm);
stm

El objeto stream.

Retorna

Número de fila.

Observaciones

Ver stm_col.


stm_token_col ()

Obtiene la columna del último token leído.

uint32_t
stm_token_col(const Stream *stm);
stm

El objeto stream.

Retorna

Número de columna.

Observaciones

Solo tiene efecto tras llamar a stm_read_token o derivadas. Ver stm_col y Tokens.


stm_token_row ()

Obtiene la fila del último token leído.

uint32_t
stm_token_row(const Stream *stm);
stm

El objeto stream.

Retorna

Número de fila.

Observaciones

Solo tiene efecto tras llamar a stm_read_token o derivadas. Ver stm_col y Tokens.


stm_token_lexeme ()

Obtiene el lexema del último token leído.

const char_t*
stm_token_lexeme(const Stream *stm);
stm

El objeto stream.

Retorna

El lexema. Está almacenado en un buffer temporal y se perderá al leer el siguiente token. Si lo necesitas, haz una copia con str_c.

Observaciones

Solo tiene efecto tras llamar a stm_read_token o derivadas. Ver Tokens.


stm_token_escapes ()

Opción de secuencias de escape al leer tokens.

void
stm_token_escapes(const Stream *stm,
                  const bool_t active_escapes);
stm

El objeto stream.

active_escapes

TRUE se procesarán las secuencias de escape al leer tokens ekTSTRING. Por ejemplo, la secuencia "\n" se transformará en el carácter 0x0A (10). FALSE ignorará las secuencias de escape, leyendo las cadenas de texto de forma literal. Por defecto FALSE.

Observaciones

Tendrá efecto en la siguiente llamada a stm_read_token. Ver Tokens.


stm_token_spaces ()

Opción de espacios en blanco al leer tokens.

void
stm_token_spaces(const Stream *stm,
                 const bool_t active_spaces);
stm

El objeto stream.

active_spaces

TRUE se devolverán tokens ekTSPACE al encontrar secuencias de espacios en blanco. FALSE ignorarán los espacios en blanco. Por defecto FALSE.

Observaciones

Tendrá efecto en la siguiente llamada a stm_read_token. Ver Tokens.


stm_token_comments ()

Opción de comentarios al leer tokens.

void
stm_token_comments(const Stream *stm,
                   const bool_t active_comments);
stm

El objeto stream.

active_comments

TRUE se devolverá un token ekTMLCOM cada vez que encuentre comentarios de C /* Comment */ y ekTSLCOM para comentarios C++ // Comment. FALSE se ignorarán los comentarios. Por defecto FALSE.

Observaciones

Tendrá efecto en la siguiente llamada a stm_read_token. Ver Tokens.


stm_state ()

Obtiene el estado actual del stream.

sstate_t
stm_state(const Stream *stm);
stm

El objeto stream.

Retorna

El Estado del stream.


stm_file_err ()

Obtiene información adicional sobre el error, en streams de disco.

ferror_t
stm_file_err(const Stream *stm);
stm

El objeto stream.

Retorna

Error de archivo.

Observaciones

Solo es relevante en File stream con el estado ekSTBROKEN.


stm_sock_err ()

Obtiene información adicional sobre el error, en streams de red.

serror_t
stm_sock_err(const Stream *stm);
stm

El objeto stream.

Retorna

Error de socket.

Observaciones

Solo es relevante en Socket stream con el estado ekSTBROKEN.


stm_corrupt ()

Establece el estado del stream a ekSTCORRUPT.

void
stm_corrupt(Stream *stm);
stm

El objeto stream.

Observaciones

En ocasiones, es la aplicación la que detecta que los datos están corruptos ya que la semántica de los mismos no coincide con lo esperado.


stm_str ()

Crea un string con el contenido actual del búfer interno. Solo es válido para stream en memoria. stm_memory.

String*
stm_str(const Stream *stm);
stm

El objeto stream.

Retorna

El string con el contenido del búfer.


stm_buffer ()

Obtiene un puntero al contenido actual del búfer interno. Solo es válido para stream en memoria. stm_memory.

const byte_t*
stm_buffer(const Stream *stm);
stm

El objeto stream.

Retorna

Puntero al búfer interno.

Observaciones

Este puntero es de solo lectura. Escribir aquí tendrá consecuencias indeseadas. Contiene la información escrita en el stream, pero todavía no consumida. Cualquier operación read sobre el stream, reducirá el tamaño del búfer.


stm_buffer_size ()

Obtiene el tamaño actual del búfer interno. Solo es válido para stream en memoria. stm_memory.

uint32_t
stm_buffer_size(const Stream *stm);
stm

El objeto stream.

Retorna

El tamaño del búfer interno (en bytes).


stm_write ()

Escribe bytes en el stream.

void
stm_write(Stream *stm,
          const byte_t *data,
          const uint32_t size);
stm

El objeto stream.

data

Puntero al bloque de datos a escribir.

size

Número de bytes a escribir.

Observaciones

El bloque se escribe tal cual llega, sin tener en cuenta el Orden de bytes ni las Codificaciones UTF.


stm_write_char ()

Escribe un carácter Unicode en el stream.

void
stm_write_char(Stream *stm,
               const uint32_t codepoint);
stm

El objeto stream.

codepoint

El código Unicode del carácter.

Observaciones

La codificación se puede cambiar con stm_set_write_utf.


stm_printf ()

Escribe texto en el stream, utilizando el formato del printf.

uint32_t
stm_printf(Stream *stm,
           const char_t *format,
           ...);
1
stm_printf(stream, Code: %-10s Price %5.2f\n", code, price);
stm

El objeto stream.

format

Cadena con el formato tipo-printf con un número variable de parámetros.

...

Argumentos o variables del printf.

Retorna

El número de bytes escritos.

Observaciones

El carácter nulo final ('\0') no será escrito. La codificación se puede cambiar con stm_set_write_utf.


stm_writef ()

Escribe una cadena C UTF8 en el stream.

uint32_t
stm_writef(Stream *stm,
           const char_t *str);
stm

El objeto stream.

str

Cadena C UTF8 terminada en carácter nulo '\0'.

Retorna

El número de bytes escritos.

Observaciones

El carácter nulo final ('\0') no será escrito. Está función es más rápida que stm_printf cuando la cadena es constante y no necesita formato. Para objetos String utiliza str_writef. La codificación se puede cambiar con stm_set_write_utf.


stm_write_bool ()

Escribe una variable bool_t en el stream.

void
stm_write_bool(Stream *stm,
               const bool_t value);
stm

El objeto stream.

value

Variable a escribir.

Observaciones

Es una escritura binaria. No utilizar en streams de texto "puros".


stm_write_i8 ()

Escribe una variable int8_t en el stream.

void
stm_write_i8(Stream *stm,
             const int8_t value);
stm

El objeto stream.

value

Variable a escribir.

Observaciones

Es una escritura binaria. No utilizar en streams de texto "puros".


stm_write_i16 ()

Escribe una variable int16_t en el stream.

void
stm_write_i16(Stream *stm,
              const int16_t value);
stm

El objeto stream.

value

Variable a escribir.

Observaciones

Es una escritura binaria. No utilizar en streams de texto "puros". Orden de bytes.


stm_write_i32 ()

Escribe una variable int32_t en el stream.

void
stm_write_i32(Stream *stm,
              const int32_t value);
stm

El objeto stream.

value

Variable a escribir.

Observaciones

Es una escritura binaria. No utilizar en streams de texto "puros". Orden de bytes.


stm_write_i64 ()

Escribe una variable int64_t en el stream.

void
stm_write_i64(Stream *stm,
              const int64_t value);
stm

El objeto stream.

value

Variable a escribir.

Observaciones

Es una escritura binaria. No utilizar en streams de texto "puros". Orden de bytes.


stm_write_u8 ()

Escribe una variable uint8_t en el stream.

void
stm_write_u8(Stream *stm,
             const uint8_t value);
stm

El objeto stream.

value

Variable a escribir.

Observaciones

Es una escritura binaria. No utilizar en streams de texto "puros".


stm_write_u16 ()

Escribe una variable uint16_t en el stream.

void
stm_write_u16(Stream *stm,
              const uint16_t value);
stm

El objeto stream.

value

Variable a escribir.

Observaciones

Es una escritura binaria. No utilizar en streams de texto "puros". Orden de bytes.


stm_write_u32 ()

Escribe una variable uint32_t en el stream.

void
stm_write_u32(Stream *stm,
              const uint32_t value);
stm

El objeto stream.

value

Variable a escribir.

Observaciones

Es una escritura binaria. No utilizar en streams de texto "puros". Orden de bytes.


stm_write_u64 ()

Escribe una variable uint64_t en el stream.

void
stm_write_u64(Stream *stm,
              const uint64_t value);
stm

El objeto stream.

value

Variable a escribir.

Observaciones

Es una escritura binaria. No utilizar en streams de texto "puros". Orden de bytes.


stm_write_r32 ()

Escribe una variable real32_t en el stream.

void
stm_write_r32(Stream *stm,
              const real32_t value);
stm

El objeto stream.

value

Variable a escribir.

Observaciones

Es una escritura binaria. No utilizar en streams de texto "puros". Orden de bytes.


stm_write_r64 ()

Escribe una variable real64_t en el stream.

void
stm_write_r64(Stream *stm,
              const real64_t value);
stm

El objeto stream.

value

Variable a escribir.

Observaciones

Es una escritura binaria. No utilizar en streams de texto "puros". Orden de bytes.


stm_write_enum ()

Escribe una variable enum en el stream.

void
stm_write_enum(Stream *stm,
               const type value,
               type);
stm

El objeto stream.

value

Variable a escribir.

type

El tipo del enum.

Observaciones

Es una escritura binaria. No utilizar en streams de texto "puros". Orden de bytes.


stm_read ()

Lee bytes desde el stream.

uint32_t
stm_read(Stream *stm,
         byte_t *data,
         const uint32_t size);
stm

El objeto stream.

data

Puntero al búfer donde se escribirán los datos leídos.

size

La cantidad de bytes a leer (tamaño del búfer).

Retorna

El número de bytes realmente leídos.


stm_read_char ()

Lee un carácter de texto desde el stream.

uint32_t
stm_read_char(Stream *stm);
stm

El objeto stream.

Retorna

El código Unicode del carácter.

Observaciones

La codificación del texto de entrada puede ajustarse con stm_set_read_utf. Actualizará el contador de filas y columnas. Ver stm_col.


stm_read_chars ()

Lee varios caracteres desde el stream.

const char_t*
stm_read_chars(Stream *stm,
               const uint32_t n);
stm

El objeto stream.

n

La cantidad de caracteres a leer.

Retorna

Puntero a la cadena C UTF8 leída. Terminará con el carácter nulo '\0'.

Observaciones

El puntero devuelto es temporal y será sobrescrito en la próxima lectura. Si es necesario, haz una copia con str_c. La codificación del texto de entrada puede ajustarse con stm_set_read_utf. Actualizará el contador de filas y columnas. Ver stm_col.


stm_read_line ()

Lee caracteres del stream hasta alcanzar un final de línea '\n'.

const char_t*
stm_read_line(Stream *stm);
stm

El objeto stream.

Retorna

Puntero a la cadena C UTF8, terminada con el carácter nulo '\0'. Los caracteres '\n' o '\r\n' no serán incluidos en el resultado. Se devolverá NULL cuando se alcance el final del stream.

Observaciones

El puntero devuelto es temporal y será sobrescrito en la próxima lectura. Si es necesario, haz una copia con str_c. La codificación del texto de entrada puede ajustarse con stm_set_read_utf. Actualizará el contador de filas y columnas. Ver stm_col.


stm_read_trim ()

Lee la siguiente secuencia de caracteres eliminando los espacios en blanco.

const char_t*
stm_read_trim(Stream *stm);
stm

El objeto stream.

Retorna

Puntero a la cadena C UTF8 leída. Terminará con el carácter nulo '\0'.

Observaciones

Útil para leer cadenas desde streams de texto. Ignorará todos los espacios en blanco iniciales y leerá caracteres hasta encontrar el primer blanco (' ', '\\t', '\\n', '\\v', '\\f', '\\r'). Si necesitas mayor control sobre los tokens utiliza stm_read_token. El puntero devuelto es temporal y será sobrescrito en la próxima lectura. Si es necesario, haz una copia con str_c. La codificación del texto de entrada puede ajustarse con stm_set_read_utf. Actualizará el contador de filas y columnas. Ver stm_col.


stm_read_token ()

Obtiene el siguiente token en Stream de texto.

token_t
stm_read_token(Stream *stm);
stm

El objeto stream.

Retorna

El tipo de token obtenido.

Observaciones

Para obtener la cadena de texto asociada al token, utiliza stm_token_lexeme. Ver Tokens.


stm_read_i8_tok ()

Lee el siguiente token con stm_read_token y, si es un número entero, lo convierte a int8_t.

int8_t
stm_read_i8_tok(Stream *stm);
stm

El objeto stream.

Retorna

El valor numérico del token.

Observaciones

En caso que no se pueda leer un token de tipo ekTINTEGER (con o sin ekTMINUS) o que el valor numérico esté fuera de rango, se devolverá 0 y se marcará el stream como corrupto con stm_corrupt.


stm_read_i16_tok ()

Lee el siguiente token y lo convierte a int16_t.

int16_t
stm_read_i16_tok(Stream *stm);
stm

El objeto stream.

Retorna

El valor numérico del token.

Observaciones

Ver stm_read_i8_tok.


stm_read_i32_tok ()

Lee el siguiente token y lo convierte a int32_t.

int32_t
stm_read_i32_tok(Stream *stm);
stm

El objeto stream.

Retorna

El valor numérico del token.

Observaciones

Ver stm_read_i8_tok.


stm_read_i64_tok ()

Lee el siguiente token y lo convierte a int64_t.

int64_t
stm_read_i64_tok(Stream *stm);
stm

El objeto stream.

Retorna

El valor numérico del token.

Observaciones

Ver stm_read_i8_tok.


stm_read_u8_tok ()

Lee el siguiente token con stm_read_token y, si es un número entero, lo convierte a uint8_t.

uint8_t
stm_read_u8_tok(Stream *stm);
stm

El objeto stream.

Retorna

El valor numérico del token.

Observaciones

En caso que no se pueda leer un token de tipo ekTINTEGER o que el valor numérico esté fuera de rango, se devolverá 0 y se marcará el stream como corrupto con stm_corrupt.


stm_read_u16_tok ()

Lee el siguiente token y lo convierte a uint16_t.

uint16_t
stm_read_u16_tok(Stream *stm);
stm

El objeto stream.

Retorna

El valor numérico del token.

Observaciones

Ver stm_read_u8_tok.


stm_read_u32_tok ()

Lee el siguiente token y lo convierte a uint32_t.

uint32_t
stm_read_u32_tok(Stream *stm);
stm

El objeto stream.

Retorna

El valor numérico del token.

Observaciones

Ver stm_read_u8_tok.


stm_read_u64_tok ()

Lee el siguiente token y lo convierte a uint64_t.

uint64_t
stm_read_u64_tok(Stream *stm);
stm

El objeto stream.

Retorna

El valor numérico del token.

Observaciones

Ver stm_read_u8_tok.


stm_read_r32_tok ()

Lee el siguiente token con stm_read_token y, si es un número real, lo convierte a real32_t.

real32_t
stm_read_r32_tok(Stream *stm);
stm

El objeto stream.

Retorna

El valor numérico del token.

Observaciones

En caso que no se pueda leer un token de tipo ekTINTEGER o ekTREAL (con o sin ekTMINUS), se devolverá 0 y se marcará el stream como corrupto con stm_corrupt.


stm_read_r64_tok ()

Lee el siguiente token y lo convierte a real64_t.

real64_t
stm_read_r64_tok(Stream *stm);
stm

El objeto stream.

Retorna

El valor numérico del token.

Observaciones

Ver stm_read_r32_tok.


stm_read_bool ()

Lee una variable bool_t desde el stream.

bool_t
stm_read_bool(Stream *stm);
stm

El objeto stream.

Retorna

Variable leída.

Observaciones

Se leerá 1 byte. Si el valor es diferente de 0 o 1, se marcará el stream como corrupto con stm_corrupt. Ver Stream binario.


stm_read_i8 ()

Lee una variable int8_t desde el stream.

int8_t
stm_read_i8(Stream *stm);
stm

El objeto stream.

Retorna

Variable leída.

Observaciones

Se leerá 1 byte. Ver Stream binario.


stm_read_i16 ()

Lee una variable int16_t desde el stream.

int16_t
stm_read_i16(Stream *stm);
stm

El objeto stream.

Retorna

Variable leída.

Observaciones

Se leerán 2 bytes. Ver Stream binario.


stm_read_i32 ()

Lee una variable int32_t desde el stream.

int32_t
stm_read_i32(Stream *stm);
stm

El objeto stream.

Retorna

Variable leída.

Observaciones

Se leerán 4 bytes. Ver Stream binario.


stm_read_i64 ()

Lee una variable int64_t desde el stream.

int64_t
stm_read_i64(Stream *stm);
stm

El objeto stream.

Retorna

Variable leída.

Observaciones

Se leerán 8 bytes. Ver Stream binario.


stm_read_u8 ()

Lee una variable uint8_t desde el stream.

uint8_t
stm_read_u8(Stream *stm);
stm

El objeto stream.

Retorna

Variable leída.

Observaciones

Se leerá 1 byte. Ver Stream binario.


stm_read_u16 ()

Lee una variable uint16_t desde el stream.

uint16_t
stm_read_u16(Stream *stm);
stm

El objeto stream.

Retorna

Variable leída.

Observaciones

Se leerán 2 bytes. Ver Stream binario.


stm_read_u32 ()

Lee una variable uint32_t desde el stream.

uint32_t
stm_read_u32(Stream *stm);
stm

El objeto stream.

Retorna

Variable leída.

Observaciones

Se leerán 4 bytes. Ver Stream binario.


stm_read_u64 ()

Lee una variable uint64_t desde el stream.

uint64_t
stm_read_u64(Stream *stm);
stm

El objeto stream.

Retorna

Variable leída.

Observaciones

Se leerán 8 bytes. Ver Stream binario.


stm_read_r32 ()

Lee una variable real32_t desde el stream.

real32_t
stm_read_r32(Stream *stm);
stm

El objeto stream.

Retorna

Variable leída.

Observaciones

Se leerán 4 bytes. Ver Stream binario.


stm_read_r64 ()

Lee una variable real64_t desde el stream.

real64_t
stm_read_r64(Stream *stm);
stm

El objeto stream.

Retorna

Variable leída.

Observaciones

Se leerán 8 bytes. Ver Stream binario.


stm_read_enum ()

Lee una variable enum desde el stream.

type
stm_read_enum(Stream *stm,
              type);
stm

El objeto stream.

type

El tipo del enum.

Retorna

Variable leída.

Observaciones

Se leerán 4 bytes. Ver Stream binario.


stm_skip ()

Salta e ignora los próximos bytes del stream.

void
stm_skip(Stream *stm,
         const uint32_t size);
stm

El objeto stream.

size

La cantidad de bytes a saltar.


stm_skip_bom ()

Salta la posible secuencia Byte Order Mark "" que se encuentra al comienzo de algunos streams de texto.

void
stm_skip_bom(Stream *stm);
stm

El objeto stream.

Observaciones

Esta función no tendrá efecto si no existe dicha secuencia al inicio del stream. El BOM es habitual en streams provenientes de algunos servidores Web.


stm_skip_token ()

Salta el siguiente token del stream. Si el token no corresponde al indicado, se marcará el stream como corrupto.

void
stm_skip_token(Stream *stm,
               const token_t token);
1
2
3
4
5
6
void stm_skip_token(Stream *stm, const token_t token)
{
    token_t tok = stm_read_token(stm);
    if (tok != token)
        stm_corrupt(stm);
}
stm

El objeto stream.

token

Token esperado.


stm_flush ()

Escribe en el canal la información existente en la caché.

void
stm_flush(Stream *stm);
stm

El objeto stream.

Observaciones

Para mejorar el rendimiento, las operaciones de escritura en streams de disco o E/S estándar se almacenan en una caché interna. Esta función fuerza la escritura en el canal y limpia el búfer. Será útil con protocolos full-duplex donde el receptor espera contestación para continuar.


stm_pipe ()

Conecta dos streams, leyendo datos de uno y escribiéndolos en otro.

void
stm_pipe(Stream *from,
         Stream *to,
         const uint32_t n);
from

El objeto stream de entrada (para leer).

to

El objeto stream de salida (para escribir).

n

La cantidad de bytes a trasvasar.

Observaciones

El trasvase se realizará sobre datos "en bruto", sin tener en cuenta Orden de bytes o Codificaciones UTF. Si tienes claro que esto no afecta, es mucho más rápido que utilizar operaciones atómicas de lectura/escritura.


stm_lines ()

Itera sobre todas las líneas en un Stream de texto. Debes usar stm_next para cerrar el bucle.

void
stm_lines(const char_t *line,
          Stream *stm);
1
2
3
4
5
6
uint32_t i = 1;
Stream *stm = stm_from_file("/home/john/friends.txt", NULL);
stm_lines(line, stm)
    bstd_printf("Friend %d, name %s\n", i++, line);
stm_next(line, stm)
stm_close(&stm);
line

Nombre de la variable que albergará temporalmente la línea. Utiliza una caché interna del stream, por lo que deberás hacer una copia con str_c si necesitas conservarla.

stm

Stream.


stm_next ()

Cierra un bucle abierto por stm_lines.

void
stm_next(const char_t *line,
         Stream *stm);
line

Nombre de la variable línea.

stm

Stream.

❮ Anterior
Siguiente ❯