#include <stddef.h>
#include <stdlib.h>
#include <string.h>
+#include <dirent.h>
#define STRING_BLOCK_SIZE 64
#define CHUNK_SIZE 32
/* ------------------------------------------------------------------------- */
FILE *scanctx_push_include(struct scan_context *ctx, void *buffer,
- const char **error)
+ const char *file, const char **error)
{
FILE *fp = NULL;
- const char *file;
- char *full_file = NULL;
-
- *error = NULL;
if(ctx->depth == MAX_INCLUDE_DEPTH)
{
*error = err_include_too_deep;
return(NULL);
}
-
- file = scanctx_take_string(ctx);
- if(ctx->config->include_dir)
- {
- full_file = (char *)malloc(strlen(ctx->config->include_dir) + strlen(file)
- + 2);
- strcpy(full_file, ctx->config->include_dir);
- strcat(full_file, FILE_SEPARATOR);
- strcat(full_file, file);
- }
-
- fp = fopen(full_file ? full_file : file, "rt");
- free((void *)full_file);
-
+ fp = fopen(file, "rt");
if(fp)
{
ctx->streams[ctx->depth] = fp;
ctx->files[ctx->depth] = __scanctx_add_filename(ctx, file);
ctx->buffers[ctx->depth] = buffer;
++(ctx->depth);
+ *error = NULL;
}
else
{
- free((void *)file);
*error = err_bad_include;
}
/* ------------------------------------------------------------------------- */
+const char *scanctx_getpath(struct scan_context *ctx)
+{
+ const char *name;
+ const char *full_path = NULL;
+
+ name = scanctx_take_string(ctx);
+ if(ctx->config->include_dir)
+ full_path = scanctx_filename(ctx, ctx->config->include_dir, name);
+ else
+ full_path = strdup(name);
+ free((void*)name);
+ return full_path;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+const char *scanctx_filename(struct scan_context *ctx,const char* dirname, const char* filename)
+{
+ const char* basedir = (NULL!=dirname)? dirname : ctx->basedir;
+ char *full_file = (char *)malloc(strlen(basedir) + strlen(filename) + 2);
+
+ strcpy(full_file, basedir);
+ strcat(full_file, FILE_SEPARATOR);
+ strcat(full_file, filename);
+
+ return full_file;
+}
+
+/* ------------------------------------------------------------------------- */
+
void *scanctx_pop_include(struct scan_context *ctx)
{
void *buffer;
--(ctx->depth);
buffer = ctx->buffers[ctx->depth];
- fclose(ctx->streams[ctx->depth]);
+ if(NULL!=ctx->streams[ctx->depth])
+ fclose(ctx->streams[ctx->depth]);
return(buffer);
}
/* ------------------------------------------------------------------------- */
+extern const char* scanctx_dirnext(struct scan_context* ctx)
+{
+ struct dirent** dentries= (struct dirent**)ctx->dentries;
+ if( NULL == ctx->dentries || ctx->de_cur==ctx->de_max ) /* shouldn't happen.... */
+ return NULL;
+
+ return dentries[ ctx->de_cur++ ]->d_name;
+}
+
+int scanctx_dirscan(struct scan_context* ctx, const char* dirname,
+ int (*filter)(const struct dirent *),
+ int (*compar)(const struct dirent **, const struct dirent **))
+{
+ int n;
+
+ if( NULL == dirname )
+ return -1;
+
+ ctx->dentries=NULL;
+ if( (n=scandir(dirname,(struct dirent***)&ctx->dentries,filter,compar)) < 0)
+ return n;
+
+ ctx->basedir=dirname;
+ ctx->de_max=n;
+ ctx->de_cur=0;
+
+ return n;
+}
+
+int scanctx_dirend(struct scan_context* ctx)
+{
+ struct dirent** dentries= (struct dirent**)ctx->dentries;
+ unsigned i;
+
+ for(i=0; i<ctx->de_max; i++)
+ free(dentries[i]);
+ free(ctx->dentries);
+ ctx->dentries=NULL;
+
+ if(ctx->basedir)
+ free((void*)ctx->basedir);
+ ctx->de_cur=ctx->de_max=0;
+
+ return 0;
+}
+int scanctx_inloop(const struct scan_context* ctx)
+{
+ if( NULL == ctx->dentries )
+ return 0;
+
+ return (ctx->de_cur < ctx->de_max)? 1 : 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
char *scanctx_take_string(struct scan_context *ctx)
{
char *r = strbuf_release(&(ctx->string));
const char *files[MAX_INCLUDE_DEPTH];
void *buffers[MAX_INCLUDE_DEPTH];
FILE *streams[MAX_INCLUDE_DEPTH];
- int depth;
strbuf_t string;
const char **filenames;
unsigned int num_filenames;
+ int depth;
+ void** dentries; /* dirent** */
+ const char* basedir; /* basedir for @include_dir */
+ unsigned de_max, de_cur; /* counters into dirent* array */
};
+struct dirent; /* forward decl */
+
extern void scanctx_init(struct scan_context *ctx, const char *top_filename);
extern const char **scanctx_cleanup(struct scan_context *ctx,
unsigned int *num_filenames);
+extern const char *scanctx_getpath(struct scan_context *ctx);
+extern const char *scanctx_filename(struct scan_context *ctx, const char *dirname, const char *filename);
+
+extern const char* scanctx_dirnext(struct scan_context* ctx);
+extern int scanctx_dirscan(struct scan_context* ctx, const char* dirname,
+ int (*filter)(const struct dirent *),
+ int (*compar)(const struct dirent **, const struct dirent **));
+extern int scanctx_dirend(struct scan_context* ctx);
+extern int scanctx_inloop(const struct scan_context* ctx);
+
extern FILE *scanctx_push_include(struct scan_context *ctx, void *prev_buffer,
- const char **error);
+ const char *file, const char **error);
extern void *scanctx_pop_include(struct scan_context *ctx);
#define scanctx_append_string(C, S) \
#include <ctype.h>
#include <string.h>
#include <limits.h>
+#include <dirent.h>
#include "parsectx.h"
#include "scanctx.h"
#include "grammar.h"
#endif /* __MINGW32__ */
}
+static int filter_dotfiles(const struct dirent *de)
+{
+ const char *fname = de->d_name;
+ return ( NULL != fname
+ && '\0' != fname[0] /* can't really happen */
+ && '.' != fname[0] ) ? 1 : 0 ;
+}
+
%}
true [Tt][Rr][Uu][Ee]
hexchar \\[Xx][0-9A-Fa-f]{2}
float ([-+]?([0-9]*)?\.[0-9]*([eE][-+]?[0-9]+)?)|([-+]?([0-9]+)(\.[0-9]*)?[eE][-+]?[0-9]+)
comment (#|\/\/).*$
-include_open ^[ \t]*@include[ \t]+\"
+include_file_open ^[ \t]*@include[ \t]+\"
+include_dir_open ^[ \t]*@include_dir[ \t]+\"
-%x COMMENT STRING INCLUDE
+%x COMMENT STRING INCLUDE_F INCLUDE_D
%%
return(TOK_STRING);
}
-{include_open} { BEGIN INCLUDE; }
-<INCLUDE>[^\"\\]+ { scanctx_append_string(yyextra, yytext); }
-<INCLUDE>\\\\ { scanctx_append_string(yyextra, "\\"); }
-<INCLUDE>\\\" { scanctx_append_string(yyextra, "\""); }
-<INCLUDE>\" {
- const char *error;
- FILE *fp = scanctx_push_include(yyextra,
- (void *)YY_CURRENT_BUFFER,
- &error);
- if(fp)
- {
- yyin = fp;
- yy_switch_to_buffer(
- yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner),
- yyscanner);
- }
- else
- {
- yyextra->config->error_text = error;
- yyextra->config->error_file = scanctx_current_filename(
- yyextra);
- yyextra->config->error_line = libconfig_yyget_lineno(
- yyscanner);
- return TOK_ERROR;
- }
- BEGIN INITIAL;
- }
+{include_file_open} { BEGIN INCLUDE_F; }
+<INCLUDE_F>[^\"\\]+ { scanctx_append_string(yyextra, yytext); }
+<INCLUDE_F>\\\\ { scanctx_append_string(yyextra, "\\"); }
+<INCLUDE_F>\\\" { scanctx_append_string(yyextra, "\""); }
+<INCLUDE_F>\" {
+ const char *error;
+ FILE *fp = scanctx_push_include(yyextra,
+ (void *)YY_CURRENT_BUFFER,
+ scanctx_getpath(yyextra),
+ &error);
+ if(fp)
+ {
+ yyin = fp;
+ yy_switch_to_buffer(
+ yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner),
+ yyscanner
+ );
+ }
+ else
+ {
+ yyextra->config->error_text = error;
+ yyextra->config->error_file = scanctx_current_filename(
+ yyextra);
+ yyextra->config->error_line = libconfig_yyget_lineno(
+ yyscanner);
+ return TOK_ERROR;
+ }
+ BEGIN INITIAL;
+ }
+
+{include_dir_open} { BEGIN INCLUDE_D; }
+<INCLUDE_D>[^\"\\]+ { scanctx_append_string(yyextra, yytext); }
+<INCLUDE_D>\\\\ { scanctx_append_string(yyextra, "\\"); }
+<INCLUDE_D>\\\" { scanctx_append_string(yyextra, "\""); }
+<INCLUDE_D>\" {
+ const char *error;
+ const char* basedir;
+ FILE *fp = NULL;
+
+ basedir = scanctx_getpath(yyextra);
+ if( scanctx_dirscan(yyextra, basedir, filter_dotfiles, alphasort) < 0 )
+ {
+ if(basedir)
+ free((void*)basedir);
+ return TOK_ERROR;
+ }
+
+ if( scanctx_inloop(yyextra) )
+ {
+ fp = scanctx_push_include(yyextra,
+ (void *)YY_CURRENT_BUFFER,
+ scanctx_filename(yyextra, NULL, scanctx_dirnext(yyextra)),
+ &error);
+
+ if(fp)
+ {
+ yyin = fp;
+ yy_switch_to_buffer(
+ yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner),
+ yyscanner
+ );
+ }
+ else
+ {
+ yyextra->config->error_text = error;
+ yyextra->config->error_file = scanctx_current_filename(
+ yyextra);
+ yyextra->config->error_line = libconfig_yyget_lineno(
+ yyscanner);
+ }
+ }
+ else
+ scanctx_dirend(yyextra); /* avoid leaks */
+
+ BEGIN INITIAL;
+ }
+
\n|\r|\f { /* ignore */ }
[ \t]+ { /* ignore */ }
. { return(TOK_GARBAGE); }
<<EOF>> {
- YY_BUFFER_STATE buf = (YY_BUFFER_STATE)scanctx_pop_include(
- yyextra);
- if(buf)
- {
- yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner);
- yy_switch_to_buffer(buf, yyscanner);
- }
- else
- yyterminate();
- }
+ const char* error;
+ FILE* fp;
+ YY_BUFFER_STATE buf = (YY_BUFFER_STATE)scanctx_pop_include(yyextra);
+ if(buf)
+ {
+ yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner);
+ yy_switch_to_buffer(buf, yyscanner);
+ }
+ else /* if no more buffers, we are done */
+ yyterminate();
+
+ if( scanctx_inloop(yyextra) )
+ {
+ /* gotta keep looping.... */
+ fp = scanctx_push_include(yyextra,
+ (void *)YY_CURRENT_BUFFER,
+ scanctx_filename(yyextra, NULL, scanctx_dirnext(yyextra)),
+ &error);
+ if(fp)
+ {
+ yyin = fp;
+ yy_switch_to_buffer(
+ yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner),
+ yyscanner
+ );
+ }
+ else
+ {
+ yyextra->config->error_text = error;
+ yyextra->config->error_file = scanctx_current_filename(yyextra);
+ yyextra->config->error_line = libconfig_yyget_lineno(yyscanner);
+ }
+ }
+ else /* not on loop, or just finished */
+ scanctx_dirend(yyextra);
+ }