gmsl-1.1.7/0000775000175000017500000000000012446002551010553 5ustar jgcjgcgmsl-1.1.7/README0000644000175000017500000000052612446002551011434 0ustar jgcjgcGNU Make Standard Library ------------------------- 1. Visit http://gmsl.sf.net for more details 2. To use the GMSL in your Makefile make sure that you have the files gmsl __gmsl Add include gmsl to your Makefile(s). 3. To run the GMSL test suite have gmsl __gmsl gmsl-tests And then run make test gmsl-1.1.7/gmsl-tests0000644000175000017500000007747612446002551012623 0ustar jgcjgc# ---------------------------------------------------------------------------- # # GNU Make Standard Library (GMSL) Test Suite # # Test suite for the GMSL # # Copyright (c) 2005-2014 John Graham-Cumming # # This file is part of GMSL # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # Neither the name of the John Graham-Cumming nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # ---------------------------------------------------------------------------- ifdef EXPORT_ALL .EXPORT_ALL_VARIABLES: endif .PHONY: all all: @echo @echo Test Summary @echo ------------ @echo "$(call int_decode,$(passed)) tests passed; $(call int_decode,$(failed)) tests failed" include gmsl passed := failed := ECHO := /bin/echo start_test = $(if $0,$(shell $(ECHO) -n "Testing '$1': " >&2))$(eval current_test := OK) stop_test = $(if $0,$(shell $(ECHO) " $(current_test)" >&2)) test_pass = .$(eval passed := $(call int_inc,$(passed))) test_fail = X$(eval failed := $(call int_inc,$(failed)))$(eval current_test := ERROR '$1' != '$2') test_assert = $(if $0,$(if $(filter undefined,$(origin 2)),$(eval 2 :=))$(shell $(ECHO) -n $(if $(call seq,$1,$2),$(call test_pass,$1,$2),$(call test_fail,$1,$2)) >&2)) $(call start_test,not) $(call test_assert,$(call not,$(true)),$(false)) $(call test_assert,$(call not,$(false)),$(true)) $(call stop_test) $(call start_test,or) $(call test_assert,$(call or,$(true),$(true)),$(true)) $(call test_assert,$(call or,$(true),$(false)),$(true)) $(call test_assert,$(call or,$(false),$(true)),$(true)) $(call test_assert,$(call or,$(false),$(false)),$(false)) $(call stop_test) $(call start_test,and) $(call test_assert,$(call and,$(true),$(true)),$(true)) $(call test_assert,$(call and,$(true),$(false)),$(false)) $(call test_assert,$(call and,$(false),$(true)),$(false)) $(call test_assert,$(call and,$(false),$(false)),$(false)) $(call stop_test) $(call start_test,xor) $(call test_assert,$(call xor,$(true),$(true)),$(false)) $(call test_assert,$(call xor,$(true),$(false)),$(true)) $(call test_assert,$(call xor,$(false),$(true)),$(true)) $(call test_assert,$(call xor,$(false),$(false)),$(false)) $(call stop_test) $(call start_test,nand) $(call test_assert,$(call nand,$(true),$(true)),$(false)) $(call test_assert,$(call nand,$(true),$(false)),$(true)) $(call test_assert,$(call nand,$(false),$(true)),$(true)) $(call test_assert,$(call nand,$(false),$(false)),$(true)) $(call stop_test) $(call start_test,nor) $(call test_assert,$(call nor,$(true),$(true)),$(false)) $(call test_assert,$(call nor,$(true),$(false)),$(false)) $(call test_assert,$(call nor,$(false),$(true)),$(false)) $(call test_assert,$(call nor,$(false),$(false)),$(true)) $(call stop_test) $(call start_test,xnor) $(call test_assert,$(call xnor,$(true),$(true)),$(true)) $(call test_assert,$(call xnor,$(true),$(false)),$(false)) $(call test_assert,$(call xnor,$(false),$(true)),$(false)) $(call test_assert,$(call xnor,$(false),$(false)),$(true)) $(call stop_test) $(call start_test,first) $(call test_assert,$(call first,1 2 3),1) $(call test_assert,$(call first,1),1) $(call test_assert,$(call first,),) $(call stop_test) $(call start_test,last) $(call test_assert,$(call last,1 2 3),3) $(call test_assert,$(call last,1),1) $(call test_assert,$(call last,),) $(call stop_test) $(call start_test,rest) $(call test_assert,$(call rest,1 2 3),2 3) $(call test_assert,$(call rest,1),) $(call test_assert,$(call rest,),) $(call stop_test) $(call start_test,chop) $(call test_assert,$(call chop,1 2 3),1 2) $(call test_assert,$(call chop,1 2 3 4),1 2 3) $(call test_assert,$(call chop,1),) $(call test_assert,$(call chop,),) $(call stop_test) $(call start_test,length) $(call test_assert,$(call length,1 2 3),3) $(call test_assert,$(call length,1 2 3 4),4) $(call test_assert,$(call length,1),1) $(call test_assert,$(call length,),0) $(call stop_test) $(call start_test,map) $(call test_assert,$(call map,origin,__undefined map MAKE),undefined file default) $(call test_assert,$(call map,origin,),) $(call stop_test) joinem = $1$2 $(call start_test,pairmap) $(call test_assert,$(call pairmap,addsuffix,2 1 3,a b c),a2 b1 c3) $(call test_assert,$(call pairmap,addprefix,2 1 3,a b c d),2a 1b 3c d) $(call test_assert,$(call pairmap,addprefix,2 1 3 4,a b c),2a 1b 3c) $(call test_assert,$(call pairmap,joinem,2 1 3 4,a b c),2a 1b 3c 4) $(call stop_test) $(call start_test,seq) $(call test_assert,$(call seq,abc,abc),T) $(call test_assert,$(call seq,x,),) $(call test_assert,$(call seq,,x),) $(call test_assert,$(call seq,x,x),T) $(call test_assert,$(call seq,a%c,abc),) $(call test_assert,$(call seq,abc,a%c),) $(call test_assert,$(call seq,abc,ABC),) $(call test_assert,$(call seq,abc,),) $(call test_assert,$(call seq,,),T) $(call test_assert,$(call seq,a b c,a b c),T) $(call test_assert,$(call seq,aa% bb% cc,aa% bb% cc),T) $(call test_assert,$(call seq,aa% bb% cc,aa% bb cc),) $(call test_assert,$(call seq,aa% bb% cc,xx yy zz),) $(call test_assert,$(call seq,x x,),) $(call test_assert,$(call seq, xx x,x xx),) $(call test_assert,$(call seq, , ),T) $(call test_assert,$(call seq,, ),) $(call test_assert,$(call seq, ,),) $(call test_assert,$(call seq,y,xy),) $(call test_assert,$(call seq,$(__gmsl_space),$(__gmsl_tab)),) $(call stop_test) $(call start_test,sne) $(call test_assert,$(call sne,abc,abc),) $(call test_assert,$(call sne,x,),T) $(call test_assert,$(call sne,,x),T) $(call test_assert,$(call sne,x,x),) $(call test_assert,$(call sne,abc,ABC),T) $(call test_assert,$(call sne,abc,),T) $(call test_assert,$(call sne,,),) $(call test_assert,$(call sne,a b c,a b c),) $(call test_assert,$(call sne,aa% bb% cc,aa% bb% cc),) $(call test_assert,$(call sne,aa% bb% cc,aa% bb cc),T) $(call stop_test) $(call start_test,strlen) $(call test_assert,$(call strlen,),0) $(call test_assert,$(call strlen,a),1) $(call test_assert,$(call strlen,a b),3) $(call test_assert,$(call strlen,a ),2) $(call test_assert,$(call strlen, a),2) $(call test_assert,$(call strlen, ),2) $(call test_assert,$(call strlen, ),3) $(call test_assert,$(call strlen, ),4) $(call stop_test) $(call start_test,substr) $(call test_assert,$(call substr,xyz,1,1),x) $(call test_assert,$(call substr,xyz,1,2),xy) $(call test_assert,$(call substr,xyz,2,3),yz) $(call test_assert,$(call substr,some string,1,1),s) $(call test_assert,$(call substr,some string,1,2),so) $(call test_assert,$(call substr,some string,1,3),som) $(call test_assert,$(call substr,some string,1,4),some) $(call test_assert,$(call substr,some string,1,5),some ) $(call test_assert,$(call substr,some string,1,6),some s) $(call test_assert,$(call substr,some string,5,5), ) $(call test_assert,$(call substr,some string,5,6), s) $(call test_assert,$(call substr,some string,5,7), st) $(call test_assert,$(call substr,some string,5,8), str) $(call test_assert,$(call substr,some string,1,100),some string) $(call stop_test) $(call start_test,lc) $(call test_assert,$(call lc,The Quick Brown Fox),the quick brown fox) $(call test_assert,$(call lc,the1 quick2 brown3 fox4),the1 quick2 brown3 fox4) $(call test_assert,$(call lc,The_),the_) $(call test_assert,$(call lc,),) $(call stop_test) $(call start_test,uc) $(call test_assert,$(call uc,The Quick Brown Fox),THE QUICK BROWN FOX) $(call test_assert,$(call uc,the1 quick2 brown3 fox4),THE1 QUICK2 BROWN3 FOX4) $(call test_assert,$(call uc,The_),THE_) $(call test_assert,$(call uc,),) $(call stop_test) $(call start_test,tr) $(call test_assert,$(call tr,A B C,1 2 3,CAPITAL),31PIT1L) $(call test_assert,$(call tr,a b c,1 2 3,CAPITAL),CAPITAL) $(call test_assert,$(call tr,E L I,3 1 1,I AM ELITE),1 AM 311T3) $(call stop_test) $(call start_test,leq) $(call test_assert,$(call leq,1 2 3,1 2 3),T) $(call test_assert,$(call leq,1 2 3,1 2 3 4),) $(call test_assert,$(call leq,1 2 3 4,1 2 3),) $(call test_assert,$(call leq,1,1),T) $(call test_assert,$(call leq,,),T) $(call stop_test) $(call start_test,lne) $(call test_assert,$(call lne,1 2 3,1 2 3),) $(call test_assert,$(call lne,1 2 3,1 2 3 4),T) $(call test_assert,$(call lne,1 2 3 4,1 2 3),T) $(call test_assert,$(call lne,1,1),) $(call test_assert,$(call lne,,),) $(call stop_test) $(call start_test,empty_set) $(call test_assert,$(empty_set),) $(call test_assert,$(empty_set),$(call set_create,)) $(call stop_test) $(call start_test,set_create) $(call test_assert,$(call set_create,),) $(call test_assert,$(call set_create,1 2 2 3),1 2 3) $(call test_assert,$(call set_create,2 1 1 2 2 3),1 2 3) $(call test_assert,$(call set_create,1),1) $(call stop_test) $(call start_test,set_insert) $(call test_assert,$(call set_insert,1,$(empty_set)),1) $(call test_assert,$(call set_insert,1,$(call set_create,1)),1) $(call test_assert,$(call set_insert,1,$(call set_create,1 2)),1 2) $(call test_assert,$(call set_insert,0,$(call set_create,1 2)),0 1 2) $(call stop_test) $(call start_test,set_remove) $(call test_assert,$(call set_remove,1,$(empty_set)),$(empty_set)) $(call test_assert,$(call set_remove,1,$(call set_create,1 2)),2) $(call test_assert,$(call set_remove,1,$(call set_create,1 11 2)),11 2) $(call test_assert,$(call set_remove,0,$(call set_create,1 2)),1 2) $(call stop_test) $(call start_test,set_is_member) $(call test_assert,$(call set_is_member,1,$(empty_set)),) $(call test_assert,$(call set_is_member,1,$(call set_create,2 3)),) $(call test_assert,$(call set_is_member,1,$(call set_create,1 2 3)),T) $(call test_assert,$(call set_is_member,1,$(call set_create,1)),T) $(call stop_test) $(call start_test,set_is_not_member) $(call test_assert,$(call set_is_not_member,1,$(empty_set)),T) $(call test_assert,$(call set_is_not_member,1,$(call set_create,2 3)),T) $(call test_assert,$(call set_is_not_member,1,$(call set_create,1 2 3)),) $(call test_assert,$(call set_is_not_member,1,$(call set_create,1)),) $(call stop_test) $(call start_test,set_union) $(call test_assert,$(call set_union,,),) $(call test_assert,$(call set_union,1 2,),1 2) $(call test_assert,$(call set_union,,3 4),3 4) $(call test_assert,$(call set_union,1 2,3 4),1 2 3 4) $(call test_assert,$(call set_union,1 2 3,3 4 5),1 2 3 4 5) $(call stop_test) $(call start_test,set_intersection) $(call test_assert,$(call set_intersection,,),) $(call test_assert,$(call set_intersection,1 2,),) $(call test_assert,$(call set_intersection,,3 4),) $(call test_assert,$(call set_intersection,1 2,3 4),) $(call test_assert,$(call set_intersection,1 2 3 4,3 4 5),3 4) $(call stop_test) $(call start_test,set_is_subset) $(call test_assert,$(call set_is_subset,,),T) $(call test_assert,$(call set_is_subset,1 2,),) $(call test_assert,$(call set_is_subset,,3 4),T) $(call test_assert,$(call set_is_subset,1 2,3 4),) $(call test_assert,$(call set_is_subset,1 2,1 2 3 4 5),T) $(call test_assert,$(call set_is_subset,1 2,1 2),T) $(call test_assert,$(call set_is_subset,1 2,1 3 4 5),) $(call stop_test) $(call start_test,set_equal) $(call test_assert,$(call set_equal,,),T) $(call test_assert,$(call set_equal,1,),) $(call test_assert,$(call set_equal,,1),) $(call test_assert,$(call set_equal,1,1),T) $(call test_assert,$(call set_equal,1 2,),) $(call test_assert,$(call set_equal,,1 2),) $(call test_assert,$(call set_equal,1 2,1 2 3),) $(call stop_test) $(call start_test,__strip_leading_zero) $(call test_assert,$(call __strip_leading_zero,),0) $(call test_assert,$(call __strip_leading_zero,0),0) $(call test_assert,$(call __strip_leading_zero,0000),0) $(call test_assert,$(call __strip_leading_zero,1),1) $(call test_assert,$(call __strip_leading_zero,10),10) $(call test_assert,$(call __strip_leading_zero,01),1) $(call test_assert,$(call __strip_leading_zero,001),1) $(call test_assert,$(call __strip_leading_zero,0010),10) $(call test_assert,$(call __strip_leading_zero,00000011000),11000) $(call stop_test) $(call start_test,int_encode) $(call test_assert,$(call int_encode,0),) $(call test_assert,$(call int_encode,1),x) $(call test_assert,$(call int_encode,001),x) $(call test_assert,$(call int_encode,2),x x) $(call test_assert,$(call int_encode,10),x x x x x x x x x x) $(call test_assert,$(words $(call int_encode,123)),123) $(call test_assert,$(words $(call int_encode,1234)),1234) $(call test_assert,$(words $(call int_encode,12345)),12345) $(call test_assert,$(words $(call int_encode,012345)),12345) $(call test_assert,$(words $(call int_encode,1000000)),1000000) $(call stop_test) $(call start_test,int_decode) $(call test_assert,$(call int_decode,),0) $(call test_assert,$(call int_decode,x),1) $(call test_assert,$(call int_decode,x x),2) $(call test_assert,$(call int_decode,x x x x x x x x x x),10) $(call stop_test) $(call start_test,int_plus) $(call test_assert,$(call int_plus,$(call int_encode,3),$(call int_encode,4)),$(call int_encode,7)) $(call test_assert,$(call int_plus,$(call int_encode,0),$(call int_encode,4)),$(call int_encode,4)) $(call test_assert,$(call int_plus,$(call int_encode,3),$(call int_encode,0)),$(call int_encode,3)) $(call test_assert,$(call int_plus,$(call int_encode,0),$(call int_encode,0)),$(call int_encode,0)) $(call test_assert,$(call int_plus,$(call int_encode,1),$(call int_encode,0)),$(call int_encode,1)) $(call stop_test) $(call start_test,plus) $(call test_assert,$(call plus,3,4),7) $(call test_assert,$(call plus,4,3),7) $(call test_assert,$(call plus,0,4),4) $(call test_assert,$(call plus,3,0),3) $(call test_assert,$(call plus,03,00),3) $(call test_assert,$(call plus,0,0),0) $(call stop_test) __gmsl_warning = $1 $(call start_test,int_subtract) $(call test_assert,$(call int_subtract,$(call int_encode,3),$(call int_encode,4)),Subtraction underflow) $(call test_assert,$(call int_subtract,$(call int_encode,4),$(call int_encode,3)),$(call int_encode,1)) $(call test_assert,$(call int_subtract,$(call int_encode,3),$(call int_encode,0)),$(call int_encode,3)) $(call test_assert,$(call int_subtract,$(call int_encode,0),$(call int_encode,0)),$(call int_encode,0)) $(call test_assert,$(call int_subtract,$(call int_encode,1),$(call int_encode,0)),$(call int_encode,1)) $(call stop_test) __gmsl_warning = x x x x x x x x x x $(call start_test,subtract) $(call test_assert,$(call subtract,3,4),10) $(call test_assert,$(call subtract,4,3),1) $(call test_assert,$(call subtract,3,0),3) $(call test_assert,$(call subtract,0,0),0) $(call stop_test) $(call start_test,int_multiply) $(call test_assert,$(call int_multiply,$(call int_encode,3),$(call int_encode,4)),$(call int_encode,12)) $(call test_assert,$(call int_multiply,$(call int_encode,4),$(call int_encode,3)),$(call int_encode,12)) $(call test_assert,$(call int_multiply,$(call int_encode,3),$(call int_encode,0)),$(call int_encode,0)) $(call test_assert,$(call int_multiply,$(call int_encode,0),$(call int_encode,0)),$(call int_encode,0)) $(call test_assert,$(call int_multiply,$(call int_encode,1),$(call int_encode,0)),$(call int_encode,0)) $(call stop_test) $(call start_test,multiply) $(call test_assert,$(call multiply,3,4),12) $(call test_assert,$(call multiply,4,3),12) $(call test_assert,$(call multiply,3,0),0) $(call test_assert,$(call multiply,0,3),0) $(call test_assert,$(call multiply,0,0),0) $(call stop_test) __gmsl_error = $1 $(call start_test,int_divide) $(call test_assert,$(call int_divide,$(call int_encode,3),$(call int_encode,4)),$(call int_encode,0)) $(call test_assert,$(call int_divide,$(call int_encode,4),$(call int_encode,3)),$(call int_encode,1)) $(call test_assert,$(call int_divide,$(call int_encode,31),$(call int_encode,3)),$(call int_encode,10)) $(call test_assert,$(call int_divide,$(call int_encode,30),$(call int_encode,3)),$(call int_encode,10)) $(call test_assert,$(call int_divide,$(call int_encode,29),$(call int_encode,3)),$(call int_encode,9)) $(call test_assert,$(call int_divide,$(call int_encode,0),$(call int_encode,1)),$(call int_encode,0)) $(call test_assert,$(call int_divide,$(call int_encode,1),$(call int_encode,0)),Division by zero) $(call stop_test) __gmsl_error = x x x x x x x x x x $(call start_test,divide) $(call test_assert,$(call divide,3,4),0) $(call test_assert,$(call divide,4,3),1) $(call test_assert,$(call divide,21,2),10) $(call test_assert,$(call divide,20,2),10) $(call test_assert,$(call divide,19,2),9) $(call test_assert,$(call divide,1,0),10) $(call stop_test) $(call start_test,dec2hex) $(call test_assert,$(call dec2hex,0),0) $(call test_assert,$(call dec2hex,1),1) $(call test_assert,$(call dec2hex,10),a) $(call test_assert,$(call dec2hex,15),f) $(call test_assert,$(call dec2hex,254),fe) $(call test_assert,$(call dec2hex,255),ff) $(call test_assert,$(call dec2hex,513),201) $(call stop_test) $(call start_test,dec2oct) $(call test_assert,$(call dec2oct,0),0) $(call test_assert,$(call dec2oct,1),1) $(call test_assert,$(call dec2oct,8),10) $(call test_assert,$(call dec2oct,15),17) $(call test_assert,$(call dec2oct,1024),2000) $(call test_assert,$(call dec2oct,1025),2001) $(call stop_test) $(call start_test,dec2bin) $(call test_assert,$(call dec2bin,0),0) $(call test_assert,$(call dec2bin,1),1) $(call test_assert,$(call dec2bin,8),1000) $(call test_assert,$(call dec2bin,15),1111) $(call test_assert,$(call dec2bin,1024),10000000000) $(call test_assert,$(call dec2bin,1025),10000000001) $(call stop_test) $(call start_test,associative array) $(call test_assert,$(call get,myarray,key1),) $(call test_assert,$(call set,myarray,key1,value1),) $(call test_assert,$(call get,myarray,key1),value1) $(call test_assert,$(call get,myarray,key2),) $(call test_assert,$(call get,myarray1,key1),) $(call test_assert,$(call defined,myarray,key1),T) $(call test_assert,$(call defined,myarray,key2),) $(call test_assert,$(call defined,myarray1,key1),) $(call test_assert,$(call set,myarray,key2,value2),) $(call test_assert,$(call keys,myarray),key1 key2) $(call test_assert,$(call keys,myarray1),) $(call test_assert,$(call set,foo,bar_baz,bob),) $(call test_assert,$(call set,foo_bar,baz,alice),) $(call test_assert,$(call get,foo,bar_baz),bob) $(call test_assert,$(call get,foo_bar,baz),alice) $(call test_assert,$(call set,foo,bar,baz/baz),) $(call test_assert,$(call get,foo,bar),baz/baz) $(call test-assert,$(call set,foo,bar-baz,baz),) $(call test_assert,$(call get,foo,bar-baz),baz) $(call set,foo,bar-baz,baz) $(call set,foo,bar,baz/baz) $(call stop_test) $(call start_test,named stack) $(call test_assert,$(call pop,mystack),) $(call test_assert,$(call push,mystack,e2)) $(call push,mystack,e1) $(call test_assert,$(call pop,mystack),e1) $(call test_assert,$(call pop,mystack),e2) $(call push,mystack,f3) $(call push,mystack,f1) $(call test_assert,$(call pop,mystack),f1) $(call push,mystack,f2) $(call test_assert,$(call peek,mystack),f2) $(call test_assert,$(call depth,mystack),2) $(call test_assert,$(call pop,mystack),f2) $(call test_assert,$(call depth,mystack),1) $(call test_assert,$(call pop,myotherstack),) $(call stop_test) $(call start_test,reverse) $(call test_assert,$(call reverse,),) $(call test_assert,$(call reverse,1),1) $(call test_assert,$(call reverse,1 2),2 1) $(call test_assert,$(call reverse,1 2 3),3 2 1) $(call stop_test) $(call start_test,uniq) $(call test_assert,$(call uniq,),) $(call test_assert,$(call uniq,a),a) $(call test_assert,$(call uniq,a a),a) $(call test_assert,$(call uniq,a aa),a aa) $(call test_assert,$(call uniq,a aa a),a aa) $(call test_assert,$(call uniq,a b ba ab b a a ba a),a b ba ab) $(call stop_test) c:=, $(call start_test,split) $(call test_assert,$(call split,$c,comma$cseparated$cstring),comma separated string) $(call test_assert,$(call split,*,star*field*record),star field record) $(call test_assert,$(call split,*,star*),star) $(call test_assert,$(call split,*,star*field),star field) $(call test_assert,$(call split,*,star****field),star field) $(call test_assert,$(call split,*,),) $(call stop_test) $(call start_test,merge) $(call test_assert,$(call merge,$c,list of things),list$cof$cthings) $(call test_assert,$(call merge,*,list of things),list*of*things) $(call test_assert,$(call merge,*,list),list) $(call test_assert,$(call merge,*,),) $(call stop_test) $(call start_test,int_max) $(call test_assert,$(call int_max,$(call int_encode,2),$(call int_encode,1)),$(call int_encode,2)) $(call test_assert,$(call int_max,$(call int_encode,1),$(call int_encode,2)),$(call int_encode,2)) $(call test_assert,$(call int_max,$(call int_encode,2),$(call int_encode,0)),$(call int_encode,2)) $(call test_assert,$(call int_max,$(call int_encode,0),$(call int_encode,2)),$(call int_encode,2)) $(call test_assert,$(call int_max,$(call int_encode,2),$(call int_encode,2)),$(call int_encode,2)) $(call test_assert,$(call int_max,$(call int_encode,0),$(call int_encode,0)),$(call int_encode,0)) $(call stop_test) $(call start_test,max) $(call test_assert,$(call max,2,1),2) $(call test_assert,$(call max,1,2),2) $(call test_assert,$(call max,2,0),2) $(call test_assert,$(call max,0,2),2) $(call test_assert,$(call max,2,2),2) $(call test_assert,$(call max,0,0),0) $(call stop_test) $(call start_test,int_min) $(call test_assert,$(call int_min,$(call int_encode,2),$(call int_encode,1)),$(call int_encode,1)) $(call test_assert,$(call int_min,$(call int_encode,1),$(call int_encode,2)),$(call int_encode,1)) $(call test_assert,$(call int_min,$(call int_encode,2),$(call int_encode,0)),$(call int_encode,0)) $(call test_assert,$(call int_min,$(call int_encode,0),$(call int_encode,2)),$(call int_encode,0)) $(call test_assert,$(call int_min,$(call int_encode,2),$(call int_encode,2)),$(call int_encode,2)) $(call test_assert,$(call int_min,$(call int_encode,0),$(call int_encode,0)),$(call int_encode,0)) $(call stop_test) $(call start_test,min) $(call test_assert,$(call min,2,1),1) $(call test_assert,$(call min,1,2),1) $(call test_assert,$(call min,2,0),0) $(call test_assert,$(call min,0,2),0) $(call test_assert,$(call min,2,2),2) $(call test_assert,$(call min,0,0),0) $(call stop_test) __gmsl_error = $1 $(call start_test,assert functions) $(call test_assert,$(call assert,$(true),ignore),) $(call test_assert,$(call assert,$(false),failed),Assertion failure: failed) $(call test_assert,$(call assert_exists,gmsl-tests),) $(call test_assert,$(call assert_exists,MISSING-gmsl-tests),Assertion failure: file 'MISSING-gmsl-tests' missing) $(call stop_test) $(call start_test,int_inc) $(call test_assert,$(call int_inc,$(call int_encode,0)),$(call int_encode,1)) $(call test_assert,$(call int_inc,$(call int_encode,1)),$(call int_encode,2)) $(call test_assert,$(call int_inc,$(call int_encode,4)),$(call int_encode,5)) $(call test_assert,$(call int_inc,$(call int_encode,10)),$(call int_encode,11)) $(call stop_test) $(call start_test,inc) $(call test_assert,$(call inc,0),1) $(call test_assert,$(call inc,1),2) $(call test_assert,$(call inc,4),5) $(call test_assert,$(call inc,10),11) $(call stop_test) __gmsl_warning = $1 $(call start_test,int_dec) $(call test_assert,$(call int_dec,$(call int_encode,1)),$(call int_encode,0)) $(call test_assert,$(call int_dec,$(call int_encode,4)),$(call int_encode,3)) $(call test_assert,$(call int_dec,$(call int_encode,10)),$(call int_encode,9)) $(call stop_test) __gmsl_warning = x x x x x x x x x x $(call start_test,dec) $(call test_assert,$(call dec,1),0) $(call test_assert,$(call dec,4),3) $(call test_assert,$(call dec,10),9) $(call stop_test) $(call start_test,int_double) $(call test_assert,$(call int_double,$(call int_encode,0)),$(call int_encode,0)) $(call test_assert,$(call int_double,$(call int_encode,1)),$(call int_encode,2)) $(call test_assert,$(call int_double,$(call int_encode,4)),$(call int_encode,8)) $(call stop_test) $(call start_test,double) $(call test_assert,$(call double,0),0) $(call test_assert,$(call double,1),2) $(call test_assert,$(call double,4),8) $(call stop_test) $(call start_test,int_halve) $(call test_assert,$(call int_halve,$(call int_encode,0)),$(call int_encode,0)) $(call test_assert,$(call int_halve,$(call int_encode,2)),$(call int_encode,1)) $(call test_assert,$(call int_halve,$(call int_encode,8)),$(call int_encode,4)) $(call test_assert,$(call int_halve,$(call int_encode,7)),$(call int_encode,3)) $(call stop_test) $(call start_test,halve) $(call test_assert,$(call halve,0),0) $(call test_assert,$(call halve,2),1) $(call test_assert,$(call halve,8),4) $(call test_assert,$(call halve,7),3) $(call stop_test) $(call start_test,gt) $(call test_assert,$(call gt,2,3),) $(call test_assert,$(call gt,3,2),$(true)) $(call test_assert,$(call gt,2,2),) $(call stop_test) $(call start_test,gte) $(call test_assert,$(call gte,2,3),) $(call test_assert,$(call gte,3,2),$(true)) $(call test_assert,$(call gte,2,2),$(true)) $(call stop_test) $(call start_test,lt) $(call test_assert,$(call lt,2,3),$(true)) $(call test_assert,$(call lt,3,2),) $(call test_assert,$(call lt,2,2),) $(call stop_test) $(call start_test,lte) $(call test_assert,$(call lte,2,3),$(true)) $(call test_assert,$(call lte,3,2),) $(call test_assert,$(call lte,2,2),$(true)) $(call stop_test) $(call start_test,eq) $(call test_assert,$(call eq,2,3),) $(call test_assert,$(call eq,3,2),) $(call test_assert,$(call eq,2,2),$(true)) $(call stop_test) $(call start_test,ne) $(call test_assert,$(call ne,2,3),$(true)) $(call test_assert,$(call ne,3,2),$(true)) $(call test_assert,$(call ne,2,2),) $(call stop_test) $(call start_test,int_gt) $(call test_assert,$(call int_gt,$(call int_encode,2),$(call int_encode,3)),) $(call test_assert,$(call int_gt,$(call int_encode,3),$(call int_encode,2)),$(true)) $(call test_assert,$(call int_gt,$(call int_encode,2),$(call int_encode,2)),) $(call stop_test) $(call start_test,int_gte) $(call test_assert,$(call int_gte,$(call int_encode,2),$(call int_encode,3)),) $(call test_assert,$(call int_gte,$(call int_encode,3),$(call int_encode,2)),$(true)) $(call test_assert,$(call int_gte,$(call int_encode,2),$(call int_encode,2)),$(true)) $(call stop_test) $(call start_test,int_lt) $(call test_assert,$(call int_lt,$(call int_encode,2),$(call int_encode,3)),$(true)) $(call test_assert,$(call int_lt,$(call int_encode,3),$(call int_encode,2)),) $(call test_assert,$(call int_lt,$(call int_encode,2),$(call int_encode,2)),) $(call stop_test) $(call start_test,int_lte) $(call test_assert,$(call int_lte,$(call int_encode,2),$(call int_encode,3)),$(true)) $(call test_assert,$(call int_lte,$(call int_encode,3),$(call int_encode,2)),) $(call test_assert,$(call int_lte,$(call int_encode,2),$(call int_encode,2)),$(true)) $(call stop_test) $(call start_test,int_eq) $(call test_assert,$(call int_eq,$(call int_encode,2),$(call int_encode,3)),) $(call test_assert,$(call int_eq,$(call int_encode,3),$(call int_encode,2)),) $(call test_assert,$(call int_eq,$(call int_encode,2),$(call int_encode,2)),$(true)) $(call stop_test) $(call start_test,int_ne) $(call test_assert,$(call int_ne,$(call int_encode,2),$(call int_encode,3)),$(true)) $(call test_assert,$(call int_ne,$(call int_encode,3),$(call int_encode,2)),$(true)) $(call test_assert,$(call int_ne,$(call int_encode,2),$(call int_encode,2)),) $(call stop_test) $(call start_test,sequence) $(call test_assert,$(call sequence,0,0),0) $(call test_assert,$(call sequence,1,1),1) $(call test_assert,$(call sequence,10,10),10) $(call test_assert,$(call sequence,0,1),0 1) $(call test_assert,$(call sequence,0,2),0 1 2) $(call test_assert,$(call sequence,1,2),1 2) $(call test_assert,$(call sequence,1,4),1 2 3 4) $(call test_assert,$(call sequence,10,20),10 11 12 13 14 15 16 17 18 19 20) $(call test_assert,$(call sequence,1,0),1 0) $(call test_assert,$(call sequence,2,1),2 1) $(call test_assert,$(call sequence,3,1),3 2 1) $(call test_assert,$(call sequence,20,10),20 19 18 17 16 15 14 13 12 11 10) $(call stop_test) $(call start_test,memoize) memo_counter = $(call int_encode,0) memo = $(eval memo_counter := $(call int_inc,$(memo_counter)))$(firstword $1) $(call test_assert,$(call int_decode,$(memo_counter)),0) $(call test_assert,$(call memoize,memo,hello john),hello) $(call test_assert,$(call int_decode,$(memo_counter)),1) $(call test_assert,$(call memoize,memo,hello john),hello) $(call test_assert,$(call int_decode,$(memo_counter)),1) $(call test_assert,$(call memoize,memo,hello john how are you),hello) $(call test_assert,$(call int_decode,$(memo_counter)),2) $(call test_assert,$(call memoize,memo,john),john) $(call test_assert,$(call int_decode,$(memo_counter)),3) $(call test_assert,$(call memoize,memo,hello john),hello) $(call test_assert,$(call int_decode,$(memo_counter)),3) $(call test_assert,$(call memoize,memo,hello john how are you),hello) $(call test_assert,$(call int_decode,$(memo_counter)),3) $(call test_assert,$(call memoize,memo,john),john) $(call test_assert,$(call int_decode,$(memo_counter)),3) md5_counter = $(call int_encode,0) ifneq ("$(shell echo -n hello | md5sum 2> /dev/null)","") md5_program := md5sum endif ifneq ("$(shell md5 -s hello 2> /dev/null)","") md5_program := md5 endif ifeq ("$(md5_program)","") $(error Can't find suitable MD5 program. Tried md5sum and md5) endif md5 = $(eval md5_counter = $(call int_inc,$(md5_counter)))$(firstword $(shell echo "$1" | $(md5_program))) $(call test_assert,$(call memoize,md5,hello john),2d62190b10246ee2f2e233f9df840445) $(call test_assert,$(call int_decode,$(memo_counter)),3) $(call test_assert,$(call int_decode,$(md5_counter)),1) $(call test_assert,$(call memoize,memo,hello john),hello) $(call test_assert,$(call int_decode,$(memo_counter)),3) $(call test_assert,$(call int_decode,$(md5_counter)),1) $(call test_assert,$(call memoize,md5,hello john),2d62190b10246ee2f2e233f9df840445) $(call test_assert,$(call int_decode,$(md5_counter)),1) $(call test_assert,$(call memoize,md5,hello john how are you),fd9b9651aa9f92d3d6d15a60bf5ccf15) $(call test_assert,$(call int_decode,$(md5_counter)),2) $(call test_assert,$(call memoize,md5,hello john),2d62190b10246ee2f2e233f9df840445) $(call test_assert,$(call int_decode,$(md5_counter)),2) $(call test_assert,$(call memoize,md5,hello john how are you),fd9b9651aa9f92d3d6d15a60bf5ccf15) $(call test_assert,$(call int_decode,$(md5_counter)),2) $(call stop_test) $(call start_test,gmsl_compatible) $(call test_assert,$(call gmsl_compatible,$(gmsl_version)),$(true)) $(call test_assert,$(call gmsl_compatible,0 9 0),$(true)) $(call test_assert,$(call gmsl_compatible,0 0 1),$(true)) $(call test_assert,$(call gmsl_compatible,0 0 0),$(true)) $(call test_assert,$(call gmsl_compatible,1 0 8),$(true)) $(call test_assert,$(call gmsl_compatible,1 0 8),$(true)) $(call test_assert,$(call gmsl_compatible,1 0 10),$(true)) $(call test_assert,$(call gmsl_compatible,1 0 11),$(true)) $(call test_assert,$(call gmsl_compatible,1 0 12),$(true)) $(call test_assert,$(call gmsl_compatible,1 0 13),$(true)) $(call test_assert,$(call gmsl_compatible,1 1 0),$(true)) $(call test_assert,$(call gmsl_compatible,1 1 1),$(true)) $(call test_assert,$(call gmsl_compatible,1 1 2),$(true)) $(call test_assert,$(call gmsl_compatible,1 1 3),$(true)) $(call test_assert,$(call gmsl_compatible,1 1 4),$(true)) $(call test_assert,$(call gmsl_compatible,1 1 5),$(true)) $(call test_assert,$(call gmsl_compatible,1 1 6),$(true)) $(call test_assert,$(call gmsl_compatible,1 1 7),$(true)) $(call test_assert,$(call gmsl_compatible,1 1 8),) $(call test_assert,$(call gmsl_compatible,1 2 0),) $(call test_assert,$(call gmsl_compatible,2 0 0),) $(call stop_test) gmsl-1.1.7/gmsl0000644000175000017500000000572712446002551011451 0ustar jgcjgc# ---------------------------------------------------------------------------- # # GNU Make Standard Library (GMSL) # # A library of functions to be used with GNU Make's $(call) that # provides functionality not available in standard GNU Make. # # Copyright (c) 2005-2014 John Graham-Cumming # # This file is part of GMSL # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # Neither the name of the John Graham-Cumming nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # ---------------------------------------------------------------------------- # Determine if the library has already been included and if so don't # bother including it again ifndef __gmsl_included # Standard definitions for true and false. true is any non-empty # string, false is an empty string. These are intended for use with # $(if). true := T false := # ---------------------------------------------------------------------------- # Function: not # Arguments: 1: A boolean value # Returns: Returns the opposite of the arg. (true -> false, false -> true) # ---------------------------------------------------------------------------- not = $(if $1,$(false),$(true)) # Prevent reinclusion of the library __gmsl_included := $(true) # Try to determine where this file is located. If the caller did # include /foo/gmsl then extract the /foo/ so that __gmsl gets # included transparently __gmsl_root := ifneq ($(MAKEFILE_LIST),) __gmsl_root := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) # If there are any spaces in the path in __gmsl_root then give up ifeq (1,$(words $(__gmsl_root))) __gmsl_root := $(patsubst %gmsl,%,$(__gmsl_root)) endif endif include $(__gmsl_root)__gmsl endif # __gmsl_included gmsl-1.1.7/__gmsl0000644000175000017500000012631612446002551011745 0ustar jgcjgc# ---------------------------------------------------------------------------- # # GNU Make Standard Library (GMSL) # # A library of functions to be used with GNU Make's $(call) that # provides functionality not available in standard GNU Make. # # Copyright (c) 2005-2014 John Graham-Cumming # # This file is part of GMSL # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # Neither the name of the John Graham-Cumming nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # ---------------------------------------------------------------------------- # This is the GNU Make Standard Library version number as a list with # three items: major, minor, revision gmsl_version := 1 1 7 __gmsl_name := GNU Make Standard Library # Used to output warnings and error from the library, it's possible to # disable any warnings or errors by overriding these definitions # manually or by setting GMSL_NO_WARNINGS or GMSL_NO_ERRORS ifdef GMSL_NO_WARNINGS __gmsl_warning := else __gmsl_warning = $(if $1,$(warning $(__gmsl_name): $1)) endif ifdef GMSL_NO_ERRORS __gmsl_error := else __gmsl_error = $(if $1,$(error $(__gmsl_name): $1)) endif # If GMSL_TRACE is enabled then calls to the library functions are # traced to stdout using warning messages with their arguments ifdef GMSL_TRACE __gmsl_tr1 = $(warning $0('$1')) __gmsl_tr2 = $(warning $0('$1','$2')) __gmsl_tr3 = $(warning $0('$1','$2','$3')) else __gmsl_tr1 := __gmsl_tr2 := __gmsl_tr3 := endif # See if spaces are valid in variable names (this was the case until # GNU Make 3.82) ifeq ($(MAKE_VERSION),3.82) __gmsl_spaced_vars := $(false) else __gmsl_spaced_vars := $(true) endif # Figure out whether we have $(eval) or not (GNU Make 3.80 and above) # if we do not then output a warning message, if we do then some # functions will be enabled. __gmsl_have_eval := $(false) __gmsl_ignore := $(eval __gmsl_have_eval := $(true)) # If this is being run with Electric Cloud's emake then warn that # their $(eval) support is incomplete in 1.x, 2.x, 3.x, 4.x and 5.0, # 5.1, 5.2 and 5.3 ifdef ECLOUD_BUILD_ID __gmsl_emake_major := $(word 1,$(subst ., ,$(EMAKE_VERSION))) __gmsl_emake_minor := $(word 2,$(subst ., ,$(EMAKE_VERSION))) ifneq ("$(findstring $(__gmsl_emake_major),1 2 3 4)$(findstring $(__gmsl_emake_major)$(__gmsl_emake_minor),50 51 52 53)","") $(warning You are using a version of Electric Cloud's emake which has incomplete $$(eval) support) __gmsl_have_eval := $(false) endif endif # See if we have $(lastword) (GNU Make 3.81 and above) __gmsl_have_lastword := $(lastword $(false) $(true)) # See if we have native or and and (GNU Make 3.81 and above) __gmsl_have_or := $(if $(filter-out undefined, \ $(origin or)),$(call or,$(true),$(false))) __gmsl_have_and := $(if $(filter-out undefined, \ $(origin and)),$(call and,$(true),$(true))) ifneq ($(__gmsl_have_eval),$(true)) $(call __gmsl_warning,Your make version $(MAKE_VERSION) does not support $$$$(eval): some functions disabled) endif __gmsl_dollar := $$ __gmsl_hash := \# # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- # Function: gmsl_compatible # Arguments: List containing the desired library version number (maj min rev) # Returns: $(true) if this version of the library is compatible # with the requested version number, otherwise $(false) # ---------------------------------------------------------------------------- gmsl_compatible = $(strip \ $(if $(call gt,$(word 1,$1),$(word 1,$(gmsl_version))), \ $(false), \ $(if $(call lt,$(word 1,$1),$(word 1,$(gmsl_version))), \ $(true), \ $(if $(call gt,$(word 2,$1),$(word 2,$(gmsl_version))), \ $(false), \ $(if $(call lt,$(word 2,$1),$(word 2,$(gmsl_version))), \ $(true), \ $(call lte,$(word 3,$1),$(word 3,$(gmsl_version)))))))) # ########################################################################### # LOGICAL OPERATORS # ########################################################################### # not is defined in gmsl # ---------------------------------------------------------------------------- # Function: and # Arguments: Two boolean values # Returns: Returns $(true) if both of the booleans are true # ---------------------------------------------------------------------------- ifneq ($(__gmsl_have_and),$(true)) and = $(__gmsl_tr2)$(if $1,$(if $2,$(true),$(false)),$(false)) endif # ---------------------------------------------------------------------------- # Function: or # Arguments: Two boolean values # Returns: Returns $(true) if either of the booleans is true # ---------------------------------------------------------------------------- ifneq ($(__gmsl_have_or),$(true)) or = $(__gmsl_tr2)$(if $1$2,$(true),$(false)) endif # ---------------------------------------------------------------------------- # Function: xor # Arguments: Two boolean values # Returns: Returns $(true) if exactly one of the booleans is true # ---------------------------------------------------------------------------- xor = $(__gmsl_tr2)$(if $1,$(if $2,$(false),$(true)),$(if $2,$(true),$(false))) # ---------------------------------------------------------------------------- # Function: nand # Arguments: Two boolean values # Returns: Returns value of 'not and' # ---------------------------------------------------------------------------- nand = $(__gmsl_tr2)$(if $1,$(if $2,$(false),$(true)),$(true)) # ---------------------------------------------------------------------------- # Function: nor # Arguments: Two boolean values # Returns: Returns value of 'not or' # ---------------------------------------------------------------------------- nor = $(__gmsl_tr2)$(if $1$2,$(false),$(true)) # ---------------------------------------------------------------------------- # Function: xnor # Arguments: Two boolean values # Returns: Returns value of 'not xor' # ---------------------------------------------------------------------------- xnor =$(__gmsl_tr2)$(if $1,$(if $2,$(true),$(false)),$(if $2,$(false),$(true))) # ########################################################################### # LIST MANIPULATION FUNCTIONS # ########################################################################### # ---------------------------------------------------------------------------- # Function: first (same as LISP's car, or head) # Arguments: 1: A list # Returns: Returns the first element of a list # ---------------------------------------------------------------------------- first = $(__gmsl_tr1)$(firstword $1) # ---------------------------------------------------------------------------- # Function: last # Arguments: 1: A list # Returns: Returns the last element of a list # ---------------------------------------------------------------------------- ifeq ($(__gmsl_have_lastword),$(true)) last = $(__gmsl_tr1)$(lastword $1) else last = $(__gmsl_tr1)$(if $1,$(word $(words $1),$1)) endif # ---------------------------------------------------------------------------- # Function: rest (same as LISP's cdr, or tail) # Arguments: 1: A list # Returns: Returns the list with the first element removed # ---------------------------------------------------------------------------- rest = $(__gmsl_tr1)$(wordlist 2,$(words $1),$1) # ---------------------------------------------------------------------------- # Function: chop # Arguments: 1: A list # Returns: Returns the list with the last element removed # ---------------------------------------------------------------------------- chop = $(__gmsl_tr1)$(wordlist 2,$(words $1),x $1) # ---------------------------------------------------------------------------- # Function: map # Arguments: 1: Name of function to $(call) for each element of list # 2: List to iterate over calling the function in 1 # Returns: The list after calling the function on each element # ---------------------------------------------------------------------------- map = $(__gmsl_tr2)$(strip $(foreach a,$2,$(call $1,$a))) # ---------------------------------------------------------------------------- # Function: pairmap # Arguments: 1: Name of function to $(call) for each pair of elements # 2: List to iterate over calling the function in 1 # 3: Second list to iterate over calling the function in 1 # Returns: The list after calling the function on each pair of elements # ---------------------------------------------------------------------------- pairmap = $(strip $(__gmsl_tr3)\ $(if $2$3,$(call $1,$(call first,$2),$(call first,$3)) \ $(call pairmap,$1,$(call rest,$2),$(call rest,$3)))) # ---------------------------------------------------------------------------- # Function: leq # Arguments: 1: A list to compare against... # 2: ...this list # Returns: Returns $(true) if the two lists are identical # ---------------------------------------------------------------------------- leq = $(__gmsl_tr2)$(strip $(if $(call seq,$(words $1),$(words $2)), \ $(call __gmsl_list_equal,$1,$2),$(false))) __gmsl_list_equal = $(if $(strip $1), \ $(if $(call seq,$(call first,$1),$(call first,$2)), \ $(call __gmsl_list_equal, \ $(call rest,$1), \ $(call rest,$2)), \ $(false)), \ $(true)) # ---------------------------------------------------------------------------- # Function: lne # Arguments: 1: A list to compare against... # 2: ...this list # Returns: Returns $(true) if the two lists are different # ---------------------------------------------------------------------------- lne = $(__gmsl_tr2)$(call not,$(call leq,$1,$2)) # ---------------------------------------------------------------------------- # Function: reverse # Arguments: 1: A list to reverse # Returns: The list with its elements in reverse order # ---------------------------------------------------------------------------- reverse =$(__gmsl_tr1)$(strip $(if $1,$(call reverse,$(call rest,$1)) \ $(call first,$1))) # ---------------------------------------------------------------------------- # Function: uniq # Arguments: 1: A list from which to remove repeated elements # Returns: The list with duplicate elements removed without reordering # ---------------------------------------------------------------------------- uniq = $(strip $(__gmsl_tr1) $(if $1,$(firstword $1) \ $(call uniq,$(filter-out $(firstword $1),$1)))) # ---------------------------------------------------------------------------- # Function: length # Arguments: 1: A list # Returns: The number of elements in the list # ---------------------------------------------------------------------------- length = $(__gmsl_tr1)$(words $1) # ########################################################################### # STRING MANIPULATION FUNCTIONS # ########################################################################### # Helper function that translates any GNU Make 'true' value (i.e. a # non-empty string) to our $(true) __gmsl_make_bool = $(if $(strip $1),$(true),$(false)) # ---------------------------------------------------------------------------- # Function: seq # Arguments: 1: A string to compare against... # 2: ...this string # Returns: Returns $(true) if the two strings are identical # ---------------------------------------------------------------------------- seq = $(__gmsl_tr2)$(if $(subst x$1,,x$2)$(subst x$2,,x$1),$(false),$(true)) # ---------------------------------------------------------------------------- # Function: sne # Arguments: 1: A string to compare against... # 2: ...this string # Returns: Returns $(true) if the two strings are not the same # ---------------------------------------------------------------------------- sne = $(__gmsl_tr2)$(call not,$(call seq,$1,$2)) # ---------------------------------------------------------------------------- # Function: split # Arguments: 1: The character to split on # 2: A string to split # Returns: Splits a string into a list separated by spaces at the split # character in the first argument # ---------------------------------------------------------------------------- split = $(__gmsl_tr2)$(strip $(subst $1, ,$2)) # ---------------------------------------------------------------------------- # Function: merge # Arguments: 1: The character to put between fields # 2: A list to merge into a string # Returns: Merges a list into a single string, list elements are separated # by the character in the first argument # ---------------------------------------------------------------------------- merge = $(__gmsl_tr2)$(strip $(if $2, \ $(if $(call seq,1,$(words $2)), \ $2,$(call first,$2)$1$(call merge,$1,$(call rest,$2))))) ifdef __gmsl_have_eval # ---------------------------------------------------------------------------- # Function: tr # Arguments: 1: The list of characters to translate from # 2: The list of characters to translate to # 3: The text to translate # Returns: Returns the text after translating characters # ---------------------------------------------------------------------------- tr = $(strip $(__gmsl_tr3)$(call assert_no_dollar,$0,$1$2$3) \ $(eval __gmsl_t := $3) \ $(foreach c, \ $(join $(addsuffix :,$1),$2), \ $(eval __gmsl_t := \ $(subst $(word 1,$(subst :, ,$c)),$(word 2,$(subst :, ,$c)), \ $(__gmsl_t))))$(__gmsl_t)) # Common character classes for use with the tr function. Each of # these is actually a variable declaration and must be wrapped with # $() or ${} to be used. [A-Z] := A B C D E F G H I J K L M N O P Q R S T U V W X Y Z # [a-z] := a b c d e f g h i j k l m n o p q r s t u v w x y z # [0-9] := 0 1 2 3 4 5 6 7 8 9 # [A-F] := A B C D E F # # ---------------------------------------------------------------------------- # Function: uc # Arguments: 1: Text to upper case # Returns: Returns the text in upper case # ---------------------------------------------------------------------------- uc = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(call tr,$([a-z]),$([A-Z]),$1) # ---------------------------------------------------------------------------- # Function: lc # Arguments: 1: Text to lower case # Returns: Returns the text in lower case # ---------------------------------------------------------------------------- lc = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(call tr,$([A-Z]),$([a-z]),$1) # ---------------------------------------------------------------------------- # Function: strlen # Arguments: 1: A string # Returns: Returns the length of the string # ---------------------------------------------------------------------------- # This results in __gmsl_tab containing a tab __gmsl_tab := # __gmsl_characters := A B C D E F G H I J K L M N O P Q R S T U V W X Y Z __gmsl_characters += a b c d e f g h i j k l m n o p q r s t u v w x y z __gmsl_characters += 0 1 2 3 4 5 6 7 8 9 __gmsl_characters += ` ~ ! @ \# $$ % ^ & * ( ) - _ = + __gmsl_characters += { } [ ] \ : ; ' " < > , . / ? | # This results in __gmsl_space containing just a space __gmsl_space := __gmsl_space += strlen = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(strip $(eval __temp := $(subst $(__gmsl_space),x,$1))$(foreach a,$(__gmsl_characters),$(eval __temp := $$(subst $$a,x,$(__temp))))$(eval __temp := $(subst x,x ,$(__temp)))$(words $(__temp))) # This results in __gmsl_newline containing just a newline define __gmsl_newline endef # ---------------------------------------------------------------------------- # Function: substr # Arguments: 1: A string # 2: Start position (first character is 1) # 3: End position (inclusive) # Returns: A substring. # Note: The string in $1 must not contain a § # ---------------------------------------------------------------------------- substr = $(if $2,$(__gmsl_tr3)$(call assert_no_dollar,$0,$1$2$3)$(strip $(eval __temp := $$(subst $$(__gmsl_space),§ ,$$1))$(foreach a,$(__gmsl_characters),$(eval __temp := $$(subst $$a,$$a$$(__gmsl_space),$(__temp))))$(eval __temp := $(wordlist $2,$3,$(__temp))))$(subst §,$(__gmsl_space),$(subst $(__gmsl_space),,$(__temp)))) endif # __gmsl_have_eval # ########################################################################### # SET MANIPULATION FUNCTIONS # ########################################################################### # Sets are represented by sorted, deduplicated lists. To create a set # from a list use set_create, or start with the empty_set and # set_insert individual elements # This is the empty set empty_set := # ---------------------------------------------------------------------------- # Function: set_create # Arguments: 1: A list of set elements # Returns: Returns the newly created set # ---------------------------------------------------------------------------- set_create = $(__gmsl_tr1)$(sort $1) # ---------------------------------------------------------------------------- # Function: set_insert # Arguments: 1: A single element to add to a set # 2: A set # Returns: Returns the set with the element added # ---------------------------------------------------------------------------- set_insert = $(__gmsl_tr2)$(sort $1 $2) # ---------------------------------------------------------------------------- # Function: set_remove # Arguments: 1: A single element to remove from a set # 2: A set # Returns: Returns the set with the element removed # ---------------------------------------------------------------------------- set_remove = $(__gmsl_tr2)$(filter-out $1,$2) # ---------------------------------------------------------------------------- # Function: set_is_member, set_is_not_member # Arguments: 1: A single element # 2: A set # Returns: (set_is_member) Returns $(true) if the element is in the set # (set_is_not_member) Returns $(false) if the element is in the set # ---------------------------------------------------------------------------- set_is_member = $(__gmsl_tr2)$(if $(filter $1,$2),$(true),$(false)) set_is_not_member = $(__gmsl_tr2)$(if $(filter $1,$2),$(false),$(true)) # ---------------------------------------------------------------------------- # Function: set_union # Arguments: 1: A set # 2: Another set # Returns: Returns the union of the two sets # ---------------------------------------------------------------------------- set_union = $(__gmsl_tr2)$(sort $1 $2) # ---------------------------------------------------------------------------- # Function: set_intersection # Arguments: 1: A set # 2: Another set # Returns: Returns the intersection of the two sets # ---------------------------------------------------------------------------- set_intersection = $(__gmsl_tr2)$(filter $1,$2) # ---------------------------------------------------------------------------- # Function: set_is_subset # Arguments: 1: A set # 2: Another set # Returns: Returns $(true) if the first set is a subset of the second # ---------------------------------------------------------------------------- set_is_subset = $(__gmsl_tr2)$(call set_equal,$(call set_intersection,$1,$2),$1) # ---------------------------------------------------------------------------- # Function: set_equal # Arguments: 1: A set # 2: Another set # Returns: Returns $(true) if the two sets are identical # ---------------------------------------------------------------------------- set_equal = $(__gmsl_tr2)$(call seq,$1,$2) # ########################################################################### # ARITHMETIC LIBRARY # ########################################################################### # Integers a represented by lists with the equivalent number of x's. # For example the number 4 is x x x x. # ---------------------------------------------------------------------------- # Function: int_decode # Arguments: 1: A number of x's representation # Returns: Returns the integer for human consumption that is represented # by the string of x's # ---------------------------------------------------------------------------- int_decode = $(__gmsl_tr1)$(words $1) # ---------------------------------------------------------------------------- # Function: int_encode # Arguments: 1: A number in human-readable integer form # Returns: Returns the integer encoded as a string of x's # ---------------------------------------------------------------------------- __int_encode = $(if $1,$(if $(call seq,$(words $(wordlist 1,$1,$2)),$1),$(wordlist 1,$1,$2),$(call __int_encode,$1,$(if $2,$2 $2,x)))) __strip_leading_zero = $(if $1,$(if $(call seq,$(patsubst 0%,%,$1),$1),$1,$(call __strip_leading_zero,$(patsubst 0%,%,$1))),0) int_encode = $(__gmsl_tr1)$(call __int_encode,$(call __strip_leading_zero,$1)) # The arithmetic library functions come in two forms: one form of each # function takes integers as arguments and the other form takes the # encoded form (x's created by a call to int_encode). For example, # there are two plus functions: # # plus Called with integer arguments and returns an integer # int_plus Called with encoded arguments and returns an encoded result # # plus will be slower than int_plus because its arguments and result # have to be translated between the x's format and integers. If doing # a complex calculation use the int_* forms with a single encoding of # inputs and single decoding of the output. For simple calculations # the direct forms can be used. # Helper function used to wrap an int_* function into a function that # takes a pair of integers, perhaps a function and returns an integer # result __gmsl_int_wrap = $(call int_decode,$(call $1,$(call int_encode,$2),$(call int_encode,$3))) __gmsl_int_wrap1 = $(call int_decode,$(call $1,$(call int_encode,$2))) __gmsl_int_wrap2 = $(call $1,$(call int_encode,$2),$(call int_encode,$3)) # ---------------------------------------------------------------------------- # Function: int_plus # Arguments: 1: A number in x's representation # 2: Another number in x's represntation # Returns: Returns the sum of the two numbers in x's representation # ---------------------------------------------------------------------------- int_plus = $(strip $(__gmsl_tr2)$1 $2) # ---------------------------------------------------------------------------- # Function: plus (wrapped version of int_plus) # Arguments: 1: An integer # 2: Another integer # Returns: Returns the sum of the two integers # ---------------------------------------------------------------------------- plus = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_plus,$1,$2) # ---------------------------------------------------------------------------- # Function: int_subtract # Arguments: 1: A number in x's representation # 2: Another number in x's represntation # Returns: Returns the difference of the two numbers in x's representation, # or outputs an error on a numeric underflow # ---------------------------------------------------------------------------- int_subtract = $(strip $(__gmsl_tr2)$(if $(call int_gte,$1,$2), \ $(filter-out xx,$(join $1,$2)), \ $(call __gmsl_warning,Subtraction underflow))) # ---------------------------------------------------------------------------- # Function: subtract (wrapped version of int_subtract) # Arguments: 1: An integer # 2: Another integer # Returns: Returns the difference of the two integers, # or outputs an error on a numeric underflow # ---------------------------------------------------------------------------- subtract = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_subtract,$1,$2) # ---------------------------------------------------------------------------- # Function: int_multiply # Arguments: 1: A number in x's representation # 2: Another number in x's represntation # Returns: Returns the product of the two numbers in x's representation # ---------------------------------------------------------------------------- int_multiply = $(strip $(__gmsl_tr2)$(foreach a,$1,$2)) # ---------------------------------------------------------------------------- # Function: multiply (wrapped version of int_multiply) # Arguments: 1: An integer # 2: Another integer # Returns: Returns the product of the two integers # ---------------------------------------------------------------------------- multiply = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_multiply,$1,$2) # ---------------------------------------------------------------------------- # Function: int_divide # Arguments: 1: A number in x's representation # 2: Another number in x's represntation # Returns: Returns the result of integer division of argument 1 divided # by argument 2 in x's representation # ---------------------------------------------------------------------------- int_divide = $(__gmsl_tr2)$(strip $(if $1,$(if $2, \ $(if $(call int_gte,$1,$2), \ x $(call int_divide,$(call int_subtract,$1,$2),$2),), \ $(call __gmsl_error,Division by zero)))) # ---------------------------------------------------------------------------- # Function: divide (wrapped version of int_divide) # Arguments: 1: An integer # 2: Another integer # Returns: Returns the integer division of the first argument by the second # ---------------------------------------------------------------------------- divide = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_divide,$1,$2) # ---------------------------------------------------------------------------- # Function: int_max, int_min # Arguments: 1: A number in x's representation # 2: Another number in x's represntation # Returns: Returns the maximum or minimum of its arguments in x's # representation # ---------------------------------------------------------------------------- int_max = $(__gmsl_tr2)$(subst xx,x,$(join $1,$2)) int_min = $(__gmsl_tr2)$(subst xx,x,$(filter xx,$(join $1,$2))) # ---------------------------------------------------------------------------- # Function: max, min # Arguments: 1: An integer # 2: Another integer # Returns: Returns the maximum or minimum of its integer arguments # ---------------------------------------------------------------------------- max = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_max,$1,$2) min = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_min,$1,$2) # ---------------------------------------------------------------------------- # Function: int_gt, int_gte, int_lt, int_lte, int_eq, int_ne # Arguments: Two x's representation numbers to be compared # Returns: $(true) or $(false) # # int_gt First argument greater than second argument # int_gte First argument greater than or equal to second argument # int_lt First argument less than second argument # int_lte First argument less than or equal to second argument # int_eq First argument is numerically equal to the second argument # int_ne First argument is not numerically equal to the second argument # ---------------------------------------------------------------------------- int_gt = $(__gmsl_tr2)$(call __gmsl_make_bool, \ $(filter-out $(words $2), \ $(words $(call int_max,$1,$2)))) int_gte = $(__gmsl_tr2)$(call __gmsl_make_bool, \ $(call int_gt,$1,$2)$(call int_eq,$1,$2)) int_lt = $(__gmsl_tr2)$(call __gmsl_make_bool, \ $(filter-out $(words $1), \ $(words $(call int_max,$1,$2)))) int_lte = $(__gmsl_tr2)$(call __gmsl_make_bool, \ $(call int_lt,$1,$2)$(call int_eq,$1,$2)) int_eq = $(__gmsl_tr2)$(call __gmsl_make_bool, \ $(filter $(words $1),$(words $2))) int_ne = $(__gmsl_tr2)$(call __gmsl_make_bool, \ $(filter-out $(words $1),$(words $2))) # ---------------------------------------------------------------------------- # Function: gt, gte, lt, lte, eq, ne # Arguments: Two integers to be compared # Returns: $(true) or $(false) # # gt First argument greater than second argument # gte First argument greater than or equal to second argument # lt First argument less than second argument # lte First argument less than or equal to second argument # eq First argument is numerically equal to the second argument # ne First argument is not numerically equal to the second argument # ---------------------------------------------------------------------------- gt = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_gt,$1,$2) gte = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_gte,$1,$2) lt = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_lt,$1,$2) lte = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_lte,$1,$2) eq = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_eq,$1,$2) ne = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_ne,$1,$2) # increment adds 1 to its argument, decrement subtracts 1. Note that # decrement does not range check and hence will not underflow, but # will incorrectly say that 0 - 1 = 0 # ---------------------------------------------------------------------------- # Function: int_inc # Arguments: 1: A number in x's representation # Returns: The number incremented by 1 in x's representation # ---------------------------------------------------------------------------- int_inc = $(strip $(__gmsl_tr1)$1 x) # ---------------------------------------------------------------------------- # Function: inc # Arguments: 1: An integer # Returns: The argument incremented by 1 # ---------------------------------------------------------------------------- inc = $(__gmsl_tr1)$(call __gmsl_int_wrap1,int_inc,$1) # ---------------------------------------------------------------------------- # Function: int_dec # Arguments: 1: A number in x's representation # Returns: The number decremented by 1 in x's representation # ---------------------------------------------------------------------------- int_dec = $(__gmsl_tr1)$(strip \ $(if $(call sne,0,$(words $1)), \ $(wordlist 2,$(words $1),$1))) # ---------------------------------------------------------------------------- # Function: dec # Arguments: 1: An integer # Returns: The argument decremented by 1 # ---------------------------------------------------------------------------- dec = $(__gmsl_tr1)$(call __gmsl_int_wrap1,int_dec,$1) # double doubles its argument, and halve halves it # ---------------------------------------------------------------------------- # Function: int_double # Arguments: 1: A number in x's representation # Returns: The number doubled (i.e. * 2) and returned in x's representation # ---------------------------------------------------------------------------- int_double = $(strip $(__gmsl_tr1)$1 $1) # ---------------------------------------------------------------------------- # Function: double # Arguments: 1: An integer # Returns: The integer times 2 # ---------------------------------------------------------------------------- double = $(__gmsl_tr1)$(call __gmsl_int_wrap1,int_double,$1) # ---------------------------------------------------------------------------- # Function: int_halve # Arguments: 1: A number in x's representation # Returns: The number halved (i.e. / 2) and returned in x's representation # ---------------------------------------------------------------------------- int_halve = $(__gmsl_tr1)$(strip $(subst xx,x,$(filter-out xy x y, \ $(join $1,$(foreach a,$1,y x))))) # ---------------------------------------------------------------------------- # Function: halve # Arguments: 1: An integer # Returns: The integer divided by 2 # ---------------------------------------------------------------------------- halve = $(__gmsl_tr1)$(call __gmsl_int_wrap1,int_halve,$1) # ---------------------------------------------------------------------------- # Function: sequence # Arguments: 1: An integer # 2: An integer # Returns: The sequence [arg1, arg2] of integers if arg1 < arg2 or # [arg2, arg1] if arg2 > arg1. If arg1 == arg1 return [arg1] # ---------------------------------------------------------------------------- sequence = $(__gmsl_tr2)$(strip $(if $(call lte,$1,$2), \ $(call __gmsl_sequence_up,$1,$2), \ $(call __gmsl_sequence_dn,$2,$1))) __gmsl_sequence_up = $(if $(call seq,$1,$2),$1,$1 $(call __gmsl_sequence_up,$(call inc,$1),$2)) __gmsl_sequence_dn = $(if $(call seq,$1,$2),$1,$2 $(call __gmsl_sequence_dn,$1,$(call dec,$2))) # ---------------------------------------------------------------------------- # Function: dec2hex, dec2bin, dec2oct # Arguments: 1: An integer # Returns: The decimal argument converted to hexadecimal, binary or # octal # ---------------------------------------------------------------------------- __gmsl_digit = $(subst 15,f,$(subst 14,e,$(subst 13,d,$(subst 12,c,$(subst 11,b,$(subst 10,a,$1)))))) dec2hex = $(call __gmsl_dec2base,$(call int_encode,$1),$(call int_encode,16)) dec2bin = $(call __gmsl_dec2base,$(call int_encode,$1),$(call int_encode,2)) dec2oct = $(call __gmsl_dec2base,$(call int_encode,$1),$(call int_encode,8)) __gmsl_base_divide = $(subst $2,X ,$1) __gmsl_q = $(strip $(filter X,$1)) __gmsl_r = $(words $(filter x,$1)) __gmsl_dec2base = $(eval __gmsl_temp := $(call __gmsl_base_divide,$1,$2))$(call __gmsl_dec2base_,$(call __gmsl_q,$(__gmsl_temp)),$(call __gmsl_r,$(__gmsl_temp)),$2) __gmsl_dec2base_ = $(if $1,$(call __gmsl_dec2base,$(subst X,x,$1),$3))$(call __gmsl_digit,$2) ifdef __gmsl_have_eval # ########################################################################### # ASSOCIATIVE ARRAYS # ########################################################################### # Magic string that is very unlikely to appear in a key or value __gmsl_aa_magic := faf192c8efbc25c27992c5bc5add390393d583c6 # ---------------------------------------------------------------------------- # Function: set # Arguments: 1: Name of associative array # 2: The key value to associate # 3: The value associated with the key # Returns: Nothing # ---------------------------------------------------------------------------- set = $(__gmsl_tr3)$(call assert_no_space,$0,$1$2)$(call assert_no_dollar,$0,$1$2$3)$(eval __gmsl_aa_$1_$(__gmsl_aa_magic)_$2_gmsl_aa_$1 := $3) # Only used internally by memoize function __gmsl_set = $(call set,$1,$2,$3)$3 # ---------------------------------------------------------------------------- # Function: get # Arguments: 1: Name of associative array # 2: The key to retrieve # Returns: The value stored in the array for that key # ---------------------------------------------------------------------------- get = $(strip $(__gmsl_tr2)$(call assert_no_space,$0,$1$2)$(call assert_no_dollar,$0,$1$2)$(__gmsl_aa_$1_$(__gmsl_aa_magic)_$2_gmsl_aa_$1)) # ---------------------------------------------------------------------------- # Function: keys # Arguments: 1: Name of associative array # Returns: Returns a list of all defined keys in the array # ---------------------------------------------------------------------------- keys = $(__gmsl_tr1)$(call assert_no_space,$0,$1)$(call assert_no_dollar,$0,$1)$(sort $(patsubst __gmsl_aa_$1_$(__gmsl_aa_magic)_%_gmsl_aa_$1,%, \ $(filter __gmsl_aa_$1_$(__gmsl_aa_magic)_%_gmsl_aa_$1,$(.VARIABLES)))) # ---------------------------------------------------------------------------- # Function: defined # Arguments: 1: Name of associative array # 2: The key to test # Returns: Returns true if the key is defined (i.e. not empty) # ---------------------------------------------------------------------------- defined = $(__gmsl_tr2)$(call assert_no_space,$0,$1$2)$(call assert_no_dollar,$0,$1$2)$(call sne,$(call get,$1,$2),) endif # __gmsl_have_eval ifdef __gmsl_have_eval # ########################################################################### # NAMED STACKS # ########################################################################### # ---------------------------------------------------------------------------- # Function: push # Arguments: 1: Name of stack # 2: Value to push onto the top of the stack (must not contain # a space) # Returns: None # ---------------------------------------------------------------------------- push = $(__gmsl_tr2)$(call assert_no_space,$0,$1$2)$(call assert_no_dollar,$0,$1$2)$(eval __gmsl_stack_$1 := $2 $(if $(filter-out undefined,\ $(origin __gmsl_stack_$1)),$(__gmsl_stack_$1))) # ---------------------------------------------------------------------------- # Function: pop # Arguments: 1: Name of stack # Returns: Top element from the stack after removing it # ---------------------------------------------------------------------------- pop = $(__gmsl_tr1)$(call assert_no_space,$0,$1)$(call assert_no_dollar,$0,$1)$(strip $(if $(filter-out undefined,$(origin __gmsl_stack_$1)), \ $(call first,$(__gmsl_stack_$1)) \ $(eval __gmsl_stack_$1 := $(call rest,$(__gmsl_stack_$1))))) # ---------------------------------------------------------------------------- # Function: peek # Arguments: 1: Name of stack # Returns: Top element from the stack without removing it # ---------------------------------------------------------------------------- peek = $(__gmsl_tr1)$(call assert_no_space,$0,$1)$(call assert_no_dollar,$0,$1)$(call first,$(__gmsl_stack_$1)) # ---------------------------------------------------------------------------- # Function: depth # Arguments: 1: Name of stack # Returns: Number of items on the stack # ---------------------------------------------------------------------------- depth = $(__gmsl_tr1)$(call assert_no_space,$0,$1)$(call assert_no_dollar,$0,$1)$(words $(__gmsl_stack_$1)) endif # __gmsl_have_eval ifdef __gmsl_have_eval # ########################################################################### # STRING CACHE # ########################################################################### # ---------------------------------------------------------------------------- # Function: memoize # Arguments: 1. Name of the function to be called if the string # has not been previously seen # 2. A string # Returns: Returns the result of a memo function (which the user must # define) on the passed in string and remembers the result. # # Example: Set memo = $(shell echo "$1" | md5sum) to make a cache # of MD5 hashes of strings. $(call memoize,memo,foo bar baz) # ---------------------------------------------------------------------------- __gmsl_memoize = $(subst $(__gmsl_space),§,$1)cc2af1bb7c4482f2ba75e338b963d3e7$(subst $(__gmsl_space),§,$2) memoize = $(__gmsl_tr2)$(strip $(if $(call defined,__gmsl_m,$(__gmsl_memoize)),\ $(call get,__gmsl_m,$(__gmsl_memoize)), \ $(call __gmsl_set,__gmsl_m,$(__gmsl_memoize),$(call $1,$2)))) endif # __gmsl_have_eval # ########################################################################### # DEBUGGING FACILITIES # ########################################################################### # ---------------------------------------------------------------------------- # Target: gmsl-print-% # Arguments: The % should be replaced by the name of a variable that you # wish to print out. # Action: Echos the name of the variable that matches the % and its value. # For example, 'make gmsl-print-SHELL' will output the value of # the SHELL variable # ---------------------------------------------------------------------------- gmsl-print-%: ; @echo $* = $($*) # ---------------------------------------------------------------------------- # Function: assert # Arguments: 1: A boolean that must be true or the assertion will fail # 2: The message to print with the assertion # Returns: None # ---------------------------------------------------------------------------- assert = $(if $2,$(if $1,,$(call __gmsl_error,Assertion failure: $2))) # ---------------------------------------------------------------------------- # Function: assert_exists # Arguments: 1: Name of file that must exist, if it is missing an assertion # will be generated # Returns: None # ---------------------------------------------------------------------------- assert_exists = $(if $0,$(call assert,$(wildcard $1),file '$1' missing)) # ---------------------------------------------------------------------------- # Function: assert_no_dollar # Arguments: 1: Name of a function being executd # 2: Arguments to check # Returns: None # ---------------------------------------------------------------------------- assert_no_dollar = $(call __gmsl_tr2)$(call assert,$(call not,$(findstring $(__gmsl_dollar),$2)),$1 called with a dollar sign in argument) # ---------------------------------------------------------------------------- # Function: assert_no_space # Arguments: 1: Name of a function being executd # 2: Arguments to check # Returns: None # ---------------------------------------------------------------------------- ifeq ($(__gmsl_spaced_vars),$(false)) assert_no_space = $(call assert,$(call not,$(findstring $(__gmsl_aa_magic),$(subst $(__gmsl_space),$(__gmsl_aa_magic),$2))),$1 called with a space in argument) else assert_no_space = endif gmsl-1.1.7/index.html0000644000175000017500000007220712446002551012556 0ustar jgcjgc GNU Make Standard Library

GNU Make Standard Library

The GNU Make Standard Library (GMSL) is a collection of functions implemented using native GNU Make functionality that provide list and string manipulation, integer arithmetic, associative arrays, stacks, and debugging facilities.  The GMSL is released under the BSD License.

[Project Page] [Download] [Discussion Forum]

Using GMSL

The two files needed are gmsl and __gmsl.  To include the GMSL in your Makefile do
include gmsl
gmsl automatically includes __gmsl.  To check that you have the right version of gmsl use the gmsl_compatible function (see below). The current version is 1 1 6.

The GMSL package also includes a test suite for GMSL.  Just run make -f gmsl-tests.

Logical Operators

GMSL has boolean $(true) (a non-empty string) and $(false) (an empty string).  The following operators can be used with those variables.


not

Arguments: A boolean value
Returns:   Returns $(true) if the boolean is $(false) and vice versa

and

Arguments: Two boolean values
Returns:   Returns $(true) if both of the booleans are true

or

Arguments: Two boolean values
Returns:   Returns $(true) if either of the booleans is true

xor

Arguments: Two boolean values
Returns:   Returns $(true) if exactly one of the booleans is true

nand

Arguments: Two boolean values
Returns:   Returns value of 'not and'

nor

Arguments: Two boolean values
Returns:   Returns value of 'not or'

xnor

Arguments: Two boolean values
Returns:   Returns value of 'not xor'

List Manipulation Functions

 A list is a string of characters; the list separator is a space.


first

Arguments: 1: A list
Returns:   Returns the first element of a list

last

Arguments: 1: A list
Returns:   Returns the last element of a list

rest

Arguments: 1: A list
Returns:   Returns the list with the first element removed

chop

Arguments: 1: A list
Returns:   Returns the list with the last element removed

map

Arguments: 1: Name of function to $(call) for each element of list
           2: List to iterate over calling the function in 1
Returns:   The list after calling the function on each element

pairmap

Arguments: 1: Name of function to $(call) for each pair of elements
           2: List to iterate over calling the function in 1
           3: Second list to iterate over calling the function in 1
Returns:   The list after calling the function on each pair of elements

leq

Arguments: 1: A list to compare against...
           2: ...this list
Returns:   Returns $(true) if the two lists are identical

lne

Arguments: 1: A list to compare against...
           2: ...this list
Returns:   Returns $(true) if the two lists are different

reverse

Arguments: 1: A list to reverse
Returns:   The list with its elements in reverse order

uniq

Arguments: 1: A list to deduplicate
Returns:   The list with elements in order without duplicates

length

Arguments: 1: A list
Returns:   The number of elements in the list

String Manipulation Functions

A string is any sequence of characters.


seq

Arguments: 1: A string to compare against...
           2: ...this string
Returns:   Returns $(true) if the two strings are identical

sne

Arguments: 1: A string to compare against...
           2: ...this string
Returns:   Returns $(true) if the two strings are not the same

strlen

Arguments: 1: A string
Returns:   Returns the length of the string

substr

Arguments: 1: A string
           2: Start offset (first character is 1)
           3: Ending offset (inclusive)
Returns:   Returns a substring

split

Arguments: 1: The character to split on
           2: A string to split
Returns:   Splits a string into a list separated by spaces at the split
           character in the first argument

merge

Arguments: 1: The character to put between fields
           2: A list to merge into a string
Returns:   Merges a list into a single string, list elements are separated
           by the character in the first argument

tr

Arguments: 1: The list of characters to translate from
           2: The list of characters to translate to
           3: The text to translate
Returns:   Returns the text after translating characters

uc

Arguments: 1: Text to upper case
Returns:   Returns the text in upper case

lc

Arguments: 1: Text to lower case
Returns:   Returns the text in lower case

Set Manipulation Functions

Sets are represented by sorted, deduplicated lists. To create a set from a list use set_create, or start with the empty_set and set_insert individual elements. The empty set is defined as empty_set.


set_create

Arguments: 1: A list of set elements
Returns:   Returns the newly created set

set_insert

Arguments: 1: A single element to add to a set
           2: A set
Returns:   Returns the set with the element added

set_remove

Arguments: 1: A single element to remove from a set
           2: A set
Returns:   Returns the set with the element removed

set_is_member

Arguments: 1: A single element
           2: A set
Returns:   Returns $(true) if the element is in the set

set_is_not_member

Arguments: 1: A single element
           2: A set
Returns:   Returns $(false) if the element is in the set

set_union

Arguments: 1: A set
           2: Another set
Returns:   Returns the union of the two sets

set_intersection

Arguments: 1: A set
           2: Another set
Returns:   Returns the intersection of the two sets

set_is_subset

Arguments: 1: A set
           2: Another set
Returns:   Returns $(true) if the first set is a subset of the second

set_equal

Arguments: 1: A set
           2: Another set
Returns:   Returns $(true) if the two sets are identical

Integer Arithmetic Functions

Integers are represented by lists with the equivalent number of x's.  For example the number 4 is x x x x.  The maximum integer that the library can handle as input (i.e. as the argument to a call to int_encode) is 65536. There is no limit on integer size for internal computations or output.

The arithmetic library functions come in two forms: one form of each function takes integers as arguments and the other form takes the encoded form (x's created by a call to int_encode).  For example, there are two plus functions: plus (called with integer arguments and returns an integer) and int_plus (called with encoded arguments and returns an encoded result).

plus will be slower than int_plus because its arguments and result have to be translated between the x's format and integers.  If doing a complex calculation use the int_* forms with a single encoding of inputs and single decoding of the output.  For simple calculations the direct forms can be used.


int_decode

Arguments: 1: A number of x's representation
Returns:   Returns the integer for human consumption that is represented
           by the string of x's

int_encode

Arguments: 1: A number in human-readable integer form
Returns:   Returns the integer encoded as a string of x's

int_plus

Arguments: 1: A number in x's representation
           2: Another number in x's represntation
Returns:   Returns the sum of the two numbers in x's representation

plus (wrapped version of int_plus)

Arguments: 1: An integer
           2: Another integer
Returns:   Returns the sum of the two integers

int_subtract

Arguments: 1: A number in x's representation
           2: Another number in x's represntation
Returns:   Returns the difference of the two numbers in x's representation,
           or outputs an error on a numeric underflow

subtract (wrapped version of int_subtract)

Arguments: 1: An integer
           2: Another integer
Returns:   Returns the difference of the two integers,
           or outputs an error on a numeric underflow

int_multiply

Arguments: 1: A number in x's representation
           2: Another number in x's represntation
Returns:   Returns the product of the two numbers in x's representation

multiply (wrapped version of int_multiply)

Arguments: 1: An integer
           2: Another integer
Returns:   Returns the product of the two integers

int_divide

Arguments: 1: A number in x's representation
           2: Another number in x's represntation
Returns:   Returns the result of integer division of argument 1 divided
           by argument 2 in x's representation

divide (wrapped version of int_divide)

Arguments: 1: An integer
           2: Another integer
Returns:   Returns the integer division of the first argument by the second

int_max, int_min

Arguments: 1: A number in x's representation
           2: Another number in x's represntation
Returns:   Returns the maximum or minimum of its arguments in x's
           representation

max, min

Arguments: 1: An integer
           2: Another integer
Returns:   Returns the maximum or minimum of its integer arguments

int_gt, int_gte, int_lt, int_lte, int_eq, int_ne

Arguments: Two x's representation numbers to be compared
Returns:   $(true) or $(false)

int_gt First argument greater than second argument
int_gte First argument greater than or equal to second argument
int_lt First argument less than second argument
int_lte First argument less than or equal to second argument
int_eq First argument is numerically equal to the second argument
int_ne First argument is not numerically equal to the second argument

gt, gte, lt, lte, eq, ne

Arguments: Two integers to be compared
Returns:   $(true) or $(false)

gt First argument greater than second argument
gte First argument greater than or equal to second argument
lt First argument less than second argument
lte First argument less than or equal to second argument
eq First argument is numerically equal to the second argument
ne First argument is not numerically equal to the second argument
increment adds 1 to its argument, decrement subtracts 1. Note that
decrement does not range check and hence will not underflow, but
will incorrectly say that 0 - 1 = 0

int_inc

Arguments: 1: A number in x's representation
Returns:   The number incremented by 1 in x's representation

inc

Arguments: 1: An integer
Returns:   The argument incremented by 1

int_dec

Arguments: 1: A number in x's representation
Returns:   The number decremented by 1 in x's representation

dec

Arguments: 1: An integer
Returns:   The argument decremented by 1

int_double

Arguments: 1: A number in x's representation
Returns:   The number doubled (i.e. * 2) and returned in x's representation

double

Arguments: 1: An integer
Returns:   The integer times 2

int_halve

Arguments: 1: A number in x's representation
Returns:   The number halved (i.e. / 2) and returned in x's representation

halve

Arguments: 1: An integer
Returns:   The integer divided by 2

sequence

Arguments: 1: An integer
           2: An integer
Returns:   The sequence [arg1 arg2] if arg1 >= arg2 or [arg2 arg1] if arg2 > arg1

dec2hex, dec2bin, dec2oct

Arguments: 1: An integer
Returns:   The decimal argument converted to hexadecimal, binary or octal

Associative Arrays

An associate array maps a key value (a string with no spaces in it) to a single value (any string).   


set

Arguments: 1: Name of associative array
           2: The key value to associate
           3: The value associated with the key
Returns:   Nothing

get

Arguments: 1: Name of associative array
           2: The key to retrieve
Returns:   The value stored in the array for that key

keys

Arguments: 1: Name of associative array
Returns:   Returns a list of all defined keys in the array

defined

Arguments: 1: Name of associative array
           2: The key to test
Returns:   Returns true if the key is defined (i.e. not empty)

Named Stacks

A stack is an ordered list of strings (with no spaces in them).


push

Arguments: 1: Name of stack
           2: Value to push onto the top of the stack (must not contain
           a space)
Returns:   None

pop

Arguments: 1: Name of stack
Returns:   Top element from the stack after removing it

peek

Arguments: 1: Name of stack
Returns:   Top element from the stack without removing it

depth

Arguments: 1: Name of stack
Returns:   Number of items on the stack

Function memoization

To reduce the number of calls to slow functions (such as $(shell) a single memoization function is provided.


memoize

Arguments: 1: Name of function to memoize
           2: String argument for the function
Returns:   Result of $1 applied to $2 but only calls $1 once for each unique $2

Miscellaneous and Debugging Facilities

GMSL defines the following constants; all are accessed as normal GNU Make variables by wrapping them in $() or ${}.

Constant
Value
Purpose
true
T
Boolean for $(if) and return from  GMSL functions
false

Boolean for $(if) and return from GMSL functions
gmsl_version
1 0 0
GMSL version number as list: major minor revision

gmsl_compatible


Arguments: List containing the desired library version number (maj min rev)
Returns:   $(true) if this version of the library is compatible
           with the requested version number, otherwise $(false)
gmsl-print-% (target not a function)

Arguments: The % should be replaced by the name of a variable that you
           wish to print out.
Action:    Echos the name of the variable that matches the % and its value.
           For example, 'make gmsl-print-SHELL' will output the value of
           the SHELL variable

assert

Arguments: 1: A boolean that must be true or the assertion will fail
           2: The message to print with the assertion
Returns:   None

assert_exists

Arguments: 1: Name of file that must exist, if it is missing an assertion
           will be generated
Returns:   None


GMSL has a number of environment variables (or command-line overrides) that control various bits of functionality:

Variable
Purpose
GMSL_NO_WARNINGS
If set prevents GMSL from outputting warning messages: artithmetic functions generate underflow warnings.
GMSL_NO_ERRORS
If set prevents GMSL from generating fatal errors: division by zero or failed assertions are fatal.
GMSL_TRACE
Enables function tracing.  Calls to GMSL functions will result in name and arguments being traced.


Copyright (c) 2005-2014 John Graham-Cumming.

John Graham-Cumming's work on this project was sponsored by Electric Cloud, Inc.

SourceForge.net Logo