lccrt/lib/common/lccrt_fs.c

352 lines
8.4 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Part of the Lccrt Project, under the Apache License v2.0
* See http://www.apache.org/licenses/LICENSE-2.0.txt for license information.
* SPDX-License-Identifier: Apache-2.0
*
* lccrt_fs.c - работа с потоками данных.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "lccrt_real.h"
/**
* Разновидности потоков данных.
*/
typedef enum
{
LCCRT_FS_TYPE_FILE,
LCCRT_FS_TYPE_BUFFER,
LCCRT_FS_TYPE_LAST
} lccrt_fs_type_t;
/**
* Файловый поток данных.
*/
typedef struct lccrt_fs_r
{
lccrt_context_ptr ctx; /* etc */
lccrt_fs_type_t type; /* тип потока данных */
FILE *file;
char *buff;
uint64_t buff_size; /* размер буфера (для LCCRT_FS_TYPE_BUFFER) */
uint64_t syms_count; /* счетчик записанных или прочитанных символов */
int8_t is_self; /* флаг владением потоком данных */
int8_t is_error; /* флаг возникновения ошибки при работе с потоком данных */
lccrt_check_type_t type_check; /* средства динамического контроля типа данных */
} lccrt_fs_t;
lccrt_check_type_define( lccrt_fs_t);
/**
* Открытие потока данных.
*/
static lccrt_fs_ptr
lccrt_fs_new( lccrt_context_ptr ctx)
{
lccrt_fs_ptr r = 0;
r = lccrt_ctx_malloc( ctx, lccrt_fs_t);
memset( r, 0, sizeof( r[0]));
lccrt_check_type_init( r, lccrt_fs_t);
r->ctx = ctx;
r->type = LCCRT_FS_TYPE_LAST;
r->file = 0;
r->buff = 0;
r->buff_size = 0;
r->is_self = 0;
r->is_error = 0;
r->syms_count = 0;
return (r);
} /* lccrt_fs_new */
/**
* Открытие потока данных на основе файла.
*/
lccrt_fs_ptr
lccrt_fs_new_file( lccrt_context_ptr ctx, FILE *file)
{
lccrt_fs_ptr r = 0;
if ( file )
{
r = lccrt_fs_new( ctx);
r->type = LCCRT_FS_TYPE_FILE;
r->file = file;
}
return (r);
} /* lccrt_fs_new_file */
/**
* Открытие потока данных на основе файла.
*/
lccrt_fs_ptr
lccrt_fs_open_file( lccrt_context_ptr ctx, const char *name, int is_load)
{
lccrt_fs_ptr r = 0;
FILE *file = 0;
file = fopen( name, is_load ? "r" : "w");
if ( file )
{
r = lccrt_fs_new_file( ctx, file);
r->is_self = 1;
}
return (r);
} /* lccrt_fs_open_file */
/**
* Открытие потока данных на основе буфера в памяти.
*/
lccrt_fs_ptr
lccrt_fs_new_buffer( lccrt_context_ptr ctx, char *buff, uint64_t buff_size)
{
lccrt_fs_ptr r = 0;
r = lccrt_fs_new( ctx);
r->type = LCCRT_FS_TYPE_BUFFER;
if ( buff )
{
r->buff_size = buff_size;
r->buff = buff;
} else
{
r->is_self = 1;
r->buff_size = buff_size ? buff_size : 4096;
r->buff = lccrt_ctx_mallocn( ctx, char, r->buff_size);
}
return (r);
} /* lccrt_fs_new_buffer */
/**
* Закрытие потока данных.
*/
int
lccrt_fs_delete( lccrt_fs_ptr f)
{
int r = 0;
if ( f )
{
lccrt_check_type_assert( f, lccrt_fs_t);
if ( (f->type == LCCRT_FS_TYPE_FILE) )
{
if ( f->is_self )
{
r = fclose( f->file);
}
} else if ( (f->type == LCCRT_FS_TYPE_BUFFER) )
{
if ( f->is_self )
{
lccrt_ctx_free( f->ctx, f->buff);
}
} else
{
r = -1;
lccrt_assert( 0);
}
lccrt_check_type_done( f, lccrt_fs_t);
lccrt_ctx_free( f->ctx, f);
}
return (r);
} /* lccrt_fs_delete */
/**
* Получить значение поля.
*/
int
lccrt_fs_is_error( lccrt_fs_ptr f)
{
int r = 0;
lccrt_check_type_assert( f, lccrt_fs_t);
r = f->is_error;
return (r);
} /* lccrt_fs_is_error */
/**
* Получить значение поля.
*/
uint64_t
lccrt_fs_get_syms_count( lccrt_fs_ptr f)
{
uint64_t r = 0;
lccrt_check_type_assert( f, lccrt_fs_t);
r = f->syms_count;
return (r);
} /* lccrt_fs_get_syms_count */
/**
* Для потока данных на основе буфера дать ссылку на область данных
* (ссылка доступна только до первого действия с потоком данных).
*/
char *
lccrt_fs_get_buffer( lccrt_fs_ptr f)
{
char *r = f->buff;
lccrt_check_type_assert( f, lccrt_fs_t);
return (r);
} /* lccrt_fs_get_buffer */
/**
* Чтение символа из потока.
*/
int
lccrt_fs_get_sym( lccrt_fs_ptr f)
{
int r = EOF;
lccrt_check_type_assert( f, lccrt_fs_t);
if ( (f->type == LCCRT_FS_TYPE_FILE) )
{
r = fgetc( f->file);
if ( !feof( f->file) )
{
f->syms_count++;
}
} else if ( (f->type == LCCRT_FS_TYPE_BUFFER) )
{
if ( (f->syms_count < f->buff_size) )
{
r = f->buff[f->syms_count];
f->syms_count++;
}
} else
{
lccrt_assert( 0);
}
return (r);
} /* lccrt_fs_get_sym */
/**
* Форматированный вывод в поток данных.
*/
int
lccrt_fs_printf( lccrt_fs_ptr f, const char *fmt, ...)
{
va_list ap;
int r = 0;
lccrt_check_type_assert( f, lccrt_fs_t);
if ( !f->is_error )
{
if ( (f->type == LCCRT_FS_TYPE_FILE) )
{
va_start( ap, fmt);
r = vfprintf( f->file, fmt, ap);
va_end( ap);
} else if ( (f->type == LCCRT_FS_TYPE_BUFFER) )
{
int k = f->buff_size;
int j = f->syms_count;
lccrt_assert( f->syms_count <= f->buff_size);
lccrt_assert( f->buff_size > 0);
if ( !f->is_self )
{
va_start( ap, fmt);
r = vsnprintf( f->buff + j, k - j, fmt, ap);
va_end( ap);
if ( (r == k - j) )
{
int l = 0;
char *b = lccrt_ctx_mallocn( f->ctx, char, r + 1);
/* Проверяем, что размера буфера было достаточно для вывода
всех данных. */
va_start( ap, fmt);
l = vsnprintf( b, r + 1, fmt, ap);
va_end( ap);
lccrt_ctx_free( f->ctx, b);
if ( (r != l) )
{
/* Превышен допустимый размер буфера. */
f->is_error = 1;
}
}
} else
{
int is_work = 1;
while ( is_work )
{
va_start( ap, fmt);
r = vsnprintf( f->buff + j, k - j, fmt, ap);
va_end( ap);
if ( (r < k - j) )
{
/* Текущего размера буфера достаточно. */
is_work = 0;
} else
{
/* Необходимо увеличить размер буфера. */
f->buff_size = 2*f->buff_size;
f->buff = lccrt_ctx_realloc( f->ctx, f->buff, f->buff_size);
k = f->buff_size;
}
}
}
} else
{
lccrt_assert( 0);
r = -1;
}
if ( (r < 0) )
{
f->is_error = 1;
} else
{
f->syms_count += r;
}
}
return (r);
} /* lccrt_fs_printf */
/**
* Вывод на печать строки и символа '\0', после строки.
*/
int
lccrt_fs_print_name_str( lccrt_fs_ptr f, const char *name)
{
int r = 0;
if ( name )
{
int k = 0;
for ( k = 0; name[k]; ++k )
{
if ( (name[k] == 0)
|| (name[k] == '\\') )
{
r += lccrt_fs_printf( f, "\\");
}
r += lccrt_fs_printf( f, "%c", name[k]);
}
r += lccrt_fs_printf( f, "%c", 0);
}
return (r);
} /* lccrt_fs_print_name_str */