*! version 2.1.0 11nov2019 daniel klein program which_version // , sclass version 11.2 syntax anything(everything) [ , FIRSTVERSion ASSERTVERSion(string asis) ] gettoken fname invalid : anything , quotes if (`"`invalid'"' != "") { display as err `"invalid `invalid'"' exit 198 } mata : which_version() end version 11.2 local re "^(v|v\.)?[0-9]+\.[0-9]+(\.[0-9]+)?(\.[0-9]+)?$" local ro "(>=|<=|>|<|==|!=|~=)" mata : mata set matastrict on void which_version() { string scalar opt_reqvv, fname, vv real scalar opt_first, rc if ((opt_reqvv=st_local("assertversion")) != "") parse_reqvv(opt_reqvv) if (pathsuffix((fname=st_local("fname"))) == "") fname = (fname+".ado") opt_first = (st_local("firstversion") == "firstversion") pragma unset vv if ((fname=findfile(fname)) != "") readfile(fname, opt_first, vv) else if ( (rc=_stata("which " + st_local("fname"))) ) exit(rc) if (vv == "") printf("{%s}unknown version\n", (opt_reqvv=="") ? "txt" : "err") st_global("s(version)", vv) st_global("s(fn)", fname) if (opt_reqvv != "") assert_version(opt_reqvv, vv) } void parse_reqvv(string scalar opt_reqvv, | transmorphic matrix relop, transmorphic matrix reqvv) { if ( regexm((reqvv=strtrim(opt_reqvv)), "^`ro'(.*)$") ) { relop = regexs(1) reqvv = strtrim(regexs(2)) } if ( regexm(reqvv, "`re'") ) if ( regexm(reqvv, "^[0-9]") ) return errprintf("option assertversion() invald\n") exit(198) } void readfile(string scalar fname, real scalar opt_first, string scalar vv) { real scalar fh, brk string scalar line if ( (fh=_fopen(fname, "r")) ) exit( error(-fh) ) brk = setbreakintr(0) printf("{txt}%s\n", fname) while ((line=_fget(fh)) != J(0, 0, "")) { if (substr(line, 1, 2) != "*!") continue else printf("{res}%s{txt}\n", line) if ((vv!="") & opt_first) continue else readline(line, vv) } (void) _fclose(fh) (void) setbreakintr(brk) } void readline(string scalar line, string scalar vv) { string rowvector _line _line = strlower(substr(subinstr(line, char(9), char(32)), 3, .)) if ( !cols((_line=tokens(_line, " ,:;"))) ) return if ( !cols((_line=select(_line, regexm(_line, "`re'")))) ) return readversion(subinstr(subinstr(_line[1], "v.", ""), "v", ""), vv) } void readversion(string scalar _vv, string scalar vv) { string scalar _vv4, vv4 if (vv != "") { align_v4((_vv4=_vv), (vv4=vv)) if (vv4 >= _vv4) return } vv = _vv } void align_v4(string rowvector _vv, string rowvector vv) { string rowvector _vv4, vv4 real scalar i _vv4 = convert_v4(_vv) vv4 = convert_v4( vv) _vv4 = ((strlen( vv4)-strlen(_vv4)):*"0" + _vv4) vv4 = ((strlen(_vv4)-strlen( vv4)):*"0" + vv4) for (i=2; i<=cols(_vv4); ++i) { _vv4[1] = (_vv4[1] + _vv4[i]) vv4[1] = ( vv4[1] + vv4[i]) } _vv = _vv4[1] vv = vv4[1] } string rowvector convert_v4(string scalar v) { string rowvector v4 v4 = tokens(v, ".") return( (v4, J(1, (7-cols(v4))/2, (".", "0"))) ) } void assert_version(string scalar opt_reqvv, string scalar vv) { string scalar relop, reqvv if (vv == "") exit(6) pragma unset reqvv parse_reqvv(opt_reqvv, (relop="=="), reqvv) align_v4(reqvv, vv) if ( _stata(sprintf(`"assert "%s" %s "%s""', vv, relop, reqvv)) ) exit(9) } end exit /* --------------------------------------- 2.1.0 11nov2019 new option assertversion() 2.0.0 23oct2019 improved regular expression matching rewrite Mata subroutines 1.0.0 17oct2019 initial release on SSC