Coverage Report

Created: 2025-08-12 06:38

/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.12k
{
41
2.12k
  __zero(ctx);
42
2.12k
  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.12k
}
48
49
/* ------------------------------------------------------------------------- */
50
51
const char **libconfig_scanctx_cleanup(struct scan_context *ctx)
52
2.12k
{
53
2.12k
  int i;
54
55
2.12k
  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.12k
  __delete(libconfig_strbuf_release(&(ctx->string)));
66
67
2.12k
  return(libconfig_strvec_release(&(ctx->filenames)));
68
2.12k
}
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.85k
{
126
1.85k
  struct include_stack_frame *include_frame;
127
128
1.85k
  *error = NULL;
129
130
1.85k
  if(ctx->stack_depth == 0)
131
1.85k
    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.22k
{
160
2.22k
  struct include_stack_frame *frame;
161
162
2.22k
  if(ctx->stack_depth == 0)
163
2.22k
    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.22k
}
178
179
/* ------------------------------------------------------------------------- */
180
181
char *libconfig_scanctx_take_string(struct scan_context *ctx)
182
3.40k
{
183
3.40k
  char *r = libconfig_strbuf_release(&(ctx->string));
184
185
3.40k
  return(r ? r : strdup(""));
186
3.40k
}
187
188
/* ------------------------------------------------------------------------- */
189
190
const char *libconfig_scanctx_current_filename(struct scan_context *ctx)
191
90.5k
{
192
90.5k
  if(ctx->stack_depth > 0)
193
0
    return(*(ctx->include_stack[ctx->stack_depth - 1].current_file));
194
195
90.5k
  return(ctx->top_filename);
196
90.5k
}
197
198
/* ------------------------------------------------------------------------- */