• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ----------------------------------------------------------------------------
2    libconfig - A library for processing structured configuration files
3    Copyright (C) 2005-2020  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 
libconfig_scanctx_init(struct scan_context * ctx,const char * top_filename)39 void libconfig_scanctx_init(struct scan_context *ctx, const char *top_filename)
40 {
41   __zero(ctx);
42   if(top_filename)
43   {
44     ctx->top_filename = strdup(top_filename);
45     libconfig_strvec_append(&(ctx->filenames), ctx->top_filename);
46   }
47 }
48 
49 /* ------------------------------------------------------------------------- */
50 
libconfig_scanctx_cleanup(struct scan_context * ctx)51 const char **libconfig_scanctx_cleanup(struct scan_context *ctx)
52 {
53   int i;
54 
55   for(i = 0; i < ctx->stack_depth; ++i)
56   {
57     struct include_stack_frame *frame = &(ctx->include_stack[i]);
58 
59     if(frame->current_stream)
60       fclose(frame->current_stream);
61 
62     __delete(frame->files);
63   }
64 
65   __delete(libconfig_strbuf_release(&(ctx->string)));
66 
67   return(libconfig_strvec_release(&(ctx->filenames)));
68 }
69 
70 /* ------------------------------------------------------------------------- */
71 
libconfig_scanctx_push_include(struct scan_context * ctx,void * prev_buffer,const char * path,const char ** error)72 FILE *libconfig_scanctx_push_include(struct scan_context *ctx, void *prev_buffer,
73                                      const char *path, const char **error)
74 {
75   struct include_stack_frame *frame;
76   const char **files = NULL, **f;
77   FILE *fp;
78 
79   if(ctx->stack_depth == MAX_INCLUDE_DEPTH)
80   {
81     *error = err_include_too_deep;
82     return(NULL);
83   }
84 
85   *error = NULL;
86 
87   if(ctx->config->include_fn)
88     files = ctx->config->include_fn(ctx->config, ctx->config->include_dir,
89                                     path, error);
90 
91   if(*error || !files)
92   {
93     libconfig_strvec_delete(files);
94     return(NULL);
95   }
96 
97   if(!*files)
98   {
99     libconfig_strvec_delete(files);
100     return(NULL);
101   }
102 
103   frame = &(ctx->include_stack[ctx->stack_depth]);
104 
105   for(f = files; *f; ++f)
106     libconfig_strvec_append(&(ctx->filenames), *f);
107 
108   frame->files = files;
109   frame->current_file = NULL;
110   frame->current_stream = NULL;
111   frame->parent_buffer = prev_buffer;
112   ++(ctx->stack_depth);
113 
114   fp = libconfig_scanctx_next_include_file(ctx, error);
115   if(!fp)
116     (void)libconfig_scanctx_pop_include(ctx);
117 
118   return(fp);
119 }
120 
121 /* ------------------------------------------------------------------------- */
122 
libconfig_scanctx_next_include_file(struct scan_context * ctx,const char ** error)123 FILE *libconfig_scanctx_next_include_file(struct scan_context *ctx,
124                                           const char **error)
125 {
126   struct include_stack_frame *include_frame;
127 
128   *error = NULL;
129 
130   if(ctx->stack_depth == 0)
131     return(NULL);
132 
133   include_frame = &(ctx->include_stack[ctx->stack_depth - 1]);
134 
135   if(include_frame->current_file)
136     ++(include_frame->current_file);
137   else
138     include_frame->current_file = include_frame->files;
139 
140   if(include_frame->current_stream)
141   {
142     fclose(include_frame->current_stream);
143     include_frame->current_stream = NULL;
144   }
145 
146   if(!*(include_frame->current_file))
147     return(NULL);
148 
149   include_frame->current_stream = fopen(*(include_frame->current_file), "rt");
150   if(!include_frame->current_stream)
151     *error = err_bad_include;
152 
153   return(include_frame->current_stream);
154 }
155 
156 /* ------------------------------------------------------------------------- */
157 
libconfig_scanctx_pop_include(struct scan_context * ctx)158 void *libconfig_scanctx_pop_include(struct scan_context *ctx)
159 {
160   struct include_stack_frame *frame;
161 
162   if(ctx->stack_depth == 0)
163     return(NULL); /* stack underflow */
164 
165   frame = &(ctx->include_stack[--(ctx->stack_depth)]);
166 
167   __delete(frame->files);
168   frame->files = NULL;
169 
170   if(frame->current_stream)
171   {
172     fclose(frame->current_stream);
173     frame->current_stream = NULL;
174   }
175 
176   return(frame->parent_buffer);
177 }
178 
179 /* ------------------------------------------------------------------------- */
180 
libconfig_scanctx_take_string(struct scan_context * ctx)181 char *libconfig_scanctx_take_string(struct scan_context *ctx)
182 {
183   char *r = libconfig_strbuf_release(&(ctx->string));
184 
185   return(r ? r : strdup(""));
186 }
187 
188 /* ------------------------------------------------------------------------- */
189 
libconfig_scanctx_current_filename(struct scan_context * ctx)190 const char *libconfig_scanctx_current_filename(struct scan_context *ctx)
191 {
192   if(ctx->stack_depth > 0)
193     return(*(ctx->include_stack[ctx->stack_depth - 1].current_file));
194 
195   return(ctx->top_filename);
196 }
197 
198 /* ------------------------------------------------------------------------- */
199