diff --git a/CHANGELOG.md b/CHANGELOG.md index 883bf0a..29f3c4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## v0.9.20 +- Parameterized goals [#115](https://github.com/xonixx/makesure/issues/115). +- Fixes and refactorings. + ## v0.9.19 - Minor fixes to `@reached_if` in [#113](https://github.com/xonixx/makesure/issues/113) - Minor fixes to `@lib` in [#111](https://github.com/xonixx/makesure/issues/111) diff --git a/Makesurefile b/Makesurefile index 8c50a89..ea23ffc 100644 --- a/Makesurefile +++ b/Makesurefile @@ -1,7 +1,7 @@ # vim: syntax=bash @options timing -@define NEXT_VERSION='0.9.19' +@define NEXT_VERSION='0.9.20' @define GOAWK_VERSION='1.21.0' @define JUST_VERSION='1.3.0' @define GOAWK="goawk$GOAWK_VERSION" diff --git a/README.md b/README.md index d2be778..46f2a29 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ By default, all scripts inside goals are executed with `bash`. If you want to us ``` $ ./makesure -h -makesure ver. 0.9.19 +makesure ver. 0.9.20 Usage: makesure [options...] [-f buildfile] [goals...] -f,--file buildfile set buildfile to use (default Makesurefile) diff --git a/makesure b/makesure index 31615f4..5d19851 100755 --- a/makesure +++ b/makesure @@ -1,59 +1,55 @@ #!/bin/sh if command -v gawk >/dev/null;then makesure_awk='gawk -ltime -v Gawk=1';makesure_pre='';else makesure_awk=awk;makesure_pre='function gettimeofday(){}';fi -exec $makesure_awk -v "Version=0.9.19" -v "Prog=$0" "$makesure_pre"' +exec $makesure_awk -v "Version=0.9.20" -v "Prog=$0" "$makesure_pre"' BEGIN { - Shell = "bash" + Shell="bash" SupportedShells["bash"] SupportedShells["sh"] SupportedOptions["tracing"] SupportedOptions["silent"] SupportedOptions["timing"] DefinesCode="" - GlobCnt = 0 - GlobGoalName = "" - Mode = "prelude" + GlobCnt=0 + GlobGoalName="" + Mode="prelude" srand() prepareArgs() - MyDirScript = "MYDIR=" quoteArg(getMyDir(ARGV[1])) ";export MYDIR;cd \"$MYDIR\"" + MyDirScript="MYDIR=" quoteArg(getMyDir(ARGV[1]))";export MYDIR;cd \"$MYDIR\"" Error="" - makesure() -} -function makesure() { - while (getline > 0) { + makesure()} +function makesure(i){ + while(getline>0){ Lines[NR]=$0 - if ($1 ~ /^@/ && "@define" != $1 && "@reached_if" != $1) reparseCli() - if ("@options" == $1) handleOptions() - else if ("@define" == $1) handleDefine() - else if ("@shell" == $1) handleShell() - else if ("@goal" == $1) { if ("@glob" == $2 || "@glob" == $3) handleGoalGlob(); else handleGoal() } - else if ("@doc" == $1) handleDoc() - else if ("@depends_on" == $1) handleDependsOn() - else if ("@reached_if" == $1) handleReachedIf() - else if ("@lib" == $1) handleLib() - else if ("@use_lib" == $1) handleUseLib() - else if ($1 ~ /^@/) addError("Unknown directive: " $1) + if($1~/^@/&&"@define"!=$1&&"@reached_if"!=$1)reparseCli() + if("@options"==$1)handleOptions() + else if("@define"==$1)handleDefine() + else if("@shell"==$1)handleShell() + else if("@goal"==$1){if("@glob"==$2||"@glob"==$3)handleGoalGlob();else handleGoal()} + else if("@doc"==$1)handleDoc() + else if("@depends_on"==$1)handleDependsOn() + else if("@reached_if"==$1)handleReachedIf() + else if("@lib"==$1)handleLib() + else if("@use_lib"==$1)handleUseLib() + else if($1~/^@/)addError("Unknown directive: " $1) else handleCodeLine($0) - } + for(i=1;i<10;i++)$i=""} doWork() - realExit(0) -} -function prepareArgs( i,arg) { - for (i = 2; i < ARGC; i++) { - arg = ARGV[i] - if (substr(arg,1,1) == "-") { - if (arg == "-f" || arg == "--file") { + realExit(0)} +function prepareArgs(i,arg){ + for(i=2;i2)addError("nothing allowed after goal name")} +function validateParamName(p){ + if(p !~ /^[A-Z_][A-Z0-9_]*$/)addError("@param name should match /^[A-Z_][A-Z0-9_]*$/: '\''" p "'\''") + return p} +function registerGoal(priv,goalName){ + if(""==goalName||"@params"==goalName) addError("Goal must have a name") - if (goalName in GoalsByName) - addError("Goal " quote2(goalName,1) " is already defined") - arrPush(GoalNames, goalName) - GoalsByName[goalName] = priv -} -function globGoal(i) { return (GlobGoalName ? GlobGoalName "@" : "") GlobFiles[i] } -function calcGlob(goalName, pattern, script, file) { - GlobCnt = 0 - GlobGoalName = goalName - split("",GlobFiles) - script = MyDirScript ";for f in " pattern ";do test -e \"$f\"&&echo \"$f\"||:;done" - if ("sh" != Shell) - script = Shell " -c " quoteArg(script) - while ((script | getline file)>0) { + else if(goalName in GoalsByName) + addError("Goal " quote2(goalName,1)" is already defined") + else { + arrPush(GoalNames,goalName) + GoalsByName[goalName]=priv + return 1}} +function globGoal(i){return (GlobGoalName?GlobGoalName "@":"")GlobFiles[i]} +function calcGlob(goalName,pattern,script,file){ + GlobCnt=0 + GlobGoalName=goalName + delete GlobFiles + script=MyDirScript ";for f in " pattern ";do test -e \"$f\"&&echo \"$f\"||:;done" + if("sh"!=Shell) + script=Shell " -c " quoteArg(script) + while((script|getline file)>0){ GlobCnt++ - arrPush(GlobFiles,file) - } + arrPush(GlobFiles,file)} closeErr(script) - quicksort(GlobFiles,0,arrLen(GlobFiles)-1) -} -function parseGoalLine( priv) { - if ($NF == "@private") { - priv=1 - NF-- - } - $1 = "" - return priv -} -function handleGoalGlob( goalName,globAllGoal,globSingle,priv,i,pattern) { + quicksort(GlobFiles,0,arrLen(GlobFiles)-1)} +function parsePriv(){ + if("@private"!=$NF)return 0 + $NF="" + NF-- + return 1} +function handleGoalGlob(goalName,globAllGoal,globSingle,priv,i,pattern,nfMax){ started("goal_glob") - priv = parseGoalLine() - goalName = $2; $2 = "" - if ("@glob" == goalName) { - goalName = "" - } else $3 = "" - calcGlob(goalName, pattern = trim($0)) - globAllGoal = goalName ? goalName : pattern - globSingle = GlobCnt == 1 && globAllGoal == globGoal(0) - for (i=0; i < GlobCnt; i++){ - registerGoal(globGoal(i), globSingle ? priv : 1) - } - if (!globSingle) { - registerGoal(globAllGoal, priv) - for (i=0; i < GlobCnt; i++){ - registerDependency(globAllGoal, globGoal(i)) - } - } -} -function handleDoc( i) { + priv=parsePriv() + if("@glob"==(goalName=$2)){ + goalName="";pattern=$(nfMax=3) + }else + pattern=$(nfMax=4) + if(NF>nfMax) + addError("nothing allowed after glob pattern") + else if(pattern=="") + addError("absent glob pattern") + else { + calcGlob(goalName,pattern) + globAllGoal=goalName?goalName:pattern + globSingle=GlobCnt==1&&globAllGoal==globGoal(0) + for(i=0;i gnMaxLen && gnLen <= 30) - gnMaxLen = gnLen - } - for (i = 0; i in GoalNames; i++) { - goalName = GoalNames[i] - if (list && GoalsByName[goalName]) + if((gnLen=length(quote2(goalName)))>gnMaxLen&&gnLen<=30) + gnMaxLen=gnLen} + for(i=0;i in GoalNames;i++){ + goalName=GoalNames[i] + if(list&&GoalsByName[goalName]) continue printf " " - if (goalName in Doc) - printf "%-" gnMaxLen "s : %s\n", quote2(goalName), Doc[goalName] + if(goalName in Doc) + printf "%-" gnMaxLen "s : %s\n",quote2(goalName),Doc[goalName] else - print quote2(goalName) - } - } else { - if (timingOn()) - t0 = currentTimeMillis() - for (i = 0; i in GoalNames; i++) { - depCnt = DependenciesCnt[goalName = GoalNames[i]] - for (j=0; j < depCnt; j++) { - dep = Dependencies[goalName, j] - topologicalSortAddConnection(goalName, dep) - } - } - topologicalSort(0,GoalNames) + print quote2(goalName)} + }else { + if(timingOn()) + t0=currentTimeMillis() topologicalSort(1,ArgGoals,resolvedGoals,reachedGoals) - preludeCode = getPreludeCode() - for (i = 0; i in GoalNames; i++) { - goalName = GoalNames[i] - body = trim(Code[goalName]) - emptyGoals[goalName] = length(body) == 0 - goalBody[0] = "" - addLine(goalBody, preludeCode) - addLine(goalBody, CodePre[goalName]) - if (goalName in GoalToLib) - addLine(goalBody, Lib[GoalToLib[goalName]]) - addLine(goalBody, body) - goalBodies[goalName] = goalBody[0] - } - if ("-d" in Args || "--resolved" in Args) { + preludeCode=getPreludeCode() + for(i=0;i in GoalNames;i++){ + body=trim(Code[goalName=GoalNames[i]]) + emptyGoals[goalName]=""==body + goalBody[0]="" + addLine(goalBody,preludeCode) + addLine(goalBody,CodePre[goalName]) + if(goalName in GoalToLib) + addLine(goalBody,Lib[GoalToLib[goalName]]) + addLine(goalBody,body) + goalBodies[goalName]=goalBody[0]} + if("-d" in Args||"--resolved" in Args){ printf "Resolved goals to reach for" - for (i = 0; i in ArgGoals; i++) - printf " %s", quote2(ArgGoals[i],1) + for(i=0;i in ArgGoals;i++) + printf " %s",quote2(ArgGoals[i],1) print ":" - for (i = 0; i in resolvedGoals; i++) - if (!reachedGoals[goalName=resolvedGoals[i]] && !emptyGoals[goalName]) + for(i=0;i in resolvedGoals;i++) + if(!reachedGoals[goalName=resolvedGoals[i]]&&!emptyGoals[goalName]) print " " quote2(goalName) - } else { - for (i = 0; i in resolvedGoals; i++) { - goalName = resolvedGoals[i] - goalTimed = timingOn() && !reachedGoals[goalName] && !emptyGoals[goalName] - if (goalTimed) - t1 = t2 ? t2 : currentTimeMillis() - if (!("silent" in Options)) - print " goal " quote2(goalName,1) " " (reachedGoals[goalName] ? "[already satisfied]." : emptyGoals[goalName] ? "[empty]." : "...") - exitCode = (reachedGoals[goalName] || emptyGoals[goalName]) ? 0 : shellExec(goalBodies[goalName],goalName) - if (exitCode != 0) - print " goal " quote2(goalName,1) " failed" - if (goalTimed) { - t2 = currentTimeMillis() - print " goal " quote2(goalName,1) " took " renderDuration(t2 - t1) - } - if (exitCode != 0) - break - } - if (timingOn()) - print " total time " renderDuration((t2 ? t2 : currentTimeMillis()) - t0) - if (exitCode != 0) - realExit(exitCode) - } - } -} -function topologicalSort(includeReachedIf,requestedGoals,result,reachedGoals, i,goalName,loop) { + }else { + for(i=0;i in resolvedGoals;i++){ + goalName=resolvedGoals[i] + goalTimed=timingOn()&&!reachedGoals[goalName]&&!emptyGoals[goalName] + if(goalTimed) + t1=t2?t2:currentTimeMillis() + if(!("silent" in Options)) + print " goal " quote2(goalName,1)" " (reachedGoals[goalName]?"[already satisfied].":emptyGoals[goalName]?"[empty].":"...") + exitCode=(reachedGoals[goalName]||emptyGoals[goalName])?0:shellExec(goalBodies[goalName],goalName) + if(exitCode!=0) + print " goal " quote2(goalName,1)" failed" + if(goalTimed){ + t2=currentTimeMillis() + print " goal " quote2(goalName,1)" took " renderDuration(t2 - t1)} + if(exitCode!=0) + break} + if(timingOn()) + print " total time " renderDuration((t2?t2:currentTimeMillis())- t0) + if(exitCode!=0) + realExit(exitCode)}}} +function topologicalSort(includeReachedIf,requestedGoals,result,reachedGoals,i,j,goalName,loop,depCnt){ topologicalSortReset() - if (arrLen(requestedGoals) == 0) - arrPush(requestedGoals, "default") - for (i = 0; i in requestedGoals; i++) { - goalName = requestedGoals[i] - if (!(goalName in GoalsByName)) { + for(i=0;i in GoalNames;i++){ + depCnt=DependenciesCnt[goalName=GoalNames[i]] + for(j=0;j " loop[2]) - } -} -function isCodeAllowed() { return "goal"==Mode || "goal_glob"==Mode || "lib"==Mode } -function isPrelude() { return "prelude"==Mode } -function checkPreludeOnly() { if (!isPrelude()) addError("Only use " $1 " in prelude") } -function checkGoalOnly() { if ("goal" != Mode && "goal_glob" != Mode) addError("Only use " $1 " in @goal") } -function currentGoalName() { return arrLast(GoalNames) } -function currentLibName() { return arrLast(LibNames) } -function realExit(code) { - exit code -} -function addError(err, n) { if (!n) n=NR; Error=addL(Error, err ":\n" ARGV[1] ":" n ": " Lines[n]) } -function die(msg, out) { - out = "cat 1>&2" - print msg | out + topologicalSortPerform(includeReachedIf,reachedGoals,goalName,result,loop)} + if(loop[0]==1) + die("There is a loop in goal dependencies via " loop[1] " -> " loop[2])} +function isCodeAllowed(){return "goal"==Mode||"goal_glob"==Mode||"lib"==Mode} +function isPrelude(){return "prelude"==Mode} +function checkPreludeOnly(){if(!isPrelude())addError("Only use " $1 " in prelude")} +function checkGoalOnly(){if("goal"!=Mode&&"goal_glob"!=Mode)addError("Only use " $1 " in @goal")} +function currentGoalName(){return arrLast(GoalNames)} +function currentLibName(){return arrLast(LibNames)} +function realExit(code){ + exit code} +function addError(err,n){if(!n)n=NR;Error=addL(Error,err ":\n" ARGV[1] ":" n ": " Lines[n])} +function addErrorDedup(err,n){if((err,n)in AddedErrors)return;AddedErrors[err,n];addError(err,n)} +function die(msg,out){ + out="cat 1>&2" + print msg|out close(out) - realExit(1) -} -function checkConditionReached(goalName, conditionStr, script) { - script = getPreludeCode() - if (goalName in GoalToLib) - script = script "\n" Lib[GoalToLib[goalName]] - script = script "\n" conditionStr - return shellExec(script, goalName "@reached_if") == 0 -} -function shellExec(script, comment, res) { - if ("tracing" in Options) { - script = ": " quoteArg(comment) "\n" script - script = Shell " -x -e -c " quoteArg(script) - } else - script = Shell " -e -c " quoteArg(script) - script = "trap '\''exit 7'\'' INT;" script - res = system(script) - return res -} -function getMyDir(makesurefilePath) { - return executeGetLine("cd \"$(dirname " quoteArg(makesurefilePath) ")\";pwd") -} -function handleCodeLine(line) { - if (!isCodeAllowed() && line !~ /^[ \t]*#/ && trim(line) != "") { - if (!ShellInPreludeErrorShown++) + realExit(1)} +function checkConditionReached(goalName,conditionStr,script){ + script=getPreludeCode() + if(goalName in GoalToLib) + script=script "\n" Lib[GoalToLib[goalName]] + script=script "\n" conditionStr + return shellExec(script,goalName "@reached_if")==0} +function shellExec(script,comment,res){ + if("tracing" in Options){ + script=": " quoteArg(comment)"\n" script + script=Shell " -x -e -c " quoteArg(script) + }else + script=Shell " -e -c " quoteArg(script) + script="trap '\''exit 7'\'' INT;" script + res=system(script) + return res} +function getMyDir(makesurefilePath){ + return executeGetLine("cd \"$(dirname " quoteArg(makesurefilePath)")\";pwd")} +function handleCodeLine(line){ + if(!isCodeAllowed()&&line !~ /^[ \t]*#/&&trim(line)!=""){ + if(!ShellInPreludeErrorShown++) addError("Shell code is not allowed outside goals/libs") - } else - addCodeLine(line) -} -function addCodeLine(line, goalName, name, i) { - if ("lib" == Mode) { - name = currentLibName() - Lib[name] = addL(Lib[name], line) - } else if ("goal_glob" == Mode) { - for (i=0; i < GlobCnt; i++){ - if (!CodePre[goalName = globGoal(i)]) - CodePre[goalName] = makeGlobVarsCode(i) - addCodeLineToGoal(goalName, line) - } - } else - addCodeLineToGoal(currentGoalName(), line) -} -function addCodeLineToGoal(name, line) { - Code[name] = addL(Code[name], line) -} -function topologicalSortReset() { - split("",Visited) -} -function topologicalSortAddConnection(from, to) { - Slist[from, ++Scnt[from]] = to -} -function topologicalSortPerform(includeReachedIf,reachedGoals, node, result, loop, i, s) { - if (Visited[node] == 2) - return - if (includeReachedIf && node in ReachedIf && checkConditionReached(node, ReachedIf[node])){ - Visited[node] = 2 - arrPush(result, node) - reachedGoals[node] = 1 + }else + addCodeLine(line)} +function addCodeLine(line,goalName,name,i){ + if("lib"==Mode){ + name=currentLibName() + Lib[name]=addL(Lib[name],line) + }else if("goal_glob"==Mode){ + for(i=0;i0){ + arrDel(GoalNames,goalName) + delete GoalsByName[goalName]}} +function instantiate(goal,args,newArgs,i,j,depArg,depArgType,dep,goalNameInstantiated,argsCnt,gi,gii,argsCode){ + goalNameInstantiated=instantiateGoalName(goal,args) + if(goalNameInstantiated!=goal){ + if(!(goalNameInstantiated in GoalsByName)) + arrPush(GoalNames,goalNameInstantiated) + copyKey(goal,goalNameInstantiated,GoalsByName) + copyKey(goal,goalNameInstantiated,DependenciesCnt) + copyKey(goal,goalNameInstantiated,CodePre) + copyKey(goal,goalNameInstantiated,Code) + copyKey(goal,goalNameInstantiated,Doc) + copyKey(goal,goalNameInstantiated,ReachedIf) + copyKey(goal,goalNameInstantiated,GoalToLib) + for(i in args) + argsCode=addL(argsCode,i "=" quoteArg(args[i])) + CodePre[goalNameInstantiated]=addL(CodePre[goalNameInstantiated],argsCode) + if(goalNameInstantiated in ReachedIf) + ReachedIf[goalNameInstantiated]=argsCode "\n" ReachedIf[goalNameInstantiated]} + for(i=0;i " newVer - } else print "you have latest version " Version " installed" - } + }else print "you have latest version " Version " installed"} rm(tmp) - if (err) die(err) -} + if(err)die(err)} function renderDuration(deltaMillis,\ - deltaSec,deltaMin,deltaHr,deltaDay,dayS,hrS,minS,secS,secSI,res) { - deltaSec = deltaMillis / 1000 - deltaMin = 0 - deltaHr = 0 - deltaDay = 0 - if (deltaSec >= 60) { - deltaMin = int(deltaSec / 60) - deltaSec = deltaSec - deltaMin * 60 - } - if (deltaMin >= 60) { - deltaHr = int(deltaMin / 60) - deltaMin = deltaMin - deltaHr * 60 - } - if (deltaHr >= 24) { - deltaDay = int(deltaHr / 24) - deltaHr = deltaHr - deltaDay * 24 - } - dayS = deltaDay > 0 ? deltaDay " d" : "" - hrS = deltaHr > 0 ? deltaHr " h" : "" - minS = deltaMin > 0 ? deltaMin " m" : "" - secS = deltaSec > 0 ? deltaSec " s" : "" - secSI = deltaSec > 0 ? int(deltaSec) " s" : "" - if (dayS != "") - res = dayS " " (hrS == "" ? "0 h" : hrS) - else if (deltaHr > 0) - res = hrS " " (minS == "" ? "0 m" : minS) - else if (deltaMin > 0) - res = minS " " (secSI == "" ? "0 s" : secSI) + deltaSec,deltaMin,deltaHr,deltaDay,dayS,hrS,minS,secS,secSI,res){ + deltaSec=deltaMillis/1000 + deltaMin=0 + deltaHr=0 + deltaDay=0 + if(deltaSec>=60){ + deltaMin=int(deltaSec/60) + deltaSec=deltaSec - deltaMin*60} + if(deltaMin>=60){ + deltaHr=int(deltaMin/60) + deltaMin=deltaMin - deltaHr*60} + if(deltaHr>=24){ + deltaDay=int(deltaHr/24) + deltaHr=deltaHr - deltaDay*24} + dayS=deltaDay>0?deltaDay " d":"" + hrS=deltaHr>0?deltaHr " h":"" + minS=deltaMin>0?deltaMin " m":"" + secS=deltaSec>0?deltaSec " s":"" + secSI=deltaSec>0?int(deltaSec)" s":"" + if(dayS!="") + res=dayS " " (hrS==""?"0 h":hrS) + else if(deltaHr>0) + res=hrS " " (minS==""?"0 m":minS) + else if(deltaMin>0) + res=minS " " (secSI==""?"0 s":secSI) else - res = deltaSec > 0 ? secS : "0 s" - return res -} -function executeGetLine(script, res) { - script | getline res + res=deltaSec>0?secS:"0 s" + return res} +function executeGetLine(script,res){ + script|getline res closeErr(script) - return res -} -function closeErr(script) { if (close(script)!=0) die("Error executing: " script) } -function dl(url, dest, verbose) { - verbose = "VERBOSE" in ENVIRON - if (commandExists("wget")) { - if (!ok("wget " (verbose ? "" : "-q") " " quoteArg(url) " -O" quoteArg(dest))) + return res} +function closeErr(script){if(close(script)!=0)die("Error executing: " script)} +function dl(url,dest,verbose){ + verbose="VERBOSE" in ENVIRON + if(commandExists("wget")){ + if(!ok("wget " (verbose?"":"-q")" " quoteArg(url)" -O" quoteArg(dest))) return "error with wget" - } else if (commandExists("curl")) { - if (!ok("curl " (verbose ? "" : "-s") " " quoteArg(url) " -o " quoteArg(dest))) + }else if(commandExists("curl")){ + if(!ok("curl " (verbose?"":"-s")" " quoteArg(url)" -o " quoteArg(dest))) return "error with curl" - } else return "wget/curl not found" -} -function natOrder(s1,s2, i1,i2, c1, c2, n1,n2) { - if (_digit(c1 = substr(s1,i1,1)) && _digit(c2 = substr(s2,i2,1))) { - n1 = +c1; while(_digit(c1 = substr(s1,++i1,1))) { n1 = n1 * 10 + c1 } - n2 = +c2; while(_digit(c2 = substr(s2,++i2,1))) { n2 = n2 * 10 + c2 } - return n1 == n2 ? natOrder(s1, s2, i1, i2) : _cmp(n1, n2) - } - while ((c1 = substr(s1,i1,1)) == (c2 = substr(s2,i2,1)) && c1 != "" && !_digit(c1)) { - i1++; i2++ - } - return _digit(c1) && _digit(c2) ? natOrder(s1, s2, i1, i2) : _cmp(c1, c2) -} -function _cmp(v1, v2) { return v1 > v2 ? 1 : v1 < v2 ? -1 : 0 } -function _digit(c) { return c >= "0" && c <= "9" } -function quicksort(data, left, right, i, last) { - if (left >= right) + }else return "wget/curl not found"} +function natOrder(s1,s2,i1,i2,c1,c2,n1,n2){ + if(_digit(c1=substr(s1,i1,1))&&_digit(c2=substr(s2,i2,1))){ + n1=+c1;while(_digit(c1=substr(s1,++i1,1))){n1=n1*10+c1} + n2=+c2;while(_digit(c2=substr(s2,++i2,1))){n2=n2*10+c2} + return n1==n2?natOrder(s1,s2,i1,i2):_cmp(n1,n2)} + while((c1=substr(s1,i1,1))==(c2=substr(s2,i2,1))&&c1!=""&&!_digit(c1)){ + i1++;i2++} + return _digit(c1)&&_digit(c2)?natOrder(s1,s2,i1,i2):_cmp(c1,c2)} +function _cmp(v1,v2){return v1>v2?1:v1="0"&&c<="9"} +function quicksort(data,left,right,i,last){ + if(left>=right) return - quicksortSwap(data, left, int((left + right) / 2)) - last = left - for (i = left + 1; i <= right; i++) - if (natOrder(data[i], data[left],1,1) < 0) - quicksortSwap(data, ++last, i) - quicksortSwap(data, left, last) - quicksort(data, left, last - 1) - quicksort(data, last + 1, right) -} -function quicksortSwap(data, i, j, temp) { - temp = data[i] - data[i] = data[j] - data[j] = temp -} -function parseCli(line, res, pos,c,last,is_doll,c1) { - for(pos=1;;) { - while((c = substr(line,pos,1))==" " || c == "\t") pos++ - if ((c = substr(line,pos,1))=="#" || c=="") + quicksortSwap(data,left,int((left+right)/2)) + last=left + for(i=left+1;i<=right;i++) + if(natOrder(data[i],data[left],1,1)<0) + quicksortSwap(data,++last,i) + quicksortSwap(data,left,last) + quicksort(data,left,last - 1) + quicksort(data,last+1,right)} +function quicksortSwap(data,i,j,temp){ + temp=data[i] + data[i]=data[j] + data[j]=temp} +function parseCli(line,res,pos,c,last,is_doll,c1){ + for(pos=1;;){ + while((c=substr(line,pos,1))==" "||c=="\t")pos++ + if((c=substr(line,pos,1))=="#"||c=="") return else { - if ((is_doll = c == "$") && substr(line,pos+1,1)=="'\''" || c == "'\''") { + if((is_doll=c=="$")&&substr(line,pos+1,1)=="'\''"||c=="'\''"){ if(is_doll) pos++ - res[last = res[-7]++] = "" - while((c = substr(line,++pos,1)) != "'\''") { - if (c=="") + res[last=res[-7]++]="" + res[last,"quote"]=is_doll?"$":"'\''" + while((c=substr(line,++pos,1))!="'\''"){ + if(c=="") return "unterminated argument" - else if (is_doll && c=="\\" && ((c1=substr(line,pos+1,1))=="'\''" || c1==c)) { - c = c1; pos++ - } - res[last] = res[last] c - } - if((c = substr(line,++pos,1)) != "" && c != " " && c != "\t") + else if(is_doll&&c=="\\"&&((c1=substr(line,pos+1,1))=="'\''"||c1==c)){ + c=c1;pos++} + res[last]=res[last] c} + if((c=substr(line,++pos,1))!=""&&c!=" "&&c!="\t") return "joined arguments" - } else { - res[last = res[-7]++] = c - while((c = substr(line,++pos,1)) != "" && c != " " && c != "\t") { + }else { + res[last=res[-7]++]=c + while((c=substr(line,++pos,1))!=""&&c!=" "&&c!="\t"){ if(c=="'\''") return "joined arguments" - res[last] = res[last] c - } - } - } - } -} -function reparseCli( res,i,err) { - err = parseCli($0, res) - if (err) { + res[last]=res[last] c}}}}} +function reparseCli(res,i,err){ + err=parseCli($0,res) + if(err){ addError("Syntax error: " err) die(Error) - } else - for (i=NF=0; i in res; i++) + }else { + $0="" + for(i=NF=0;i in res;i++){ $(++NF)=res[i] -} -function quote2(s,force) { - if (index(s,"'\''")) { + Quotes[NF]=res[i,"quote"]}}} +function quote2(s,force){ + if(index(s,"'\''")){ gsub(/\\/,"\\\\",s) gsub(/'\''/,"\\'\''",s) return "$'\''" s "'\''" - } else - return force || s ~ /[^a-zA-Z0-9.,@_\/=+-]/ ? "'\''" s "'\''" : s -} -function addLine(target, line) { target[0] = addL(target[0], line) } -function addL(s, l) { return s ? s "\n" l : l } -function arrPush(arr, elt) { arr[arr[-7]++] = elt } -function arrLen(arr) { return +arr[-7] } -function arrLast(arr) { return arr[arrLen(arr)-1] } -function commandExists(cmd) { return ok("command -v " cmd " >/dev/null") } -function ok(cmd) { return system(cmd) == 0 } -function isFile(path) { return ok("test -f " quoteArg(path)) } -function rm(f) { system("rm " quoteArg(f)) } -function quoteArg(a) { gsub("'\''", "'\''\\'\'''\''", a); return "'\''" a "'\''" } -function trim(s) { sub(/^[ \t\r\n]+/, "", s); sub(/[ \t\r\n]+$/, "", s); return s } -' Makesurefile "$@" + }else + return force||s~/[^a-zA-Z0-9.,@_\/=+-]/?"'\''" s "'\''":s} +function addLine(target,line){target[0]=addL(target[0],line)} +function addL(s,l){return s?s "\n" l:l} +function arrPush(arr,elt){arr[arr[-7]++]=elt} +function arrLen(arr){return +arr[-7]} +function arrDel(arr,v,l,i,e,resArr){ + l=arrLen(arr) + for(i=0;i0?arr[l-1]:""} +function commandExists(cmd){return ok("command -v " cmd " >/dev/null")} +function ok(cmd){return system(cmd)==0} +function isFile(path){return ok("test -f " quoteArg(path))} +function rm(f){system("rm " quoteArg(f))} +function quoteArg(a){gsub("'\''","'\''\\'\'''\''",a);return "'\''" a "'\''"} +function trim(s){sub(/^[ \t\r\n]+/,"",s);sub(/[ \t\r\n]+$/,"",s);return s} +function copyKey(keySrc,keyDst,arr){if(keySrc in arr)arr[keyDst]=arr[keySrc]}' Makesurefile "$@" diff --git a/makesure_candidate b/makesure_candidate index 2491ebe..5d19851 100755 --- a/makesure_candidate +++ b/makesure_candidate @@ -1,6 +1,6 @@ #!/bin/sh if command -v gawk >/dev/null;then makesure_awk='gawk -ltime -v Gawk=1';makesure_pre='';else makesure_awk=awk;makesure_pre='function gettimeofday(){}';fi -exec $makesure_awk -v "Version=0.9.19" -v "Prog=$0" "$makesure_pre"' +exec $makesure_awk -v "Version=0.9.20" -v "Prog=$0" "$makesure_pre"' BEGIN { Shell="bash" SupportedShells["bash"]