Previously, wordexp() was used. However for providing Windows builds of mconf-idf we can't use wordexp() so we use this simplified environment variable expansion code instead. The reasoning here is to make the behaviour consistent across Windows (CMake vs GNU Make), Linux & macOS mconf.
404 lines
7.6 KiB
Text
404 lines
7.6 KiB
Text
%option nostdinit noyywrap never-interactive full ecs
|
|
%option 8bit perf-report perf-report
|
|
%option noinput
|
|
%x COMMAND HELP STRING PARAM
|
|
%{
|
|
/*
|
|
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
|
* Released under the terms of the GNU GPL v2.0.
|
|
*/
|
|
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "lkc.h"
|
|
#include "expand_env.h"
|
|
|
|
#define START_STRSIZE 16
|
|
|
|
static struct {
|
|
struct file *file;
|
|
int lineno;
|
|
} current_pos;
|
|
|
|
static char *text;
|
|
static int text_size, text_asize;
|
|
|
|
struct buffer {
|
|
struct buffer *parent;
|
|
YY_BUFFER_STATE state;
|
|
};
|
|
|
|
struct buffer *current_buf;
|
|
|
|
static int last_ts, first_ts;
|
|
|
|
static void zconf_endhelp(void);
|
|
static void zconf_endfile(void);
|
|
|
|
static void new_string(void)
|
|
{
|
|
text = xmalloc(START_STRSIZE);
|
|
text_asize = START_STRSIZE;
|
|
text_size = 0;
|
|
*text = 0;
|
|
}
|
|
|
|
static void append_string(const char *str, int size)
|
|
{
|
|
int new_size = text_size + size + 1;
|
|
if (new_size > text_asize) {
|
|
new_size += START_STRSIZE - 1;
|
|
new_size &= -START_STRSIZE;
|
|
text = realloc(text, new_size);
|
|
text_asize = new_size;
|
|
}
|
|
memcpy(text + text_size, str, size);
|
|
text_size += size;
|
|
text[text_size] = 0;
|
|
}
|
|
|
|
static void alloc_string(const char *str, int size)
|
|
{
|
|
text = xmalloc(size + 1);
|
|
memcpy(text, str, size);
|
|
text[size] = 0;
|
|
}
|
|
|
|
static void warn_ignored_character(char chr)
|
|
{
|
|
fprintf(stderr,
|
|
"%s:%d:warning: ignoring unsupported character '%c'\n",
|
|
zconf_curname(), zconf_lineno(), chr);
|
|
}
|
|
%}
|
|
|
|
n [A-Za-z0-9_-]
|
|
|
|
%%
|
|
int str = 0;
|
|
int ts, i;
|
|
|
|
[ \t]*#.*\n |
|
|
[ \t]*\n {
|
|
current_file->lineno++;
|
|
return T_EOL;
|
|
}
|
|
[ \t]*#.*
|
|
|
|
|
|
[ \t]+ {
|
|
BEGIN(COMMAND);
|
|
}
|
|
|
|
. {
|
|
unput(yytext[0]);
|
|
BEGIN(COMMAND);
|
|
}
|
|
|
|
|
|
<COMMAND>{
|
|
{n}+ {
|
|
const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
|
|
BEGIN(PARAM);
|
|
current_pos.file = current_file;
|
|
current_pos.lineno = current_file->lineno;
|
|
if (id && id->flags & TF_COMMAND) {
|
|
zconflval.id = id;
|
|
return id->token;
|
|
}
|
|
alloc_string(yytext, yyleng);
|
|
zconflval.string = text;
|
|
return T_WORD;
|
|
}
|
|
[^\r\n] warn_ignored_character(*yytext);
|
|
\r?\n {
|
|
BEGIN(INITIAL);
|
|
current_file->lineno++;
|
|
return T_EOL;
|
|
}
|
|
}
|
|
|
|
<PARAM>{
|
|
"&&" return T_AND;
|
|
"||" return T_OR;
|
|
"(" return T_OPEN_PAREN;
|
|
")" return T_CLOSE_PAREN;
|
|
"!" return T_NOT;
|
|
"=" return T_EQUAL;
|
|
"!=" return T_UNEQUAL;
|
|
"<=" return T_LESS_EQUAL;
|
|
">=" return T_GREATER_EQUAL;
|
|
"<" return T_LESS;
|
|
">" return T_GREATER;
|
|
\"|\' {
|
|
str = yytext[0];
|
|
new_string();
|
|
BEGIN(STRING);
|
|
}
|
|
\r?\n BEGIN(INITIAL); current_file->lineno++; return T_EOL;
|
|
({n}|[/.])+ {
|
|
const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
|
|
if (id && id->flags & TF_PARAM) {
|
|
zconflval.id = id;
|
|
return id->token;
|
|
}
|
|
alloc_string(yytext, yyleng);
|
|
zconflval.string = text;
|
|
return T_WORD;
|
|
}
|
|
#.* /* comment */
|
|
\\\r?\n current_file->lineno++;
|
|
[[:blank:]]+
|
|
. warn_ignored_character(*yytext);
|
|
<<EOF>> {
|
|
BEGIN(INITIAL);
|
|
}
|
|
}
|
|
|
|
<STRING>{
|
|
[^'"\\\n]+/\n {
|
|
append_string(yytext, yyleng);
|
|
zconflval.string = text;
|
|
return T_WORD_QUOTE;
|
|
}
|
|
[^'"\\\n]+ {
|
|
append_string(yytext, yyleng);
|
|
}
|
|
\\.?/\n {
|
|
append_string(yytext + 1, yyleng - 1);
|
|
zconflval.string = text;
|
|
return T_WORD_QUOTE;
|
|
}
|
|
\\.? {
|
|
append_string(yytext + 1, yyleng - 1);
|
|
}
|
|
\'|\" {
|
|
if (str == yytext[0]) {
|
|
BEGIN(PARAM);
|
|
zconflval.string = text;
|
|
return T_WORD_QUOTE;
|
|
} else
|
|
append_string(yytext, 1);
|
|
}
|
|
\r?\n {
|
|
printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
|
|
current_file->lineno++;
|
|
BEGIN(INITIAL);
|
|
return T_EOL;
|
|
}
|
|
<<EOF>> {
|
|
BEGIN(INITIAL);
|
|
}
|
|
}
|
|
|
|
<HELP>{
|
|
[ \t]+ {
|
|
ts = 0;
|
|
for (i = 0; i < yyleng; i++) {
|
|
if (yytext[i] == '\t')
|
|
ts = (ts & ~7) + 8;
|
|
else
|
|
ts++;
|
|
}
|
|
last_ts = ts;
|
|
if (first_ts) {
|
|
if (ts < first_ts) {
|
|
zconf_endhelp();
|
|
return T_HELPTEXT;
|
|
}
|
|
ts -= first_ts;
|
|
while (ts > 8) {
|
|
append_string(" ", 8);
|
|
ts -= 8;
|
|
}
|
|
append_string(" ", ts);
|
|
}
|
|
}
|
|
[ \t]*\r?\n/[^ \t\r\n] {
|
|
current_file->lineno++;
|
|
zconf_endhelp();
|
|
return T_HELPTEXT;
|
|
}
|
|
[ \t]*\r?\n {
|
|
current_file->lineno++;
|
|
append_string("\n", 1);
|
|
}
|
|
[^ \t\r?\n].* {
|
|
while (yyleng) {
|
|
if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
|
|
break;
|
|
yyleng--;
|
|
}
|
|
append_string(yytext, yyleng);
|
|
if (!first_ts)
|
|
first_ts = last_ts;
|
|
}
|
|
<<EOF>> {
|
|
zconf_endhelp();
|
|
return T_HELPTEXT;
|
|
}
|
|
}
|
|
|
|
<<EOF>> {
|
|
if (current_file) {
|
|
zconf_endfile();
|
|
return T_EOL;
|
|
}
|
|
fclose(yyin);
|
|
yyterminate();
|
|
}
|
|
|
|
%%
|
|
void zconf_starthelp(void)
|
|
{
|
|
new_string();
|
|
last_ts = first_ts = 0;
|
|
BEGIN(HELP);
|
|
}
|
|
|
|
static void zconf_endhelp(void)
|
|
{
|
|
zconflval.string = text;
|
|
BEGIN(INITIAL);
|
|
}
|
|
|
|
|
|
/*
|
|
* Try to open specified file with following names:
|
|
* ./name
|
|
* $(srctree)/name
|
|
* The latter is used when srctree is separate from objtree
|
|
* when compiling the kernel.
|
|
* Return NULL if file is not found.
|
|
*/
|
|
FILE *zconf_fopen(const char *name)
|
|
{
|
|
char *env, fullname[PATH_MAX+1];
|
|
FILE *f;
|
|
|
|
f = fopen(name, "r");
|
|
if (!f && name != NULL && name[0] != '/') {
|
|
env = getenv(SRCTREE);
|
|
if (env) {
|
|
sprintf(fullname, "%s/%s", env, name);
|
|
f = fopen(fullname, "r");
|
|
}
|
|
}
|
|
return f;
|
|
}
|
|
|
|
void zconf_initscan(const char *name)
|
|
{
|
|
yyin = zconf_fopen(name);
|
|
if (!yyin) {
|
|
printf("can't find file %s\n", name);
|
|
exit(1);
|
|
}
|
|
|
|
current_buf = xmalloc(sizeof(*current_buf));
|
|
memset(current_buf, 0, sizeof(*current_buf));
|
|
|
|
current_file = file_lookup(name);
|
|
current_file->lineno = 1;
|
|
}
|
|
|
|
void zconf_nextfile(const char *name)
|
|
{
|
|
struct file *iter;
|
|
struct file *file = file_lookup(name);
|
|
struct buffer *buf = xmalloc(sizeof(*buf));
|
|
memset(buf, 0, sizeof(*buf));
|
|
|
|
current_buf->state = YY_CURRENT_BUFFER;
|
|
yyin = zconf_fopen(file->name);
|
|
if (!yyin) {
|
|
printf("%s:%d: can't open file \"%s\"\n",
|
|
zconf_curname(), zconf_lineno(), file->name);
|
|
exit(1);
|
|
}
|
|
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
|
|
buf->parent = current_buf;
|
|
current_buf = buf;
|
|
|
|
for (iter = current_file->parent; iter; iter = iter->parent ) {
|
|
if (!strcmp(current_file->name,iter->name) ) {
|
|
printf("%s:%d: recursive inclusion detected. "
|
|
"Inclusion path:\n current file : '%s'\n",
|
|
zconf_curname(), zconf_lineno(),
|
|
zconf_curname());
|
|
iter = current_file->parent;
|
|
while (iter && \
|
|
strcmp(iter->name,current_file->name)) {
|
|
printf(" included from: '%s:%d'\n",
|
|
iter->name, iter->lineno-1);
|
|
iter = iter->parent;
|
|
}
|
|
if (iter)
|
|
printf(" included from: '%s:%d'\n",
|
|
iter->name, iter->lineno+1);
|
|
exit(1);
|
|
}
|
|
}
|
|
file->lineno = 1;
|
|
file->parent = current_file;
|
|
current_file = file;
|
|
}
|
|
|
|
void zconf_nextfiles(const char *expression)
|
|
{
|
|
/* Expand environment variables in 'expression' */
|
|
char* str = expand_environment(expression, zconf_curname(), zconf_lineno());
|
|
|
|
/* zconf_nextfile() processes files in LIFO order, so to keep the
|
|
files in the order provided we need to process the list backwards
|
|
*/
|
|
if (str != NULL && strlen(str)) {
|
|
char* pos = str + strlen(str); // start at null terminator
|
|
|
|
while (pos != str) {
|
|
pos--;
|
|
if(*pos == ' ') {
|
|
*pos = '\0'; // split buffer into multiple c-strings
|
|
if (strlen(pos + 1)) {
|
|
zconf_nextfile(pos + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (strlen(str)) { // re-check as first character may have been a space
|
|
zconf_nextfile(str);
|
|
}
|
|
}
|
|
|
|
free_expanded(str);
|
|
}
|
|
|
|
static void zconf_endfile(void)
|
|
{
|
|
struct buffer *parent;
|
|
|
|
current_file = current_file->parent;
|
|
|
|
parent = current_buf->parent;
|
|
if (parent) {
|
|
fclose(yyin);
|
|
yy_delete_buffer(YY_CURRENT_BUFFER);
|
|
yy_switch_to_buffer(parent->state);
|
|
}
|
|
free(current_buf);
|
|
current_buf = parent;
|
|
}
|
|
|
|
int zconf_lineno(void)
|
|
{
|
|
return current_pos.lineno;
|
|
}
|
|
|
|
const char *zconf_curname(void)
|
|
{
|
|
return current_pos.file ? current_pos.file->name : "<none>";
|
|
}
|