#!/usr/bin/ruby # vim: et sw=2 VER="(1116816)" ME="links.rb: " $mrg_fields=["vlan","vpi","vci","comment"] $chk_fields=["vlan","vpi","vci","cnt"] $lst_fields=["vlan","vpi","vci"] $str_fields=["comment","extra"] $lag_fields=["lag","pc","lg"] $num_fields=[] $check=false $hdrs=false $sbl=false $no_comm=false $sh_loc=true $exfld="extra" $incl=[] $excl=[] $expr=[] class Object def _str(p=nil) return to_s if !p or self.class!=Float return "%.#{p}f" % self end end def in_list(s,list) for i in list if i.match(s) return true end end return false end def regexfix(str) tmp=[] for t in str.scan(/(_)|(\|)|([^_\|]*)/).flatten.compact tmp.push(t) if not t.empty? end res="" while t=tmp.shift case t when "_" then res+=(tmp.empty? or tmp[0]=="|") ? "([ .]+|$)" : "[ .]+" when "|" then res+="|" else res+="#{t}" end end return res end def in_fields(t,fields) fields.length.times do |i| return i if fields[i]==t end return nil end def scomp(x,y) return 0 if x.empty? and y.empty? return -1 if x.empty? return 1 if y.empty? xa=x.scan(/([0-9]+)|([^0-9]+)/) ya=y.scan(/([0-9]+)|([^0-9]+)/) r=nil xi=xa.shift yi=ya.shift while xi and yi if xi[0] and yi[0] xv=xi[0].to_i yv=yi[0].to_i if(xv==yv) r=0 xi=xa.shift yi=ya.shift next end r=(xv>yv) ? 1 : -1 break end if xi[1] and yi[1] xv=xi[1] yv=yi[1] if(xv==yv) r=0 xi=xa.shift yi=ya.shift next end r=(xv<=>yv) break end break end return (x<=>y) if !r if r==0 r=-1 if !xi and yi r=1 if xi and !yi end return r end class Expr FN0=["count","show"] FN1=["count","sum","min","max","avg","add","sub","icnt","show","pfxl","pfxc"] FN2=["sumif","xval","getid"] FNS=FN1+FN2 AGG=["count","sum","sumif","min","max","avg"] SAG=["add","sub"] OPS=["+","-","*","/"] CMP=["=","==","!=","<","<=",">",">="] LOG=["|","&","^","?","!"] ALL=OPS+CMP+LOG OPL={ "|"=>1,"&"=>1,"^"=>1, "="=>2,"=="=>2,"!="=>2,"<"=>2,"<="=>2,">"=>2,">="=>2, "+"=>3,"-"=>3,"*"=>4,"/"=>4, "?"=>0,"!"=>9 } Ops=Struct.new :ops, :op, :ac attr_reader :fld, :aggr, :aid def initialize(arr) @aggr=0 # 1:AGG, 2:SAG, 4:vaggr, 8:alloc @show=false @temp=false @fld=nil @str=arr.join @ops=[] @aid=-1 tmp=[] tmp[0]=Ops.new([],nil,0) i=0 if arr.length>1 and arr[1]==":" t=arr.shift if m=/^%(.*)/.match(t) @fld=m[1] @temp=true else @fld=t end arr.shift end for s in arr if s=="," or s==")" while i>0 and tmp[i].ac==0 tmp[i].ops.push(tmp[i].op) if tmp[i].op tmp[i-1].ops+=tmp[i].ops i-=1 end if tmp[i].op=="?" if tmp[i].ac!=-3 $stderr.puts ME+"syntax error" exit end tmp[i].ops.push(tmp[i].op) tmp[i-1].ops+=tmp[i].ops i-=1 end end if s==":" while i>0 and tmp[i].ac==0 tmp[i].ops.push(tmp[i].op) if tmp[i].op tmp[i-1].ops+=tmp[i].ops i-=1 end if tmp[i].op!="?" or tmp[i].ac!=-2 $stderr.puts ME+"syntax error" exit end tmp[i].ac=-3 next end if s=="?" if tmp[i].op=="?" $stderr.puts ME+"syntax error" exit end if tmp[i].op tmp[i].ops.push(tmp[i].op) tmp[i].op=nil end tmp[i+1]=Ops.new([],s,-2) i+=1 next end if s=="()" if !tmp[i].op or not FNS.include?(tmp[i].op) $stderr.puts ME+"syntax error" exit end if not FN0.include?(tmp[i].op) $stderr.puts ME+"function needs argument" exit end tmp[i].ops.push("1",tmp[i].op) tmp[i].op=nil next end if s=="," if i<1 or tmp[i-1].ac<2 $stderr.puts ME+"syntax error" exit end tmp[i].ops.push(tmp[i].op) if tmp[i].op tmp[i].op=nil tmp[i-1].ac-=1 next end if s=="(" tmp[i+1]=Ops.new([],nil,-1) i+=1 next end if s==")" if tmp[i].ac!=-1 $stderr.puts ME+"parantheses mismatch" exit end tmp[i].ops.push(tmp[i].op) if tmp[i].op tmp[i-1].ops+=tmp[i].ops i-=1 next if tmp[i].ac<1 if tmp[i].ac>1 $stderr.puts ME+"missing argument" exit end if i<1 tmp[i].ops.push(tmp[i].op) if tmp[i].op tmp[i].op=nil tmp[i].ac=0 next end tmp[i].ops.push(tmp[i].op) if tmp[i].op tmp[i-1].ops+=tmp[i].ops i-=1 next end if s=="!" if !tmp[i].op and tmp[i].ac==0 tmp[i].op=s next end tmp[i+1]=Ops.new([],s,0) i+=1 next end if FNS.include?(s) @aggr|=1 if AGG.include?(s) @aggr|=2 if SAG.include?(s) @aggr|=8 if s=="getid" if ("%b" % @aggr).count("1")>1 $stderr.puts ME+"cannot mix aggregation functions" exit end @show=true if s=="show" c=0 c=1 if FN1.include?(s) c=2 if FN2.include?(s) if !tmp[i].op and tmp[i].ac==0 tmp[i].op=s tmp[i].ac=c next end tmp[i+1]=Ops.new([],s,c) i+=1 next end if ALL.include?(s) if !tmp[i].op tmp[i].op=s next end if OPL[s]>OPL[tmp[i].op] tmp[i+1]=Ops.new([tmp[i].ops.pop],s,0) i+=1 next end if OPL[s]==OPL[tmp[i].op] tmp[i].ops.push(tmp[i].op) tmp[i].op=s next end while i>0 and tmp[i].ac==0 tmp[i].ops.push(tmp[i].op) if tmp[i].op tmp[i-1].ops+=tmp[i].ops i-=1 end tmp[i].ops.push(tmp[i].op) tmp[i].op=s next end tmp[i].ops.push(s) if tmp[i].op=="!" tmp[i].ops.push(tmp[i].op) tmp[i-1].ops+=tmp[i].ops i-=1 end end if tmp[i].ac==-1 $stderr.puts ME+"parantheses mismatch" exit end while i>1 and tmp[i].ac==0 tmp[i].ops.push(tmp[i].op) if tmp[i].op tmp[i-1].ops+=tmp[i].ops i-=1 end if tmp[i].op=="?" tmp[i].ops.push(tmp[i].op) tmp[i-1].ops+=tmp[i].ops i-=1 end if i>1 $stderr.puts ME+"stack error" exit end if i==1 tmp[i].ops.push(tmp[i].op) if tmp[i].op tmp[i-1].ops+=tmp[i].ops end @ops=tmp[0].ops @ops.push(tmp[0].op) if tmp[0].op end def self.parse(str) expr=[] arr=[] pc=0 for s in str.scan(/!=|==|<=|>=|\(\)|[\:\,\=\?\<\>\+\-\*\/\!\|\&\^\(\)]|"[^"]*"|[@%]?[a-zA-Z0-9\.]*/) next if s.empty? if s=="," and pc==0 e=Expr.new(arr) e.chk_vaggr(expr) expr<v) ? r : v if r s.push(v) ar.push(v) next end if o=="avg" if s.length<1 $stderr.puts ME+"expr: avg(): need argument" exit end a=s.pop if !a $stderr.puts ME+"expr: avg(): invalid argument" exit end v=a.to_f rs=av.shift rc=av.shift if rs and rc rs+=v rc+=1 v=rs/rc else rs=v rc=1 end s.push(v) ar.push(rs,rc) next end if o=="add" if s.length<1 $stderr.puts ME+"expr: add(): need argument" exit end a=s.pop if !a $stderr.puts ME+"expr: add(): invalid argument" exit end v=a.to_f r=av.shift r=0.0 if !r v=(bl) ? r+v : 0.0 s.push(v) ar.push(v) next end if o=="sub" if s.length<1 $stderr.puts ME+"expr: sub(): need argument" exit end a=s.pop if !a $stderr.puts ME+"expr: sub(): invalid argument" exit end v=a.to_f r=av.shift r=0.0 if !r v=(bl) ? r-v : v s.push(v) ar.push(v) next end if o=="icnt" if s.length<1 $stderr.puts ME+"expr: icnt(): need argument" exit end a=s.pop if !a $stderr.puts ME+"expr: icnt(): invalid argument" exit end v=a.split(/[, ]+/).compact.length s.push(v) next end if o=="show" if s.length<1 $stderr.puts ME+"expr: show(): need argument" exit end a=s.pop if !a s.push(0) next end if a.class==String a=(a.empty? or a=="-") ? 0 : 1 else a=a.to_i end v=(a==0) ? 0 : 1 s.push(v) next end if o=="pfxl" if s.length<1 $stderr.puts ME+"expr: pfxl(): need argument" exit end a=s.pop if !a or a.class!=String $stderr.puts ME+"expr: pfxl(): invalid argument" next end d=(a.include?(":")) ? 128 : 32 t=a.split("/") if t.length!=2 s.push(d) next end v=t[1].to_i s.push(v) next end if o=="pfxc" if s.length<1 $stderr.puts ME+"expr: pfxc(): need argument" exit end a=s.pop if !a or a.class!=String $stderr.puts ME+"expr: pfxc(): invalid argument" next end if a.include?(":") s.push(0) next end t=a.split("/") if t.length==2 v=32-t[1].to_i s.push(1<x @aid=-1 if v==@aid if @aid<0 and v-x>1 r=(x==r) ? r+1 : x @aid=r end s.push(@aid) ar.push(v) next end if o=="!" a=s.pop if a.class==String a=(a.empty? or a=="-") ? 0 : 1 else a=a.to_i end v=(a==0) ? 1 : 0 s.push(v) next end if o=="?" c=s.pop b=s.pop a=s.pop if a.class==String a=(a.empty? or a=="-") ? 0 : 1 else a=a.to_i end v=(a==0) ? c : b s.push(v) next end if o=="|" b=s.pop a=s.pop if b.class==String b=(b.empty? or b=="-") ? 0 : 1 else b=b.to_i end if a.class==String a=(a.empty? or a=="-") ? 0 : 1 else a=a.to_i end v=a|b s.push(v) next end if o=="&" b=s.pop a=s.pop if b.class==String b=(b.empty? or b=="-") ? 0 : 1 else b=b.to_i end if a.class==String a=(a.empty? or a=="-") ? 0 : 1 else a=a.to_i end v=a&b s.push(v) next end if o=="^" b=s.pop a=s.pop if b.class==String b=(b.empty? or b=="-") ? 0 : 1 else b=b.to_i end if a.class==String a=(a.empty? or a=="-") ? 0 : 1 else a=a.to_i end v=a^b s.push(v) next end if o=="+" b=s.pop.to_f a=s.pop.to_f v=a+b s.push(v) next end if o=="-" b=s.pop.to_f a=s.pop.to_f v=a-b s.push(v) next end if o=="*" b=s.pop.to_f a=s.pop.to_f v=a*b s.push(v) next end if o=="/" b=s.pop.to_f a=s.pop.to_f v=a/b s.push(v) next end if o=="=" or o=="==" b=s.pop a=s.pop if a.empty? s.push(0) next end if b.class==Fixnum a=a.to_i v=(a==b) ? 1 : 0 elsif b.class==Float a=a.to_f v=(a==b) ? 1 : 0 else a=a.downcase if o=="=" v=(a.include?(b.downcase)) ? 1 : 0 else v=(a==b.downcase) ? 1 : 0 end end s.push(v) next end if o=="!=" b=s.pop a=s.pop if a.empty? s.push(0) next end if b.class==Fixnum a=a.to_i v=(a!=b) ? 1 : 0 elsif b.class==Float a=a.to_i v=(a!=b) ? 1 : 0 else a=a.downcase v=(a.include?(b.downcase)) ? 0 : 1 end s.push(v) next end if o=="<" b=s.pop.to_f a=s.pop.to_f v=(a" b=s.pop.to_f a=s.pop.to_f v=(a>b) ? 1 : 0 s.push(v) next end if o==">=" b=s.pop.to_f a=s.pop.to_f v=(a>=b) ? 1 : 0 s.push(v) next end if /^"/.match(o) o=o.delete('"') s.push(o) next end if /^[0-9.]+$/.match(o) if o.include?(".") o=o.to_f else o=o.to_i end s.push(o) next end t=o.downcase if m=/^@(.*)/.match(t) if !n=vars["&"+m[1]] if !n=find_key(flds,m[1]) $stderr.puts ME+"expr: unknown var: "+t exit end vars["&"+m[1]]=n end if bl o="" if !o=vars["@"+n] else o="" if !o=flds[n] vars["@"+n]=o end elsif vars.has_key?(t) o="" if !o=vars[t] elsif flds.has_key?(t) o="" if !o=flds[t] elsif n=vars["&"+t] o="" if !o=flds[n] elsif n=find_key(flds,t) vars["&"+t]=n o="" if !o=flds[n] else $stderr.puts ME+"expr: unknown var: "+t exit end s.push(o) end if not av.empty? $stderr.puts ME+"syntax error" exit end av.replace(ar) v=s.pop if v.class==String and v.include?("\n") return v.split("\n")[0] end vars[@fld]=v if @fld return v end def name return @fld if @fld return @str end def temp? return @temp end def aggr?(*ba) for b in ba return true if (@aggr&b)==b end return false end def show? return @show end def chk_vaggr(expr) vars=[] for o in @ops next if FNS.include?(o) or ALL.include?(o) vars< %s:%s\n",li.n1.nm,li.p1,li.n2.nm,li.p2 end end i+=1 end end def self.chk_links # LAGs i=0 while i<$links.length li=$links[i] j=i+1 s1c=s2c=0 we=0.0 while j<$links.length lj=$links[j] pj=nil for f in $lag_fields break if pj=lj.flds1[f] end (j+=1; next) if !pj or pj.start_with?("{") ok=false ok=true if lj.n1==li.n1 and lj.n2==li.n2 and pj==li.p1 ok=true if lj.n1==li.n2 and lj.n2==li.n1 and pj==li.p2 (j+=1; next) if not ok s1c+=1 if lj.sd==1 s2c+=1 if lj.sd==2 we+=lj.we $links.delete_at(j) end if s1c>0 and s2c>0 $stderr.printf "Warning: LAG mismatch: %s:%s <-> %s:%s\n",li.n1.nm,li.p1,li.n2.nm,li.p2 end li.we=we if we>0.0 i+=1 end # merge links i=0 while i<$links.length li=$links[i] j=i+1 while j<$links.length lj=$links[j] ok=false ok=true if lj.n1==li.n1 and lj.n2==li.n2 ok=true if lj.n1==li.n2 and lj.n2==li.n1 (j+=1; next) if not ok li.ml=true li.we+=lj.we li.wecnt+=1 li.fmerge(lj) $links.delete_at(j) end i+=1 end end def initialize(n1,n2,p1,p2,we,fields) @n1,@n2=n1,n2 @p1,@p2=p1,p2 @ml=false @we=we @wecnt=1 @fields=fields @flds1={} @flds2={} @ss=false @sd=0 @b=nil @av1={} @av2={} @vars1={} @vars2={} return end def clone(n2,p2) n1,p1=@n1,@p1 we=@we fields=@fields flds1=@flds1.dup flds2=@flds2.dup obj=Link.allocate obj.instance_exec do @n1,@n2=n1,n2 @p1,@p2=p1,p2 @ml=false @we=we @wecnt=1 @fields=fields @flds1=flds1 @flds2=flds2 @ss=false @sd=0 @b=nil @av1={} @av2={} @vars1={} @vars2={} end return obj end def speed(w=nil) return @we/@wecnt if !w @we=w if @we==0.0 or w<@we end def count return @wecnt end def fstr(f) return '""' if $no_comm and f=="comment" str="" if !str=@flds1[f] return str.dump end def fget(f) flds=(@ss) ? @flds2 : @flds1 return flds[f] end def fset(f,t) flds=(@ss) ? @flds2 : @flds1 return if !v=_set(f,flds[f],t) flds[f]=v return end def fmerge(l) for f in $mrg_fields if t=l.flds1[f] if v=_set(f,@flds1[f],t) @flds1[f]=v end end if t=l.flds2[f] if v=_set(f,@flds2[f],t) @flds2[f]=v end end end for f in $num_fields if v=l.vars1[f] @vars1[f]+=v end if v=l.vars2[f] @vars2[f]+=v end end return end def chk_fields() for f in $chk_fields if fcheck(f) $stderr.printf "Warning: %s mismatch: %s:%s <-> %s:%s\n",f,@n1.nm,@p1,@n2.nm,@p2 end end end def exec(e,vars,av,sd,bl=false) flds=(not bl and sd==2) ? @flds2 : @flds1 av[e]=[] if !av[e] v=e.exec(flds,av[e],vars,bl).to_f return v end def exec1(e) @av1[e]=[] if !@av1[e] e.exec(@flds1,@av1[e],@vars1) return end def vcheck(f) v1=@vars1[f] v2=@vars2[f] return false if !v1 or !v2 return (v1==v2) ? false : true end private def _set(f,v,t) if $lst_fields.include?(f) return nil if t=="-" or t=="?" return nil if t.start_with?("-") v=(v) ? v+","+t : t a=v.split(",") a.uniq! a.reject! do |x| next false if x.include?("-") next false if x.start_with?("*") or x.start_with?("+") xi=x.to_i r=false for y in a next if not y.include?("-") u=y.split("-") if xi>=u[0].to_i and xi<=u[1].to_i r=true break end end next r end a.sort! { |x,y| scomp(x,y) } v=a.join(",") return v end if $str_fields.include?(f) v=(v) ? v+"; "+t : t return v end return t end def fcheck(f) v1=@flds1[f] v2=@flds2[f] return false if !v1 or !v2 if $lst_fields.include?(f) if v1.start_with?("*") or v2.start_with?("*") return false end end return (v1==v2) ? false : true end end def get_node_type(s) return case s when /^gw-/i then "Gateway" when /^rt-/i then "Router" when /^sr-/i then "Service Router" when /^sw-/i then "Switch L2" when /^ap-/i then "Access Point" when /^as-/i then "Access Server" when /^swr-/i then "Switch L3" when /^sw3-/i then "Switch L3" when /^swa-/i then "Access Switch" when /^C1[78]/i then "Router" when /^C28/i then "Router" when /^ASR/i then "Router" when /^C29/i then "Switch L2" when /^C3[5678]/i then "Switch L3" when /^C45/i then "Switch L3" when /^C6[58]/i then "Switch L3" when /^C7[23]/i then "Router" when /^C85/i then "Router" when /^C76/i then "Switch L3" when /^S3048/i then "Switch L3" when /^S5750E/i then "Switch L3" when /^CS6200/i then "Switch L3" else nil end end def get_node_type2(s) return case s.downcase when "gw" then "Gateway" when "rt" then "Router" when "sr" then "Service Router" when "sw" then "Switch L2" when "ap" then "Access Point" when "as" then "Access Server" when "swr" then "Switch L3" when "sw3" then "Switch L3" when "swa" then "Access Switch" else nil end end def _grp_expand(wet,w,str) return if !str or !w if not str.include?("-") wet[str]=w return end if str.include?("(") return if !m=/([^\(\)]*)\(([0-9-]+)\)(.*)/.match(str) st=m[2].split("-") a=st[0].to_i b=st[1].to_i a.upto(b) do |i| si=m[1]+i.to_s+m[3] wet[si]=w end return end st=str.split("/") x=st.pop s=st.join("/") st=x.split("-") a=st[0].to_i b=st[1].to_i a.upto(b) do |i| si=(s.empty?) ? i.to_s : s+"/"+i.to_s wet[si]=w end return end def get_speed(s) if m=/^([0-9.]*)([MGT])$/.match(s) t={"M"=>1,"G"=>1000,"T"=>1000000} return w=m[1].to_f*t[m[2]] end w=case s when "FE" then 100.0 when "GE" then 1000.0 when "10GE" then 10000.0 when "25GE" then 25000.0 when "40GE" then 40000.0 when "100GE" then 100000.0 when "E1" then 2.0 when "E2" then 8.4 when "E3" then 34.4 when "E4" then 139.3 when "E5" then 564.9 when "T1" then 1.5 when "T1C" then 3.1 when "T2" then 6.3 when "T3" then 44.7 when "T4" then 274.1 when "T5" then 400.3 when "DS1" then 1.5 when "DS1C" then 3.1 when "DS2" then 6.3 when "DS3" then 44.7 when "DS4" then 274.1 when "DS5" then 400.3 when "STM-0" then 51.8 when "STM-1" then 155.5 when "STM-4" then 622.0 when "STM-16" then 2488.3 when "STM-64" then 9953.2 when "STM-256" then 39813.1 when "STM-1024" then 159252.4 when "OC-1" then 51.8 when "OC-3" then 155.5 when "OC-12" then 622.0 when "OC-24" then 1244.1 when "OC-48" then 2488.3 when "OC-192" then 9953.2 when "OC-768" then 39813.1 when "OC-3072" then 159252.4 else s.to_f end return w end def mk_wet(str) m=/\<(.*)\>/.match(str) return nil if !m wet={} if not m[1].include?(":") w=get_speed(m[1]) wet["*"]=w return wet end tmp=m[1].split(" ") spd={} for t in tmp m=/(.*):(.*)/.match(t) next if !m m[2].split(",").each do |g| spd[g]=get_speed(m[1]) end end wet["*"]=spd["*"] if spd["*"] if m=/\|(.*)\|/.match(str) idx=1 for s in m[1].split(" ") si=idx.to_s _grp_expand(wet,spd[si],s) idx+=1 end end return wet end def port_speed(p,wet=nil) w=case p when /^Et[0-9]/ then 10.0 when /^Fa[0-9]/ then 100.0 when /^Gi[0-9]/ then 1000.0 when /^Te[0-9]/ then 10000.0 when /^Fo[0-9]/ then 40000.0 when /^Hu[0-9]/ then 100000.0 else nil end return w if w return 0.0 if !wet return wet[p] if wet[p] return wet["*"] if wet["*"] return 0.0 end def load_file(buf,fn) dir=File.dirname(fn) begin f=File.open(fn,"r") rescue $stderr.puts ME+"unable to open file" exit end for l in f l.chop! next if l.empty? next if /^! /.match(l) buf.push(l) end f.close end def get_fields(fld) fields=[] ft=[] zf=nil zc=0 tc=0 for t in fld.downcase.scan(/[^\t]+\t*/) s=t.delete("\t") if s.start_with?("_") s.slice!("_") zf=s zc=tc else fields<0 fields<] [-X ] ..." puts " -n - just validate (aka dry-run)" puts " -I - include devices matching RegEx " puts " -X - exclude devices matching RegEx " puts " -e - do simple math expr on every record" exit end $os="Unix" $os="Cygwin" if ENV["OS"]=="Windows_NT" $os="WSL" if ENV["WSLENV"] i=0 while i=ARGV.length for l in $stdin l.chop! next if l.empty? next if /^! /.match(l) next if /^<[^>]*>$/.match(l) buf.push(l) end else while i]*>$/.match(l) buf.push(l) end else load_file(buf,fn) end end end $nodes={} $links=[] for s in buf if tmp=/^# +([^ ]*)/.match(s) nm=tmp[1] m=/\[([^ ]*)\]/.match(s) ip=(m) ? m[1] : nil m=/"([^"]*)"/.match(s) loc=(m) ? m[1] : nil m=/\{(.*)\}/.match(s) type=(m) ? m[1] : nil tp=(type) ? get_node_type2(type) : get_node_type(nm) next if $nodes[nm] next if in_list(nm,$excl) next if not $incl.empty? and not in_list(nm,$incl) $nodes[nm]=Node.new(nm,ip,tp,loc) end end inbl=igbl=false hdr=fld=wet=nil fields=ft=nil n1=n2=nil p1=p2=nil lp=nil l=bl=nil vlan=nil sln=nil for s in buf if inbl if /^--+/.match(s) inbl=igbl=false hdr=fld=wet=nil idx=ln=nil fields=ft=nil n1=n2=nil p1=p2=nil lp=nil l=bl=nil vlan=nil sln=nil next end next if igbl next if !n1 tmp=s.split(/\t+/) next if tmp.length<2 if tmp[0].empty? next if !l c=tmp.length tc=/\t+/.match(s)[0].length i=ft.index(tc) next if !i or i<1 if i==1 i=j=2 c-=1 if tmp[1].start_with?("!") str=tmp[1].sub(/^! ?/,"") l.fset($exfld,str) elsif not tmp[1].start_with?("-") sln=tmp[1] end else j=1 end while c>1 next if !f=fields[i] if tmp[j].start_with?("!") str=tmp[j].sub(/^! ?/,"") l.fset($exfld,str) else l.fset(f,tmp[j]) end i+=1 j+=1 c-=1 end next end if sln t1=sln.split(":") nm=t1[0] p2=(t1[1]) ? t1[1] : "NULL" if !n2=$nodes[nm] ok=($hdrs) ? false : true ok && ok=false if not $incl.empty? and not in_list(nm,$incl) ok && ok=false if in_list(nm,$excl) if ok n2=Node.new(nm,nil,get_node_type(nm)) $nodes[nm]=n2 end end $links<0.0 and (we1==0.0 or we2\n" f.puts "" f.puts "" f.puts <<'EOF'
EOF f.close if $os=="Cygwin" fork { exec("start /tmp/links.htm") } exit end exit if !cmd=ENV["BLWB"] fork do system(cmd+" /tmp/links.htm") end