include "osfiles.s7i";
include "chartype.s7i";
include "scanfile.s7i";
include "scanstri.s7i";
include "cli_cmds.s7i";
const set of char: target_name_char is {'!' .. '~'} - {':', '='};
const set of char: macro_name_char is {'!' .. '~'} - {')', ':', '='};
const type: ruleType is new struct
var string: target is "";
var array string: dependencies is 0 times "";
var array string: commands is 0 times "";
var boolean: ruleProcessed is FALSE;
end struct;
const type: ruleHash is hash [string] ruleType;
const type: ruleArray is array ruleType;
const type: ruleArrayHash is hash [string] ruleArray;
const type: stringHash is hash [string] string;
const type: makeDataType is new struct
var file: makefile is STD_NULL;
var ruleHash: rules is ruleHash.value;
var ruleArrayHash: patternRules is ruleArrayHash.value;
var stringHash: macros is stringHash.value;
var string: targetOfFirstRule is "";
var boolean: executeCommands is TRUE;
var boolean: inSilentMode is FALSE;
var boolean: doIgnoreErrors is FALSE;
end struct;
const func boolean: patternMatches (in string: stri, in string: pattern) is func
result
var boolean: doesMatch is FALSE;
local
var integer: patternPercentPos is 0;
begin
patternPercentPos := pos(pattern, '%');
if patternPercentPos <> 0 then
doesMatch := startsWith(stri, pattern[.. pred(patternPercentPos)]) and
endsWith(stri, pattern[succ(patternPercentPos) ..]);
else
doesMatch := stri = pattern;
end if;
end func;
const func boolean: patternMatches (in string: stri, in array string: patternList) is func
result
var boolean: doesMatch is FALSE;
local
var string: pattern is "";
begin
for pattern range patternList until doesMatch do
doesMatch := patternMatches(stri, pattern);
end for;
end func;
const func string: patternSubstitute (in var string: stri, in string: pattern, in string: replacement) is func
result
var string: replaced is ""
local
var string: symbol is "";
var integer: patternPercentPos is 0;
var integer: replacementPercentPos is 0;
begin
patternPercentPos := pos(pattern, '%');
replacementPercentPos := pos(replacement, '%');
if patternPercentPos <> 0 and replacementPercentPos <> 0 then
repeat
replaced &:= getWhiteSpace(stri);
symbol := getWord(stri);
if symbol <> "" then
if startsWith(symbol, pattern[.. pred(patternPercentPos)]) and
endsWith(symbol, pattern[succ(patternPercentPos) ..]) then
symbol := replacement[.. pred(replacementPercentPos)] &
symbol[patternPercentPos .. length(symbol) - length(pattern) + patternPercentPos] &
replacement[succ(replacementPercentPos) ..];
end if;
replaced &:= symbol;
end if;
until symbol = "";
end if;
end func;
const func string: replaceSuffixes (in var string: stri, in string: suffix, in string: replacement) is func
result
var string: replaced is ""
local
var string: symbol is "";
begin
if pos(suffix, '%') <> 0 and pos(replacement, '%') <> 0 then
replaced := patternSubstitute(stri, suffix, replacement);
else
repeat
replaced &:= getWhiteSpace(stri);
symbol := getWord(stri);
if symbol <> "" then
if endsWith(symbol, suffix) then
symbol := symbol[.. length(symbol) - length(suffix)] & replacement;
end if;
replaced &:= symbol;
end if;
until symbol = "";
end if;
end func;
const func string: getMacroName (inout string: stri) is func
result
var string: symbol is "";
local
var integer: pos is 1;
begin
while pos <= length(stri) and stri[pos] in macro_name_char do
incr(pos);
end while;
symbol := stri[.. pred(pos)];
stri := stri[pos ..];
end func;
const func string: getMacroParameter (in string: stri, inout integer: pos,
in char: delimiter) is func
result
var string: parameter is "";
begin
while pos <= length(stri) and stri[pos] <> delimiter do
if stri[pos] = '(' then
incr(pos);
parameter &:= "(";
parameter &:= getMacroParameter(stri, pos, ')');
parameter &:= ")";
elsif stri[pos] = '{' then
incr(pos);
parameter &:= "{";
parameter &:= getMacroParameter(stri, pos, '}');
parameter &:= "}";
else
parameter &:= stri[pos];
end if;
incr(pos);
end while;
end func;
const func string: applyMacros (in stringHash: macros, in string: stri,
in boolean: leaveUndefMacros) is forward;
const func string: replaceSuffixes (in stringHash: macros, in string: stri,
in string: parameters, in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var integer: pos is 1;
var string: suffix is "";
var string: replacement is "";
var string: evaluatedParam is "";
begin
suffix := getMacroParameter(parameters, pos, '=');
if pos <= length(parameters) then
incr(pos);
replacement := parameters[pos ..];
evaluatedParam := applyMacros(macros, stri, leaveUndefMacros);
funcResult := replaceSuffixes(evaluatedParam, suffix, replacement);
end if;
end func;
const func string: strip (in stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var integer: pos is 1;
var string: evaluatedParam is "";
begin
evaluatedParam := applyMacros(macros, parameters, leaveUndefMacros);
funcResult := replace(evaluatedParam, "\t", " ");
funcResult := replaceN(funcResult, " ", " ");
funcResult := trim(funcResult);
end func;
const func string: subst (in stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var integer: pos is 1;
var string: from is "";
var string: replacement is "";
var string: evaluatedParam is "";
begin
from := getMacroParameter(parameters, pos, ',');
from := applyMacros(macros, from, leaveUndefMacros);
if pos <= length(parameters) then
incr(pos);
replacement := getMacroParameter(parameters, pos, ',');
replacement := applyMacros(macros, replacement, leaveUndefMacros);
if pos <= length(parameters) then
incr(pos);
evaluatedParam := applyMacros(macros, parameters[pos ..], leaveUndefMacros);
funcResult := replace(evaluatedParam, from, replacement);
end if;
end if;
end func;
const func string: patsubst (in stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var integer: pos is 1;
var string: pattern is "";
var string: replacement is "";
var string: evaluatedParam is "";
begin
pattern := getMacroParameter(parameters, pos, ',');
pattern := applyMacros(macros, pattern, leaveUndefMacros);
if pos <= length(parameters) then
incr(pos);
replacement := getMacroParameter(parameters, pos, ',');
replacement := applyMacros(macros, replacement, leaveUndefMacros);
if pos <= length(parameters) then
incr(pos);
evaluatedParam := applyMacros(macros, parameters[pos ..], leaveUndefMacros);
funcResult := patternSubstitute(evaluatedParam, pattern, replacement);
end if;
end if;
end func;
const func string: dir (in stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var string: names is "";
var string: name is "";
var integer: slashOrbackslashPos is 0;
var integer: periodPos is 0;
begin
names := applyMacros(macros, parameters, leaveUndefMacros);
repeat
skipWhiteSpace(names);
name := getWord(names);
if name <> "" then
if funcResult <> "" then
funcResult &:= " ";
end if;
slashOrbackslashPos := max(rpos(name, '/'), rpos(name, '\\'));
if slashOrbackslashPos <> 0 then
funcResult &:= name[.. slashOrbackslashPos];
else
funcResult &:= "./";
end if;
end if;
until name = "";
end func;
const func string: notdir (in stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var string: names is "";
var string: name is "";
var integer: slashOrbackslashPos is 0;
var integer: periodPos is 0;
begin
names := applyMacros(macros, parameters, leaveUndefMacros);
repeat
skipWhiteSpace(names);
name := getWord(names);
if name <> "" then
if funcResult <> "" then
funcResult &:= " ";
end if;
slashOrbackslashPos := max(rpos(name, '/'), rpos(name, '\\'));
if slashOrbackslashPos <> 0 then
funcResult &:= name[succ(slashOrbackslashPos) ..];
else
funcResult &:= name;
end if;
end if;
until name = "";
end func;
const func string: suffix (in stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var string: names is "";
var string: name is "";
var integer: slashOrbackslashPos is 0;
var integer: periodPos is 0;
begin
names := applyMacros(macros, parameters, leaveUndefMacros);
repeat
skipWhiteSpace(names);
name := getWord(names);
if name <> "" then
periodPos := rpos(name, '.');
if periodPos <> 0 then
slashOrbackslashPos := max(rpos(name, '/'), rpos(name, '\\'));
if slashOrbackslashPos < periodPos then
if funcResult <> "" then
funcResult &:= " ";
end if;
funcResult &:= name[periodPos ..];
end if;
end if;
end if;
until name = "";
end func;
const func string: basename (in stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var string: names is "";
var string: name is "";
var integer: slashOrbackslashPos is 0;
var integer: periodPos is 0;
begin
names := applyMacros(macros, parameters, leaveUndefMacros);
repeat
skipWhiteSpace(names);
name := getWord(names);
if name <> "" then
if funcResult <> "" then
funcResult &:= " ";
end if;
periodPos := rpos(name, '.');
if periodPos = 0 then
funcResult &:= name;
else
slashOrbackslashPos := max(rpos(name, '/'), rpos(name, '\\'));
if slashOrbackslashPos < periodPos then
funcResult &:= name[.. pred(periodPos)];
else
funcResult &:= name;
end if;
end if;
end if;
until name = "";
end func;
const func string: addprefix (in stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var integer: pos is 1;
var string: prefix is "";
var string: names is "";
var string: name is "";
begin
prefix := getMacroParameter(parameters, pos, ',');
prefix := applyMacros(macros, prefix, leaveUndefMacros);
if pos <= length(parameters) then
incr(pos);
names := applyMacros(macros, parameters[pos ..], leaveUndefMacros);
repeat
skipWhiteSpace(names);
name := getWord(names);
if name <> "" then
if funcResult <> "" then
funcResult &:= " ";
end if;
funcResult &:= prefix;
funcResult &:= name;
end if;
until name = "";
end if;
end func;
const func string: addsuffix (in stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var integer: pos is 1;
var string: suffix is "";
var string: names is "";
var string: name is "";
begin
suffix := getMacroParameter(parameters, pos, ',');
suffix := applyMacros(macros, suffix, leaveUndefMacros);
if pos <= length(parameters) then
incr(pos);
names := applyMacros(macros, parameters[pos ..], leaveUndefMacros);
repeat
skipWhiteSpace(names);
name := getWord(names);
if name <> "" then
if funcResult <> "" then
funcResult &:= " ";
end if;
funcResult &:= name;
funcResult &:= suffix;
end if;
until name = "";
end if;
end func;
const func string: filter (in stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var integer: pos is 1;
var string: patterns is "";
var string: pattern is "";
var string: names is "";
var string: name is "";
var array string: patternList is 0 times "";
begin
patterns := getMacroParameter(parameters, pos, ',');
patterns := applyMacros(macros, patterns, leaveUndefMacros);
if pos <= length(parameters) then
incr(pos);
names := applyMacros(macros, parameters[pos ..], leaveUndefMacros);
repeat
skipWhiteSpace(patterns);
pattern := getWord(patterns);
patternList &:= pattern;
until pattern = "";
repeat
skipWhiteSpace(names);
name := getWord(names);
if name <> "" and patternMatches(name, patternList) then
if funcResult <> "" then
funcResult &:= " ";
end if;
funcResult &:= name;
end if;
until name = "";
end if;
end func;
const func string: filterOut (in stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var integer: pos is 1;
var string: patterns is "";
var string: pattern is "";
var string: names is "";
var string: name is "";
var array string: patternList is 0 times "";
begin
patterns := getMacroParameter(parameters, pos, ',');
patterns := applyMacros(macros, patterns, leaveUndefMacros);
if pos <= length(parameters) then
incr(pos);
names := applyMacros(macros, parameters[pos ..], leaveUndefMacros);
repeat
skipWhiteSpace(patterns);
pattern := getWord(patterns);
patternList &:= pattern;
until pattern = "";
repeat
skipWhiteSpace(names);
name := getWord(names);
if name <> "" and not patternMatches(name, patternList) then
if funcResult <> "" then
funcResult &:= " ";
end if;
funcResult &:= name;
end if;
until name = "";
end if;
end func;
const func string: foreach (in var stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var integer: pos is 1;
var string: variable is "";
var string: wordList is "";
var string: bodyText is "";
var string: symbol is "";
var string: evaluatedBody is "";
begin
variable := getMacroParameter(parameters, pos, ',');
variable := applyMacros(macros, variable, leaveUndefMacros);
if pos <= length(parameters) then
incr(pos);
wordList := getMacroParameter(parameters, pos, ',');
wordList := applyMacros(macros, wordList, leaveUndefMacros);
if pos <= length(parameters) then
incr(pos);
bodyText := parameters[pos ..];
repeat
skipWhiteSpace(wordList);
symbol := getWord(wordList);
if symbol <> "" then
if funcResult <> "" then
funcResult &:= " ";
end if;
macros @:= [variable] symbol;
evaluatedBody := applyMacros(macros, bodyText, leaveUndefMacros);
funcResult &:= evaluatedBody;
end if;
until symbol = "";
end if;
end if;
end func;
const func string: call (in var stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var integer: pos is 1;
var string: variable is "";
var string: variableValue is "";
var integer: paramNumber is 1;
var string: paramValue is "";
begin
variable := getMacroParameter(parameters, pos, ',');
if variable in macros then
variableValue := macros[variable];
while pos <= length(parameters) do
incr(pos);
paramValue := getMacroParameter(parameters, pos, ',');
macros @:= [str(paramNumber)] paramValue;
incr(paramNumber);
end while;
funcResult := applyMacros(macros, variableValue, leaveUndefMacros);
end if;
end func;
const func string: sort (in stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var string: wordList is "";
var string: name is "";
var string: lastName is "";
var array string: wordArray is 0 times "";
begin
wordList := applyMacros(macros, parameters, leaveUndefMacros);
repeat
skipWhiteSpace(wordList);
name := getWord(wordList);
if name <> "" then
wordArray &:= name;
end if;
until name = "";
wordArray := sort(wordArray);
for name range wordArray do
if name <> lastName then
if funcResult <> "" then
funcResult &:= " ";
end if;
funcResult &:= name;
end if;
lastName := name;
end for;
end func;
const func string: shell (in stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var string: evaluatedParam is "";
begin
evaluatedParam := applyMacros(macros, parameters, leaveUndefMacros);
funcResult := execCommand(evaluatedParam);
end func;
const func string: wildcard (in stringHash: macros, in string: parameters,
in boolean: leaveUndefMacros) is func
result
var string: funcResult is "";
local
var string: evaluatedParam is "";
var array string: matches is 0 times "";
begin
evaluatedParam := applyMacros(macros, parameters, leaveUndefMacros);
matches := findMatchingFiles(evaluatedParam, TRUE);
if length(matches) <> 0 then
funcResult := join(matches, ' ');
end if;
end func;
const func string: applyMacros (in stringHash: macros, in string: stri,
in boolean: leaveUndefMacros) is func
result
var string: applied is "";
local
var integer: dollarPos is 0;
var integer: closeParenPos is 0;
var string: parameter is "";
var string: name is "";
var string: macroValue is "";
var boolean: done is FALSE;
begin
applied := stri;
dollarPos := pos(applied, '$');
while dollarPos <> 0 do
if applied[succ(dollarPos)] in {'(', '{'} then
closeParenPos := dollarPos + 2;
if applied[succ(dollarPos)] = '(' then
parameter := getMacroParameter(applied, closeParenPos, ')');
else
parameter := getMacroParameter(applied, closeParenPos, '}');
end if;
if closeParenPos <= length(applied) then
name := getMacroName(parameter);
done := FALSE;
if parameter = "" then
if name in macros then
macroValue := applyMacros(macros, macros[name], leaveUndefMacros);
done := TRUE;
else
macroValue := getenv(name);
done := macroValue <> "";
end if;
elsif parameter[1] = ':' then
if name in macros then
macroValue := replaceSuffixes(macros, macros[name],
parameter[2 ..], leaveUndefMacros);
done := TRUE;
end if;
elsif parameter[1] = ' ' then
skipSpaceOrTab(parameter);
if name = "strip" then
macroValue := strip(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "subst" then
macroValue := subst(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "patsubst" then
macroValue := patsubst(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "dir" then
macroValue := dir(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "notdir" then
macroValue := notdir(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "suffix" then
macroValue := suffix(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "basename" then
macroValue := basename(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "addprefix" then
macroValue := addprefix(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "addsuffix" then
macroValue := addsuffix(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "filter" then
macroValue := filter(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "filter-out" then
macroValue := filterOut(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "foreach" then
macroValue := foreach(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "call" then
macroValue := call(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "sort" then
macroValue := sort(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "shell" then
macroValue := shell(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "wildcard" then
macroValue := wildcard(macros, parameter, leaveUndefMacros);
done := TRUE;
elsif name = "error" then
writeln(" *** Error: " <& applyMacros(macros, parameter, FALSE));
raise FILE_ERROR;
elsif name = "warning" then
writeln(applyMacros(macros, parameter, FALSE));
macroValue := "";
done := TRUE;
else
writeln(" *** Unknown function " <& literal(name) <& ", ignored.");
end if;
end if;
if done then
applied := applied[.. pred(dollarPos)] &
macroValue &
applied[succ(closeParenPos) ..];
elsif leaveUndefMacros then
incr(dollarPos);
else
applied := applied[.. pred(dollarPos)] &
applied[succ(closeParenPos) ..];
end if;
else
incr(dollarPos);
end if;
elsif applied[succ(dollarPos)] = '$' then
dollarPos +:= 2;
else
incr(dollarPos);
end if;
dollarPos := pos(applied, '$', dollarPos);
end while;
end func;
const func string: getMacroParameter (inout file: makefile, in char: delimiter) is func
result
var string: parameter is "";
begin
while makefile.bufferChar <> delimiter and makefile.bufferChar <> EOF do
if makefile.bufferChar = '(' then
parameter &:= "(";
makefile.bufferChar := getc(makefile);
parameter &:= getMacroParameter(makefile, ')');
parameter &:= ")";
elsif makefile.bufferChar = '{' then
parameter &:= "{";
makefile.bufferChar := getc(makefile);
parameter &:= getMacroParameter(makefile, '}');
parameter &:= "}";
else
parameter &:= makefile.bufferChar;
end if;
makefile.bufferChar := getc(makefile);
end while;
end func;
const func string: getMakeLine (inout file: makefile) is func
result
var string: data is "";
begin
data := "";
while makefile.bufferChar <> '\n' and makefile.bufferChar <> EOF do
if makefile.bufferChar = '\r' then
makefile.bufferChar := getc(makefile);
if makefile.bufferChar <> '\n' then
data &:= '\r';
end if;
elsif makefile.bufferChar = '\\' then
makefile.bufferChar := getc(makefile);
if makefile.bufferChar = '\r' then
makefile.bufferChar := getc(makefile);
if makefile.bufferChar = '\n' then
makefile.bufferChar := getc(makefile);
skipSpaceOrTab(makefile);
if data <> "" and data[length(data)] not in space_or_tab then
data &:= ' ';
end if;
else
data &:= "\\\r";
end if;
elsif makefile.bufferChar = '\n' then
makefile.bufferChar := getc(makefile);
skipSpaceOrTab(makefile);
if data <> "" and data[length(data)] not in space_or_tab then
data &:= ' ';
end if;
else
data &:= '\\';
end if;
else
data &:= makefile.bufferChar;
makefile.bufferChar := getc(makefile);
end if;
end while;
end func;
const func string: getMakeTarget (inout file: makefile) is func
result
var string: symbol is "";
begin
symbol := str(makefile.bufferChar);
makefile.bufferChar := getc(makefile);
while makefile.bufferChar in target_name_char do
symbol &:= makefile.bufferChar;
makefile.bufferChar := getc(makefile);
end while;
end func;
const proc: find_endif_directive (inout file: makefile) is func
local
var string: command is "";
begin
repeat
if makefile.bufferChar = '!' then
makefile.bufferChar := getc(makefile);
command := lower(getWord(makefile));
skipLine(makefile);
makefile.bufferChar := getc(makefile);
if command = "if" then
find_endif_directive(makefile);
end if;
else
skipLine(makefile);
makefile.bufferChar := getc(makefile);
end if;
until command = "endif";
end func;
const proc: find_endif_or_else_directive (inout file: makefile) is func
local
var string: command is "";
begin
repeat
if makefile.bufferChar = '!' then
makefile.bufferChar := getc(makefile);
command := lower(getWord(makefile));
skipLine(makefile);
makefile.bufferChar := getc(makefile);
if command = "if" then
find_endif_directive(makefile);
end if;
else
skipLine(makefile);
makefile.bufferChar := getc(makefile);
end if;
until command = "endif" or command = "else";
end func;
const proc: execIf (inout file: makefile, in stringHash: macros) is func
local
var string: functionName is "";
var string: fileName is "";
var string: value2 is "";
var boolean: cond is FALSE;
var string: command is "";
begin
skipSpaceOrTab(makefile);
functionName := getName(makefile);
if functionName = "exist" and makefile.bufferChar = '(' then
makefile.bufferChar := getc(makefile);
fileName := getMacroParameter(makefile, ')');
skipLine(makefile);
makefile.bufferChar := getc(makefile);
if fileType(fileName) = FILE_ABSENT then
find_endif_or_else_directive(makefile);
end if;
end if;
end func;
const proc: find_endif (inout file: makefile) is func
local
var string: command is "";
begin
repeat
command := getMakeTarget(makefile);
skipLine(makefile);
makefile.bufferChar := getc(makefile);
if command = "ifeq" or command = "ifneq" then
find_endif(makefile);
end if;
until command = "endif";
end func;
const proc: find_endif_or_else (inout file: makefile) is func
local
var string: command is "";
begin
repeat
command := getMakeTarget(makefile);
skipLine(makefile);
makefile.bufferChar := getc(makefile);
if command = "ifeq" or command = "ifneq" then
find_endif(makefile);
end if;
until command = "endif" or command = "else";
end func;
const proc: execIfeq (inout file: makefile, in stringHash: macros, in boolean: equal) is func
local
var string: parameter is "";
var string: value1 is "";
var string: value2 is "";
begin
if makefile.bufferChar = '(' then
makefile.bufferChar := getc(makefile);
parameter := getMacroParameter(makefile, ',');
value1 := applyMacros(macros, parameter, TRUE);
skipSpaceOrTab(makefile);
if makefile.bufferChar = ',' then
makefile.bufferChar := getc(makefile);
parameter := getMacroParameter(makefile, ')');
value2 := applyMacros(macros, parameter, TRUE);
if makefile.bufferChar = ')' then
skipLine(makefile);
makefile.bufferChar := getc(makefile);
if (value1 = value2) <> equal then
find_endif_or_else(makefile);
end if;
end if;
end if;
end if;
end func;
const proc: execIfdef (inout file: makefile, in stringHash: macros, in boolean: equal) is func
local
var string: name is "";
begin
name := getMakeTarget(makefile);
skipLine(makefile);
makefile.bufferChar := getc(makefile);
if (name in macros or getenv(name) <> "") <> equal then
find_endif_or_else(makefile);
end if;
end func;
const func string: getMakeDependency (inout string: dependencies) is func
result
var string: symbol is "";
local
var integer: leng is 0;
var integer: start is 1;
var integer: pos is 1;
begin
leng := length(dependencies);
while start <= leng and dependencies[start] in white_space_char do
incr(start);
end while;
if start <= leng then
pos := start;
if dependencies[pos] = '"' then
repeat
incr(pos);
while pos <= leng and dependencies[pos] <> '"' do
symbol &:= dependencies[pos];
incr(pos);
end while;
if pos <= leng then
incr(pos);
if pos <= leng and dependencies[pos] = '"' then
symbol &:= '"';
end if;
else
writeln(" *** Quoted dependency " <& literal(symbol) <&
" does not end with \".");
end if;
until pos > leng or dependencies[pos] <> '"';
if pos <= leng and dependencies[pos] not in white_space_char then
writeln(" *** White space expected after quoted dependency " <&
literal(symbol) <& " found " <& literal(dependencies[pos]) <& ".");
end if;
else
repeat
if dependencies[pos] = '\\' and pos < leng and dependencies[succ(pos)] = ' ' then
incr(pos);
end if;
symbol &:= dependencies[pos];
incr(pos);
until pos > leng or dependencies[pos] in white_space_char;
end if;
dependencies := dependencies[pos ..];
else
dependencies := "";
end if;
end func;
const func ruleType: readRule (inout makeDataType: makeData, in string: target) is func
result
var ruleType: rule is ruleType.value;
local
var file: makefile is STD_NULL;
var string: dependencies is "";
var string: dependency is "";
var string: command is "";
begin
makefile := makeData.makefile;
rule.target := target;
skipSpaceOrTab(makefile);
dependencies := applyMacros(makeData.macros, getMakeLine(makefile), TRUE);
while dependencies <> "" do
dependency := getMakeDependency(dependencies);
rule.dependencies &:= dependency;
skipWhiteSpace(dependencies);
end while;
makefile.bufferChar := getc(makefile);
while makefile.bufferChar = '\t' or makefile.bufferChar = ' ' or
makefile.bufferChar = '\r' or makefile.bufferChar = '\n' or
makefile.bufferChar = '#' do
skipSpaceOrTab(makefile);
if makefile.bufferChar = '\r' then
makefile.bufferChar := getc(makefile);
end if;
if makefile.bufferChar = '#' then
skipLineComment(makefile);
elsif makefile.bufferChar <> '\n' then
command := getMakeLine(makefile);
rule.commands &:= command;
end if;
makefile.bufferChar := getc(makefile);
end while;
end func;
const func boolean: patternRulePresent (in makeDataType: makeData, in string: target,
in string: dependency) is func
result
var boolean: patternRulePresent is FALSE;
local
var integer: ruleArrayIndex is 0;
var string: ruleDependency is "";
begin
if target in makeData.patternRules then
for key ruleArrayIndex range makeData.patternRules[target]
until patternRulePresent do
for ruleDependency range makeData.patternRules[target][ruleArrayIndex].dependencies
until patternRulePresent do
patternRulePresent := ruleDependency = dependency;
end for;
end for;
end if;
end func;
const proc: addPatternRule (inout makeDataType: makeData, in ruleType: rule) is func
begin
if rule.target in makeData.patternRules then
makeData.patternRules[rule.target] &:= rule;
else
makeData.patternRules @:= [rule.target] [] (rule);
end if;
end func;
const proc: addRule (inout makeDataType: makeData, in ruleType: rule) is func
begin
if length(makeData.rules) = 0 then
makeData.targetOfFirstRule := rule.target;
end if;
if pos(rule.target, '%') <> 0 then
addPatternRule(makeData, rule);
elsif rule.target in makeData.rules then
if length(rule.commands) = 0 then
makeData.rules[rule.target].dependencies &:= rule.dependencies;
elsif length(makeData.rules[rule.target].commands) = 0 then
makeData.rules[rule.target].dependencies &:= rule.dependencies;
makeData.rules[rule.target].commands := rule.commands;
else
writeln(" *** Rule " <& rule.target <& " redefined.");
end if;
else
makeData.rules @:= [rule.target] rule;
end if;
end func;
const proc: includeMakefile (inout makeDataType: makeData, in boolean: ignoreError) is forward;
const proc: readMakefile (inout makeDataType: makeData) is func
local
var file: makefile is STD_NULL;
var string: name is "";
var array string: alternateTargets is 0 times "";
var string: data is "";
begin
makefile := makeData.makefile;
makefile.bufferChar := getc(makefile);
while makefile.bufferChar <> EOF do
skipWhiteSpace(makefile);
if makefile.bufferChar = '#' then
skipLineComment(makefile);
makefile.bufferChar := getc(makefile);
elsif makefile.bufferChar = '!' then
makefile.bufferChar := getc(makefile);
name := lower(getWord(makefile));
if name = "if" then
execIf(makefile, makeData.macros);
elsif name = "include" then
includeMakefile(makeData, name = "-include");
makefile := makeData.makefile;
elsif name = "endif" then
skipLineComment(makefile);
makefile.bufferChar := getc(makefile);
else
writeln(" *** Unknown directive !" <& name);
skipLineComment(makefile);
makefile.bufferChar := getc(makefile);
end if;
elsif makefile.bufferChar in target_name_char then
name := getMakeTarget(makefile);
skipSpaceOrTab(makefile);
if name = "override" and makefile.bufferChar in target_name_char then
name := getMakeTarget(makefile);
skipSpaceOrTab(makefile);
end if;
if makefile.bufferChar = '=' then
makefile.bufferChar := getc(makefile);
skipSpace(makefile);
makeData.macros @:= [name] getMakeLine(makefile);
makefile.bufferChar := getc(makefile);
elsif makefile.bufferChar = ':' then
makefile.bufferChar := getc(makefile);
if makefile.bufferChar = '=' then
makefile.bufferChar := getc(makefile);
skipSpace(makefile);
data := applyMacros(makeData.macros, getMakeLine(makefile), FALSE);
makeData.macros @:= [name] data;
makefile.bufferChar := getc(makefile);
else
name := applyMacros(makeData.macros, name, TRUE);
addRule(makeData, readRule(makeData, name));
end if;
elsif makefile.bufferChar = '?' then
makefile.bufferChar := getc(makefile);
if makefile.bufferChar = '=' then
makefile.bufferChar := getc(makefile);
skipSpace(makefile);
data := getMakeLine(makefile);
if name not in makeData.macros and getenv(name) = "" then
makeData.macros @:= [name] data;
end if;
makefile.bufferChar := getc(makefile);
end if;
elsif makefile.bufferChar = '+' then
makefile.bufferChar := getc(makefile);
if makefile.bufferChar = '=' then
makefile.bufferChar := getc(makefile);
skipSpace(makefile);
data := applyMacros(makeData.macros, getMakeLine(makefile), TRUE);
if name in makeData.macros and makeData.macros[name] <> "" then
makeData.macros @:= [name] makeData.macros[name] & " " & data;
else
makeData.macros @:= [name] data;
end if;
makefile.bufferChar := getc(makefile);
end if;
elsif name = "ifeq" then
execIfeq(makefile, makeData.macros, TRUE);
elsif name = "ifneq" then
execIfeq(makefile, makeData.macros, FALSE);
elsif name = "ifdef" then
execIfdef(makefile, makeData.macros, TRUE);
elsif name = "ifndef" then
execIfdef(makefile, makeData.macros, FALSE);
elsif name = "else" then
skipLine(makefile);
makefile.bufferChar := getc(makefile);
find_endif(makefile);
elsif name = "endif" then
skipLine(makefile);
makefile.bufferChar := getc(makefile);
elsif name = "include" or name = "-include" then
includeMakefile(makeData, name = "-include");
makefile := makeData.makefile;
elsif name = ".SILENT" then
makeData.inSilentMode := TRUE;
skipLine(makefile);
makefile.bufferChar := getc(makefile);
else
name := applyMacros(makeData.macros, name, TRUE);
alternateTargets := 0 times "";
while makefile.bufferChar in target_name_char do
alternateTargets &:= getMakeTarget(makefile);
skipSpace(makefile);
end while;
if makefile.bufferChar = ':' then
makefile.bufferChar := getc(makefile);
addRule(makeData, readRule(makeData, name));
else
writeln(" *** Illegal character " <& literal(makefile.bufferChar) <&
" after target or variable named " <& literal(name) <& ", ignored.");
makefile.bufferChar := getc(makefile);
end if;
end if;
elsif makefile.bufferChar <> EOF then
writeln(" *** Illegal character " <& literal(makefile.bufferChar) <& ", ignored.");
makefile.bufferChar := getc(makefile);
end if;
end while;
end func;
const proc: includeMakefile (inout makeDataType: makeData, in boolean: ignoreError) is func
local
var string: includeFiles is "";
var string: fileName is "";
var file: makefile is STD_NULL;
var file: surroundingFile is STD_NULL;
begin
skipSpace(makeData.makefile);
includeFiles := applyMacros(makeData.macros, getMakeLine(makeData.makefile), TRUE);
makeData.makefile.bufferChar := getc(makeData.makefile);
while includeFiles <> "" do
fileName := getWord(includeFiles);
makefile := open(fileName, "r");
if makefile = STD_NULL then
if not ignoreError then
writeln(" *** include file " <& fileName <& " not found.");
end if;
else
surroundingFile := makeData.makefile;
makeData.makefile := makefile;
readMakefile(makeData);
close(makefile);
makeData.makefile := surroundingFile;
end if;
skipWhiteSpace(includeFiles);
end while;
end func;
const proc: readMakefile (inout makeDataType: makeData, in string: fileName) is func
local
var file: makefile is STD_NULL;
var file: surroundingFile is STD_NULL;
begin
makefile := open(fileName, "r");
if makefile = STD_NULL then
writeln(" *** Makefile " <& fileName <& " not found.");
else
surroundingFile := makeData.makefile;
makeData.makefile := makefile;
readMakefile(makeData);
close(makefile);
makeData.makefile := surroundingFile;
end if;
end func;