199 lines
5.2 KiB
C
Executable File
199 lines
5.2 KiB
C
Executable File
/* ----------------------------------------------------------------------------
|
|
libconfig - A library for processing structured configuration files
|
|
Copyright (C) 2005-2020 Mark A Lindner
|
|
|
|
This file is part of libconfig.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public License
|
|
as published by the Free Software Foundation; either version 2.1 of
|
|
the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; if not, see
|
|
<http://www.gnu.org/licenses/>.
|
|
----------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "scanctx.h"
|
|
#include "strvec.h"
|
|
#include "wincompat.h"
|
|
#include "util.h"
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static const char *err_bad_include = "cannot open include file";
|
|
static const char *err_include_too_deep = "include file nesting too deep";
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
void libconfig_scanctx_init(struct scan_context *ctx, const char *top_filename)
|
|
{
|
|
__zero(ctx);
|
|
if(top_filename)
|
|
{
|
|
ctx->top_filename = strdup(top_filename);
|
|
libconfig_strvec_append(&(ctx->filenames), ctx->top_filename);
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
const char **libconfig_scanctx_cleanup(struct scan_context *ctx)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < ctx->stack_depth; ++i)
|
|
{
|
|
struct include_stack_frame *frame = &(ctx->include_stack[i]);
|
|
|
|
if(frame->current_stream)
|
|
fclose(frame->current_stream);
|
|
|
|
__delete(frame->files);
|
|
}
|
|
|
|
__delete(libconfig_strbuf_release(&(ctx->string)));
|
|
|
|
return(libconfig_strvec_release(&(ctx->filenames)));
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
FILE *libconfig_scanctx_push_include(struct scan_context *ctx, void *prev_buffer,
|
|
const char *path, const char **error)
|
|
{
|
|
struct include_stack_frame *frame;
|
|
const char **files = NULL, **f;
|
|
FILE *fp;
|
|
|
|
if(ctx->stack_depth == MAX_INCLUDE_DEPTH)
|
|
{
|
|
*error = err_include_too_deep;
|
|
return(NULL);
|
|
}
|
|
|
|
*error = NULL;
|
|
|
|
if(ctx->config->include_fn)
|
|
files = ctx->config->include_fn(ctx->config, ctx->config->include_dir,
|
|
path, error);
|
|
|
|
if(*error || !files)
|
|
{
|
|
libconfig_strvec_delete(files);
|
|
return(NULL);
|
|
}
|
|
|
|
if(!*files)
|
|
{
|
|
libconfig_strvec_delete(files);
|
|
return(NULL);
|
|
}
|
|
|
|
frame = &(ctx->include_stack[ctx->stack_depth]);
|
|
|
|
for(f = files; *f; ++f)
|
|
libconfig_strvec_append(&(ctx->filenames), *f);
|
|
|
|
frame->files = files;
|
|
frame->current_file = NULL;
|
|
frame->current_stream = NULL;
|
|
frame->parent_buffer = prev_buffer;
|
|
++(ctx->stack_depth);
|
|
|
|
fp = libconfig_scanctx_next_include_file(ctx, error);
|
|
if(!fp)
|
|
(void)libconfig_scanctx_pop_include(ctx);
|
|
|
|
return(fp);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
FILE *libconfig_scanctx_next_include_file(struct scan_context *ctx,
|
|
const char **error)
|
|
{
|
|
struct include_stack_frame *include_frame;
|
|
|
|
*error = NULL;
|
|
|
|
if(ctx->stack_depth == 0)
|
|
return(NULL);
|
|
|
|
include_frame = &(ctx->include_stack[ctx->stack_depth - 1]);
|
|
|
|
if(include_frame->current_file)
|
|
++(include_frame->current_file);
|
|
else
|
|
include_frame->current_file = include_frame->files;
|
|
|
|
if(include_frame->current_stream)
|
|
{
|
|
fclose(include_frame->current_stream);
|
|
include_frame->current_stream = NULL;
|
|
}
|
|
|
|
if(!*(include_frame->current_file))
|
|
return(NULL);
|
|
|
|
include_frame->current_stream = fopen(*(include_frame->current_file), "rt");
|
|
if(!include_frame->current_stream)
|
|
*error = err_bad_include;
|
|
|
|
return(include_frame->current_stream);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
void *libconfig_scanctx_pop_include(struct scan_context *ctx)
|
|
{
|
|
struct include_stack_frame *frame;
|
|
|
|
if(ctx->stack_depth == 0)
|
|
return(NULL); /* stack underflow */
|
|
|
|
frame = &(ctx->include_stack[--(ctx->stack_depth)]);
|
|
|
|
__delete(frame->files);
|
|
frame->files = NULL;
|
|
|
|
if(frame->current_stream)
|
|
{
|
|
fclose(frame->current_stream);
|
|
frame->current_stream = NULL;
|
|
}
|
|
|
|
return(frame->parent_buffer);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
char *libconfig_scanctx_take_string(struct scan_context *ctx)
|
|
{
|
|
char *r = libconfig_strbuf_release(&(ctx->string));
|
|
|
|
return(r ? r : strdup(""));
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
const char *libconfig_scanctx_current_filename(struct scan_context *ctx)
|
|
{
|
|
if(ctx->stack_depth > 0)
|
|
return(*(ctx->include_stack[ctx->stack_depth - 1].current_file));
|
|
|
|
return(ctx->top_filename);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|