Coverage Report

Created: 2025-11-16 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libconfig/lib/scanctx.c
Line
Count
Source
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
1.75k
{
41
1.75k
  __zero(ctx);
42
1.75k
  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
1.75k
}
48
49
/* ------------------------------------------------------------------------- */
50
51
const char **libconfig_scanctx_cleanup(struct scan_context *ctx)
52
1.75k
{
53
1.75k
  int i;
54
55
1.75k
  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
1.75k
  __delete(libconfig_strbuf_release(&(ctx->string)));
66
67
1.75k
  return(libconfig_strvec_release(&(ctx->filenames)));
68
1.75k
}
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.61k
{
126
1.61k
  struct include_stack_frame *include_frame;
127
128
1.61k
  *error = NULL;
129
130
1.61k
  if(ctx->stack_depth == 0)
131
1.61k
    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
1.82k
{
160
1.82k
  struct include_stack_frame *frame;
161
162
1.82k
  if(ctx->stack_depth == 0)
163
1.82k
    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
1.82k
}
178
179
/* ------------------------------------------------------------------------- */
180
181
char *libconfig_scanctx_take_string(struct scan_context *ctx)
182
3.73k
{
183
3.73k
  char *r = libconfig_strbuf_release(&(ctx->string));
184
185
3.73k
  return(r ? r : strdup(""));
186
3.73k
}
187
188
/* ------------------------------------------------------------------------- */
189
190
const char *libconfig_scanctx_current_filename(struct scan_context *ctx)
191
60.4k
{
192
60.4k
  if(ctx->stack_depth > 0)
193
0
    return(*(ctx->include_stack[ctx->stack_depth - 1].current_file));
194
195
60.4k
  return(ctx->top_filename);
196
60.4k
}
197
198
/* ------------------------------------------------------------------------- */