Implement word, wordlist, words, firstword, and lastword
diff --git a/eval.go b/eval.go
index 3429176..a6a2baa 100644
--- a/eval.go
+++ b/eval.go
@@ -33,6 +33,11 @@
"patsubst": funcPatsubst,
"strip": funcStrip,
"findstring": funcFindstring,
+ "word": funcWord,
+ "wordlist": funcWordlist,
+ "words": funcWords,
+ "firstword": funcFirstword,
+ "lastword": funcLastword,
"wildcard": funcWildcard,
"dir": funcDir,
"notdir": funcNotdir,
diff --git a/exec.go b/exec.go
index 19359d4..1198e2e 100644
--- a/exec.go
+++ b/exec.go
@@ -207,6 +207,8 @@
})
}
ev := newEvaluator(localVars)
+ ev.filename = rule.filename
+ ev.lineno = rule.cmdLineno
var cmds []string
for _, cmd := range rule.cmds {
if strings.IndexByte(cmd, '$') < 0 {
diff --git a/func.go b/func.go
index 7ada6ba..49b17b6 100644
--- a/func.go
+++ b/func.go
@@ -4,6 +4,7 @@
"fmt"
"os/exec"
"path/filepath"
+ "strconv"
"strings"
)
@@ -60,11 +61,84 @@
// filter
// filter-out
// sort
-// word
-// wordlist
-// words
-// firstword
-// lastword
+
+func numericValueForFunc(ev *Evaluator, a string, funcName string, nth string) int {
+ a = strings.TrimSpace(ev.evalExpr(a))
+ n, err := strconv.Atoi(a)
+ if err != nil || n < 0 {
+ Error(ev.filename, ev.lineno, `*** non-numeric %s argument to "%s" function: "%s".`, nth, funcName, a)
+ }
+ return n
+}
+
+func funcWord(ev *Evaluator, args []string) string {
+ if len(args) < 2 {
+ panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `word'.", len(args)))
+ }
+ index := numericValueForFunc(ev, args[0], "word", "first")
+ if index == 0 {
+ Error(ev.filename, ev.lineno, `*** first argument to "word" function must be greater than 0.`)
+ }
+ toks := splitSpaces(ev.evalExpr(strings.Join(args[1:], ",")))
+ if index-1 >= len(toks) {
+ return ""
+ }
+ return ev.evalExpr(toks[index-1])
+}
+
+func funcWordlist(ev *Evaluator, args []string) string {
+ if len(args) < 3 {
+ panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `wordlist'.", len(args)))
+ }
+ si := numericValueForFunc(ev, args[0], "wordlist", "first")
+ if si == 0 {
+ Error(ev.filename, ev.lineno, `*** invalid first argument to "wordlist" function: ""`, args[0])
+ }
+ ei := numericValueForFunc(ev, args[1], "wordlist", "second")
+ if ei == 0 {
+ Error(ev.filename, ev.lineno, `*** invalid second argument to "wordlist" function: ""`, args[1])
+ }
+
+ toks := splitSpaces(ev.evalExpr(strings.Join(args[2:], ",")))
+ if si-1 >= len(toks) {
+ return ""
+ }
+ if ei-1 >= len(toks) {
+ ei = len(toks)
+ }
+
+ return strings.Join(toks[si-1:ei], " ")
+}
+
+func funcWords(ev *Evaluator, args []string) string {
+ if len(args) <= 0 {
+ panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `words'.", len(args)))
+ }
+ toks := splitSpaces(ev.evalExpr(strings.Join(args, ",")))
+ return strconv.Itoa(len(toks))
+}
+
+func funcFirstword(ev *Evaluator, args []string) string {
+ if len(args) <= 0 {
+ panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `firstword'.", len(args)))
+ }
+ toks := splitSpaces(ev.evalExpr(strings.Join(args, ",")))
+ if len(toks) == 0 {
+ return ""
+ }
+ return toks[0]
+}
+
+func funcLastword(ev *Evaluator, args []string) string {
+ if len(args) <= 0 {
+ panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `lastword'.", len(args)))
+ }
+ toks := splitSpaces(ev.evalExpr(strings.Join(args, ",")))
+ if len(toks) == 0 {
+ return ""
+ }
+ return toks[len(toks)-1]
+}
// http://www.gnu.org/software/make/manual/make.html#File-Name-Functions
func funcWildcard(ev *Evaluator, args []string) string {
diff --git a/test/err_word_non_numeric.mk b/test/err_word_non_numeric.mk
new file mode 100644
index 0000000..aacdee9
--- /dev/null
+++ b/test/err_word_non_numeric.mk
@@ -0,0 +1,2 @@
+test:
+ echo $(word -1, foo bar)
diff --git a/test/err_word_zero.mk b/test/err_word_zero.mk
new file mode 100644
index 0000000..9b6efee
--- /dev/null
+++ b/test/err_word_zero.mk
@@ -0,0 +1,2 @@
+test:
+ echo $(word 0, foo bar)
diff --git a/test/firstword.mk b/test/firstword.mk
new file mode 100644
index 0000000..7f9590a
--- /dev/null
+++ b/test/firstword.mk
@@ -0,0 +1,4 @@
+test:
+ echo $(firstword foo bar baz)
+ echo $(firstword )
+
diff --git a/test/lastword.mk b/test/lastword.mk
new file mode 100644
index 0000000..12a2621
--- /dev/null
+++ b/test/lastword.mk
@@ -0,0 +1,4 @@
+test:
+ echo $(lastword foo bar baz)
+ echo $(lastword )
+
diff --git a/test/word.mk b/test/word.mk
new file mode 100644
index 0000000..55f6226
--- /dev/null
+++ b/test/word.mk
@@ -0,0 +1,7 @@
+test:
+ echo $(word 2, foo bar baz)
+ echo $(word 2, )
+ echo $(word 4, foo bar baz)
+ echo $(word 1, foo,bar baz)
+ echo $(word 2, foo,bar baz)
+ echo $(word 2, foo, bar baz)
diff --git a/test/wordlist.mk b/test/wordlist.mk
new file mode 100644
index 0000000..3dc84ed
--- /dev/null
+++ b/test/wordlist.mk
@@ -0,0 +1,5 @@
+test:
+ echo $(wordlist 2, 3, foo bar baz)
+ echo $(wordlist 2, 4, foo bar baz)
+ echo $(wordlist 4, 7, foo bar baz)
+ echo $(wordlist 3, 2, foo bar baz)
diff --git a/test/words.mk b/test/words.mk
new file mode 100644
index 0000000..96f9e4d
--- /dev/null
+++ b/test/words.mk
@@ -0,0 +1,3 @@
+test:
+ echo $(words foo bar baz)
+ echo $(words )