Coverage Report

Created: 2025-08-29 06:37

/src/libconfig/lib/scanctx.c
Line
Count
Source (jump to first uncovered line)
1
/* ----------------------------------------------------------------------------
2
   libconfig - A library for processing structured configuration files
3
   Copyright (C) 2005-2025  Mark A Lindner
4
5
   This file is part of libconfig.
6
7
   This library is free software; you can redistribute it and/or
8
   modify it under the terms of the GNU Lesser General Public License
9
   as published by the Free Software Foundation; either version 2.1 of
10
   the License, or (at your option) any later version.
11
12
   This library is distributed in the hope that it will be useful, but
13
   WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
   Lesser General Public License for more details.
16
17
   You should have received a copy of the GNU Library General Public
18
   License along with this library; if not, see
19
   <http://www.gnu.org/licenses/>.
20
   ----------------------------------------------------------------------------
21
*/
22
23
#include "scanctx.h"
24
#include "strvec.h"
25
#include "wincompat.h"
26
#include "util.h"
27
28
#include <stddef.h>
29
#include <stdlib.h>
30
#include <string.h>
31
32
/* ------------------------------------------------------------------------- */
33
34
static const char *err_bad_include = "cannot open include file";
35
static const char *err_include_too_deep = "include file nesting too deep";
36
37
/* ------------------------------------------------------------------------- */
38
39
void libconfig_scanctx_init(struct scan_context *ctx, const char *top_filename)
40
2.24k
{
41
2.24k
  __zero(ctx);
42
2.24k
  if(top_filename)
43
0
  {
44
0
    ctx->top_filename = strdup(top_filename);
45
0
    libconfig_strvec_append(&(ctx->filenames), ctx->top_filename);
46
0
  }
47
2.24k
}
48
49
/* ------------------------------------------------------------------------- */
50
51
const char **libconfig_scanctx_cleanup(struct scan_context *ctx)
52
2.24k
{
53
2.24k
  int i;
54
55
2.24k
  for(i = 0; i < ctx->stack_depth; ++i)
56
0
  {
57
0
    struct include_stack_frame *frame = &(ctx->include_stack[i]);
58
59
0
    if(frame->current_stream)
60
0
      fclose(frame->current_stream);
61
62
0
    __delete(frame->files);
63
0
  }
64
65
2.24k
  __delete(libconfig_strbuf_release(&(ctx->string)));
66
67
2.24k
  return(libconfig_strvec_release(&(ctx->filenames)));
68
2.24k
}
69
70
/* ------------------------------------------------------------------------- */
71
72
FILE *libconfig_scanctx_push_include(struct scan_context *ctx, void *prev_buffer,
73
                                     const char *path, const char **error)
74
0
{
75
0
  struct include_stack_frame *frame;
76
0
  const char **files = NULL, **f;
77
0
  FILE *fp;
78
79
0
  if(ctx->stack_depth == MAX_INCLUDE_DEPTH)
80
0
  {
81
0
    *error = err_include_too_deep;
82
0
    return(NULL);
83
0
  }
84
85
0
  *error = NULL;
86
87
0
  if(ctx->config->include_fn)
88
0
    files = ctx->config->include_fn(ctx->config, ctx->config->include_dir,
89
0
                                    path, error);
90
91
0
  if(*error || !files)
92
0
  {
93
0
    libconfig_strvec_delete(files);
94
0
    return(NULL);
95
0
  }
96
97
0
  if(!*files)
98
0
  {
99
0
    libconfig_strvec_delete(files);
100
0
    return(NULL);
101
0
  }
102
103
0
  frame = &(ctx->include_stack[ctx->stack_depth]);
104
105
0
  for(f = files; *f; ++f)
106
0
    libconfig_strvec_append(&(ctx->filenames), *f);
107
108
0
  frame->files = files;
109
0
  frame->current_file = NULL;
110
0
  frame->current_stream = NULL;
111
0
  frame->parent_buffer = prev_buffer;
112
0
  ++(ctx->stack_depth);
113
114
0
  fp = libconfig_scanctx_next_include_file(ctx, error);
115
0
  if(!fp)
116
0
    (void)libconfig_scanctx_pop_include(ctx);
117
118
0
  return(fp);
119
0
}
120
121
/* ------------------------------------------------------------------------- */
122
123
FILE *libconfig_scanctx_next_include_file(struct scan_context *ctx,
124
                                          const char **error)
125
1.95k
{
126
1.95k
  struct include_stack_frame *include_frame;
127
128
1.95k
  *error = NULL;
129
130
1.95k
  if(ctx->stack_depth == 0)
131
1.95k
    return(NULL);
132
133
0
  include_frame = &(ctx->include_stack[ctx->stack_depth - 1]);
134
135
0
  if(include_frame->current_file)
136
0
    ++(include_frame->current_file);
137
0
  else
138
0
    include_frame->current_file = include_frame->files;
139
140
0
  if(include_frame->current_stream)
141
0
  {
142
0
    fclose(include_frame->current_stream);
143
0
    include_frame->current_stream = NULL;
144
0
  }
145
146
0
  if(!*(include_frame->current_file))
147
0
    return(NULL);
148
149
0
  include_frame->current_stream = fopen(*(include_frame->current_file), "rt");
150
0
  if(!include_frame->current_stream)
151
0
    *error = err_bad_include;
152
153
0
  return(include_frame->current_stream);
154
0
}
155
156
/* ------------------------------------------------------------------------- */
157
158
void *libconfig_scanctx_pop_include(struct scan_context *ctx)
159
2.36k
{
160
2.36k
  struct include_stack_frame *frame;
161
162
2.36k
  if(ctx->stack_depth == 0)
163
2.36k
    return(NULL); /* stack underflow */
164
165
0
  frame = &(ctx->include_stack[--(ctx->stack_depth)]);
166
167
0
  __delete(frame->files);
168
0
  frame->files = NULL;
169
170
0
  if(frame->current_stream)
171
0
  {
172
0
    fclose(frame->current_stream);
173
0
    frame->current_stream = NULL;
174
0
  }
175
176
0
  return(frame->parent_buffer);
177
2.36k
}
178
179
/* ------------------------------------------------------------------------- */
180
181
char *libconfig_scanctx_take_string(struct scan_context *ctx)
182
3.85k
{
183
3.85k
  char *r = libconfig_strbuf_release(&(ctx->string));
184
185
3.85k
  return(r ? r : strdup(""));
186
3.85k
}
187
188
/* ------------------------------------------------------------------------- */
189
190
const char *libconfig_scanctx_current_filename(struct scan_context *ctx)
191
87.7k
{
192
87.7k
  if(ctx->stack_depth > 0)
193
0
    return(*(ctx->include_stack[ctx->stack_depth - 1].current_file));
194
195
87.7k
  return(ctx->top_filename);
196
87.7k
}
197
198
/* ------------------------------------------------------------------------- */