allow wcore to coexist with other windows
[lcore.git] / binipstuff.pas
1 { Copyright (C) 2005 Bas Steendijk and Peter Green\r
2   For conditions of distribution and use, see copyright notice in zlib_license.txt\r
3   which is included in the package\r
4   ----------------------------------------------------------------------------- }\r
5 unit binipstuff;\r
6 \r
7 interface\r
8 \r
9 {$include lcoreconfig.inc}\r
10 \r
11 uses\r
12 {$ifndef win32}\r
13   sockets,\r
14 {$endif}\r
15   pgtypes;\r
16 \r
17 {$ifdef fpc}\r
18   {$mode delphi}\r
19 {$endif}\r
20 {$ifdef cpu386}{$define i386}{$endif}\r
21 {$ifdef i386}{$define ENDIAN_LITTLE}{$endif}\r
22 \r
23 {$include uint32.inc}\r
24 \r
25 const\r
26   hexchars:array[0..15] of ansichar='0123456789abcdef';\r
27   {$ifdef win32}\r
28     AF_INET=2;\r
29     AF_INET6=23;\r
30   {$else}\r
31     //redeclare these constants so units that use us can use them\r
32     //without using sockets directly\r
33     AF_INET=AF_INET;\r
34     AF_INET6=AF_INET6;\r
35     //AF_INET6=10;\r
36   {$endif}\r
37 \r
38 type\r
39   {$ifdef ipv6}\r
40     \r
41     {$ifdef win32}\r
42       {$define want_Tin6_addr}\r
43     {$endif}\r
44     {$ifdef ver1_0}\r
45       {$define want_Tin6_addr}\r
46     {$endif}\r
47     {$ifdef want_Tin6_addr}\r
48       Tin6_addr = packed record\r
49         case byte of\r
50           0: (u6_addr8  : array[0..15] of byte);\r
51           1: (u6_addr16 : array[0..7] of Word);\r
52           2: (u6_addr32 : array[0..3] of uint32);\r
53           3: (s6_addr8  : array[0..15] of shortint);\r
54           4: (s6_addr   : array[0..15] of shortint);\r
55           5: (s6_addr16 : array[0..7] of smallint);\r
56           6: (s6_addr32 : array[0..3] of LongInt);\r
57       end;\r
58     {$endif}\r
59   {$endif}\r
60 \r
61   tbinip=record\r
62     family:integer;\r
63     {$ifdef ipv6}\r
64       case integer of\r
65         0: (ip:longint);\r
66         1: (ip6:tin6_addr);\r
67     {$else}\r
68       ip:longint;\r
69     {$endif}\r
70   end;\r
71 \r
72   {$ifdef win32}\r
73     TInetSockAddr = packed Record\r
74       family:Word;\r
75       port  :Word;\r
76       addr  :uint32;\r
77       pad   :array [1..8] of byte;\r
78     end;\r
79     {$ifdef ipv6}\r
80 \r
81       TInetSockAddr6 = packed record\r
82         sin6_family: word;\r
83         sin6_port: word;\r
84         sin6_flowinfo: uint32;\r
85         sin6_addr: tin6_addr;\r
86         sin6_scope_id: uint32;\r
87       end;\r
88     {$endif}\r
89   {$endif}\r
90 \r
91 \r
92 \r
93   {$ifdef ipv6}\r
94     {$ifdef ver1_0}\r
95       cuint16=word;\r
96       cuint32=dword;\r
97       sa_family_t=word;\r
98 \r
99       TInetSockAddr6 = packed record\r
100         sin6_family: word;\r
101         sin6_port: word;\r
102         sin6_flowinfo: uint32;\r
103         sin6_addr: tin6_addr;\r
104         sin6_scope_id: uint32;\r
105       end;\r
106     {$endif}\r
107   {$endif}\r
108   TinetSockAddrv = packed record\r
109     case integer of\r
110       0: (InAddr:TInetSockAddr);\r
111       {$ifdef ipv6}\r
112       1: (InAddr6:TInetSockAddr6);\r
113       {$endif}\r
114   end;\r
115   Pinetsockaddrv = ^Tinetsockaddrv;\r
116 \r
117   type\r
118     tsockaddrin=TInetSockAddr;\r
119 \r
120 \r
121 \r
122 {\r
123 bin IP list code, by beware\r
124 while this is really just a string, on the interface side it must be treated\r
125 as an opaque var which is passed as "var" when it needs to be modified}\r
126 \r
127   tbiniplist=tbufferstring;\r
128 \r
129 function biniplist_new:tbiniplist;\r
130 procedure biniplist_add(var l:tbiniplist;ip:tbinip);\r
131 function biniplist_getcount(const l:tbiniplist):integer;\r
132 function biniplist_get(const l:tbiniplist;index:integer):tbinip;\r
133 procedure biniplist_set(var l:tbiniplist;index:integer;ip:tbinip);\r
134 procedure biniplist_setcount(var l:tbiniplist;newlen:integer);\r
135 procedure biniplist_free(var l:tbiniplist);\r
136 procedure biniplist_addlist(var l:tbiniplist;const l2:tbiniplist);\r
137 function biniplist_tostr(const l:tbiniplist):thostname;\r
138 function isbiniplist(const l:tbiniplist):boolean;\r
139 \r
140 function htons(w:word):word;\r
141 function htonl(i:uint32):uint32;\r
142 \r
143 function ipstrtobin(const s:thostname;var binip:tbinip):boolean;\r
144 function ipstrtobinf(const s:thostname):tbinip;\r
145 function ipbintostr(const binip:tbinip):thostname;\r
146 {$ifdef ipv6}\r
147 function ip6bintostr(const bin:tin6_addr):thostname;\r
148 function ip6strtobin(const s:thostname;var bin:tin6_addr):boolean;\r
149 {$endif}\r
150 \r
151 function comparebinip(const ip1,ip2:tbinip):boolean;\r
152 procedure maskbits(var binip:tbinip;bits:integer);\r
153 function comparebinipmask(ip1,ip2:tbinip;bits:integer):boolean;\r
154 \r
155 procedure addipsoffamily(var l:tbiniplist;const l2:tbiniplist;family:integer);\r
156 \r
157 {deprecated}\r
158 function longip(s:thostname):longint;\r
159 \r
160 function needconverttov4(const ip:tbinip):boolean;\r
161 procedure converttov4(var ip:tbinip);\r
162 procedure converttov6(var ip:tbinip);\r
163 \r
164 function inaddrvtobinip(inaddrv:tinetsockaddrv):tbinip;\r
165 function makeinaddrv(addr:tbinip;port:ansistring;var inaddr:tinetsockaddrv):integer;\r
166 function inaddrsize(inaddr:tinetsockaddrv):integer;\r
167 \r
168 implementation\r
169 \r
170 uses sysutils;\r
171 \r
172 function htons(w:word):word;\r
173 begin\r
174   {$ifdef ENDIAN_LITTLE}\r
175   result := ((w and $ff00) shr 8) or ((w and $ff) shl 8);\r
176   {$else}\r
177   result := w;\r
178   {$endif}\r
179 end;\r
180 \r
181 function htonl(i:uint32):uint32;\r
182 begin\r
183   {$ifdef ENDIAN_LITTLE}\r
184   result := (i shr 24) or (i shr 8 and $ff00) or (i shl 8 and $ff0000) or (i shl 24 and $ff000000);\r
185   {$else}\r
186   result := i;\r
187   {$endif}\r
188 end;\r
189 \r
190 \r
191 function inaddrvtobinip(inaddrv:tinetsockaddrv):tbinip;\r
192 begin\r
193   result.family := inaddrv.inaddr.family;\r
194   if result.family = AF_INET then result.ip := inaddrv.inaddr.addr;\r
195   {$ifdef ipv6}\r
196   if result.family = AF_INET6 then result.ip6 := inaddrv.inaddr6.sin6_addr;\r
197   {$endif}\r
198 end;\r
199 \r
200 function makeinaddrv(addr:tbinip;port:ansistring;var inaddr:tinetsockaddrv):integer;\r
201 begin\r
202   result := 0;\r
203 {  biniptemp := forwardlookup(addr,10);}\r
204   fillchar(inaddr,sizeof(inaddr),0);\r
205   //writeln('converted address '+addr+' to binip '+ipbintostr(biniptemp));\r
206   if addr.family = AF_INET then begin\r
207     inAddr.InAddr.family:=AF_INET;\r
208     inAddr.InAddr.port:=htons(strtointdef(port,0));\r
209     inAddr.InAddr.addr:=addr.ip;\r
210     result := sizeof(tinetsockaddr);\r
211   end else\r
212   {$ifdef ipv6}\r
213   if addr.family = AF_INET6 then begin\r
214     inAddr.InAddr6.sin6_family:=AF_INET6;\r
215     inAddr.InAddr6.sin6_port:=htons(strtointdef(port,0));\r
216     inAddr.InAddr6.sin6_addr:=addr.ip6;\r
217     result := sizeof(tinetsockaddr6);\r
218   end;\r
219   {$endif}\r
220 end;\r
221 \r
222 function inaddrsize(inaddr:tinetsockaddrv):integer;\r
223 begin\r
224   {$ifdef ipv6}\r
225   if inaddr.inaddr.family = AF_INET6 then result := sizeof(tinetsockaddr6) else\r
226   {$endif}\r
227   result := sizeof(tinetsockaddr);\r
228 end;\r
229 \r
230 {internal}\r
231 {converts dotted v4 IP to longint. returns host endian order}\r
232 function longip(s:thostname):longint;\r
233 var\r
234   l:longint;\r
235   a,b:integer;\r
236 function convertbyte(const s:ansistring):integer;\r
237 begin\r
238   result := strtointdef(s,-1);\r
239   if result < 0 then begin\r
240     result := -1;\r
241     exit;\r
242   end;\r
243   if result > 255 then begin\r
244     result := -1;\r
245     exit;\r
246   end;\r
247   {01 exception}\r
248   if (result <> 0) and (s[1] = '0') then begin\r
249     result := -1;\r
250     exit;\r
251   end;\r
252   {+1 exception}\r
253   if not (s[1] in ['0'..'9']) then begin\r
254     result := -1;\r
255     exit\r
256   end;\r
257 end;\r
258 \r
259 begin\r
260   result := 0;\r
261   a := pos('.',s);\r
262   if a = 0 then exit;\r
263   b := convertbyte(copy(s,1,a-1));if (b < 0) then exit;\r
264   l := b shl 24;\r
265   s := copy(s,a+1,256);\r
266   a := pos('.',s);\r
267   if a = 0 then exit;\r
268   b := convertbyte(copy(s,1,a-1));if (b < 0) then exit;\r
269   l := l or b shl 16;\r
270   s := copy(s,a+1,256);\r
271   a := pos('.',s);\r
272   if a = 0 then exit;\r
273   b := convertbyte(copy(s,1,a-1));if (b < 0) then exit;\r
274   l := l or b shl 8;\r
275   s := copy(s,a+1,256);\r
276   b := convertbyte(copy(s,1,256));if (b < 0) then exit;\r
277   l := l or b;\r
278   result := l;\r
279 end;\r
280 \r
281 \r
282 function ipstrtobinf;\r
283 begin\r
284   ipstrtobin(s,result);\r
285 end;\r
286 \r
287 function ipstrtobin(const s:thostname;var binip:tbinip):boolean;\r
288 begin\r
289   binip.family := 0;\r
290   result := false;\r
291   {$ifdef ipv6}\r
292   if pos(':',s) <> 0 then begin\r
293     {try ipv6. use builtin routine}\r
294     result := ip6strtobin(s,binip.ip6);\r
295     if result then binip.family := AF_INET6;\r
296     exit;\r
297   end;\r
298   {$endif}\r
299 \r
300   {try v4}\r
301   binip.ip := htonl(longip(s));\r
302   if (binip.ip <> 0) or (s = '0.0.0.0') then begin\r
303     result := true;\r
304     binip.family := AF_INET;\r
305     exit;\r
306   end;\r
307 end;\r
308 \r
309 function ipbintostr(const binip:tbinip):thostname;\r
310 var\r
311   a:integer;\r
312 begin\r
313   result := '';\r
314   {$ifdef ipv6}\r
315   if binip.family = AF_INET6 then begin\r
316     result := ip6bintostr(binip.ip6);\r
317   end else\r
318   {$endif}\r
319   if binip.family = AF_INET then begin\r
320     a := htonl(binip.ip);\r
321     result := inttostr(a shr 24)+'.'+inttostr((a shr 16) and $ff)+'.'+inttostr((a shr 8) and $ff)+'.'+inttostr(a and $ff);\r
322   end;\r
323 end;\r
324 \r
325 \r
326 {------------------------------------------------------------------------------}\r
327 \r
328 {$ifdef ipv6}\r
329 \r
330 {\r
331 IPv6 address binary to/from string conversion routines\r
332 written by beware\r
333 \r
334 - implementation does not depend on other ipv6 code such as the tin6_addr type,\r
335   the parameter can also be untyped.\r
336 - it is host endian neutral - binary format is aways network order\r
337 - it supports compression of zeroes\r
338 - it supports ::ffff:192.168.12.34 style addresses\r
339 - they are made to do the Right Thing, more efficient implementations are possible\r
340 }\r
341 \r
342 {fpc has hostaddrtostr6 and strtohostaddr6 but the later isnt implemented yet}\r
343 \r
344 \r
345 function ip6bintostr(const bin:tin6_addr):thostname;\r
346 {base16 with lowercase output}\r
347 function makehex(w:word):ansistring;\r
348 begin\r
349   result := '';\r
350   if w >= 4096 then result := result + hexchars[w shr 12];\r
351   if w >= 256 then result := result + hexchars[w shr 8 and $f];\r
352   if w >= 16 then result := result + hexchars[w shr 4 and $f];\r
353   result := result + hexchars[w and $f];\r
354 end;\r
355 \r
356 var\r
357   a,b,c,addrlen:integer;\r
358   runbegin,runlength:integer;\r
359   bytes:array[0..15] of byte absolute bin;\r
360   words:array[0..7] of word;\r
361   dwords:array[0..3] of integer absolute words;\r
362 begin\r
363   for a := 0 to 7 do begin\r
364     words[a] := bytes[a shl 1] shl 8 or bytes[a shl 1 or 1];\r
365   end;\r
366   if (dwords[0] = 0) and (dwords[1] = 0) and (words[4] = 0) and (words[5] = $ffff) then begin\r
367     {::ffff:/96 exception: v4 IP}\r
368     addrlen := 6;\r
369   end else begin\r
370     addrlen := 8;\r
371   end;\r
372   {find longest run of zeroes}\r
373   runbegin := 0;\r
374   runlength := 0;\r
375   for a := 0 to addrlen-1 do begin\r
376     if words[a] = 0 then begin\r
377       c := 0;\r
378       for b := a to addrlen-1 do if words[b] = 0 then begin\r
379         inc(c);\r
380       end else break;\r
381       if (c > runlength) then begin\r
382         runlength := c;\r
383         runbegin := a;\r
384       end;\r
385     end;\r
386   end;\r
387 \r
388   {run length atleast 2 0 words}\r
389   if (runlength = 1) then begin\r
390     runlength := 0;\r
391     runbegin := 0;\r
392   end;\r
393 \r
394   result := '';\r
395   for a := 0 to runbegin-1 do begin\r
396     if (a <> 0) then result := result + ':';\r
397     result := result + makehex(words[a]);\r
398   end;\r
399   if runlength > 0 then result := result + '::';\r
400   c := runbegin+runlength;\r
401   for a := c to addrlen-1 do begin\r
402     if (a > c) then result := result + ':';\r
403     result := result + makehex(words[a]);\r
404   end;\r
405   if addrlen = 6 then begin\r
406     result := result + ':'+inttostr(bytes[12])+'.'+inttostr(bytes[13])+'.'+inttostr(bytes[14])+'.'+inttostr(bytes[15]);\r
407   end;\r
408 end;\r
409 \r
410 function ip6strtobin(const s:thostname;var bin:tin6_addr):boolean;\r
411 var\r
412   a,b:integer;\r
413   fields:array[0..7] of ansistring;\r
414   fieldcount:integer;\r
415   emptyfield:integer;\r
416   wordcount:integer;\r
417   words:array[0..7] of word;\r
418   bytes:array[0..15] of byte absolute bin;\r
419 begin\r
420   result := false;\r
421   for a := 0 to 7 do fields[a] := '';\r
422   fieldcount := 0;\r
423   for a := 1 to length(s) do begin\r
424     if s[a] = ':' then inc(fieldcount) else fields[fieldcount] := fields[fieldcount] + s[a];\r
425     if fieldcount > 7 then exit;\r
426   end;\r
427   if fieldcount < 2 then exit;\r
428 \r
429   {find the empty field (compressed zeroes), not counting the first and last there may be at most 1}\r
430   emptyfield := -1;\r
431   for a := 1 to fieldcount-1 do begin\r
432     if fields[a] = '' then begin\r
433       if emptyfield = -1 then emptyfield := a else exit;\r
434     end;\r
435   end;\r
436 \r
437   {check if last field is a valid v4 IP}\r
438   a := longip(fields[fieldcount]);\r
439   if (a <> 0) or (fields[fieldcount] = '0.0.0.0') then wordcount := 6 else wordcount := 8;\r
440   {0:1:2:3:4:5:6.6.6.6\r
441    0:1:2:3:4:5:6:7}\r
442   fillchar(words,sizeof(words),0);\r
443   if wordcount = 6 then begin\r
444     if fieldcount > 6 then exit;\r
445     words[6] := a shr 16;\r
446     words[7] := a and $ffff;\r
447   end;\r
448   if emptyfield = -1 then begin\r
449     {no run length: must be an exact number of fields}\r
450     if wordcount = 6 then begin\r
451       if fieldcount <> 6 then exit;\r
452       emptyfield := 5;\r
453     end else if wordcount = 8 then begin\r
454       if fieldcount <> 7 then exit;\r
455       emptyfield := 7;\r
456     end else exit;\r
457   end;\r
458   for a := 0 to emptyfield do begin\r
459     if fields[a] = '' then b := 0 else b := strtointdef('$'+fields[a],-1);\r
460     if (b < 0) or (b > $ffff) then exit;\r
461     words[a] := b;\r
462   end;\r
463   if wordcount = 6 then dec(fieldcount);\r
464   for a := wordcount-1 downto wordcount-(fieldcount-emptyfield) do begin\r
465     b := a+fieldcount-wordcount+1;\r
466     if fields[b] = '' then b := 0 else b := strtointdef('$'+fields[b],-1);\r
467     if (b < 0) or (b > $ffff) then exit;\r
468     words[a] := b;\r
469   end;\r
470   for a := 0 to 7 do begin\r
471     bytes[a shl 1] := words[a] shr 8;\r
472     bytes[a shl 1 or 1] := words[a] and $ff;\r
473   end;\r
474   result := true;\r
475 end;\r
476 {$endif}\r
477 \r
478 function comparebinip(const ip1,ip2:tbinip):boolean;\r
479 begin\r
480   if (ip1.ip <> ip2.ip) then begin\r
481     result := false;\r
482     exit;\r
483   end;\r
484 \r
485   {$ifdef ipv6}\r
486   if ip1.family = AF_INET6 then begin\r
487     if (ip1.ip6.s6_addr32[1] <> ip2.ip6.s6_addr32[1])\r
488     or (ip1.ip6.s6_addr32[2] <> ip2.ip6.s6_addr32[2])\r
489     or (ip1.ip6.s6_addr32[3] <> ip2.ip6.s6_addr32[3]) then begin\r
490       result := false;\r
491       exit;\r
492     end;\r
493   end;\r
494   {$endif}\r
495 \r
496   result := (ip1.family = ip2.family);\r
497 end;\r
498 \r
499 procedure maskbits(var binip:tbinip;bits:integer);\r
500 const\r
501   ipmax={$ifdef ipv6}15{$else}3{$endif};\r
502 type tarr=array[0..ipmax] of byte;\r
503 var\r
504   arr:^tarr;\r
505   a,b:integer;\r
506 begin\r
507   arr := @binip.ip;\r
508   if bits = 0 then b := 0 else b := ((bits-1) div 8)+1;\r
509   for a := b to ipmax do begin\r
510     arr[a] := 0;\r
511   end;\r
512   if (bits and 7 <> 0) then begin\r
513     arr[bits shr 3] := arr[bits div 8] and not ($ff shr (bits and 7))\r
514   end;\r
515 end;\r
516 \r
517 function comparebinipmask;\r
518 begin\r
519   maskbits(ip1,bits);\r
520   maskbits(ip2,bits);\r
521   result := comparebinip(ip1,ip2);\r
522 end;\r
523 \r
524 function needconverttov4(const ip:tbinip):boolean;\r
525 begin\r
526   {$ifdef ipv6}\r
527   if ip.family = AF_INET6 then begin\r
528     if (ip.ip6.u6_addr32[0] = 0) and (ip.ip6.u6_addr32[1] = 0) and\r
529     (ip.ip6.u6_addr16[4] = 0) and (ip.ip6.u6_addr16[5] = $ffff) then begin\r
530       result := true;\r
531       exit;\r
532     end;\r
533   end;\r
534   {$endif}\r
535 \r
536   result := false;\r
537 end;\r
538 \r
539 {converts a binary IP to v4 if it is a v6 IP in the v4 range}\r
540 procedure converttov4(var ip:tbinip);\r
541 begin\r
542   {$ifdef ipv6}\r
543   if needconverttov4(ip) then begin\r
544     ip.family := AF_INET;\r
545     ip.ip := ip.ip6.s6_addr32[3];\r
546   end;\r
547   {$endif}\r
548 end;\r
549 \r
550 \r
551 {converts a binary IP to v6 if it is a v4 IP}\r
552 procedure converttov6(var ip:tbinip);\r
553 begin\r
554   {$ifdef ipv6}\r
555     if ip.family = AF_INET then begin\r
556       ip.family := AF_INET6;\r
557       ip.ip6.s6_addr32[3] := ip.ip; \r
558       ip.ip6.u6_addr32[0] := 0; \r
559       ip.ip6.u6_addr32[1] := 0;\r
560       ip.ip6.u6_addr16[4] := 0;\r
561       ip.ip6.u6_addr16[5] := $ffff;\r
562     end;\r
563   {$endif}\r
564 end;\r
565 \r
566 \r
567 {-----------biniplist stuff--------------------------------------------------}\r
568 \r
569 const\r
570   biniplist_prefix: ansistring = 'bipl'#0;\r
571   //fpc 1.0.x doesn't seem to like use of length function in a constant \r
572   //definition\r
573   //biniplist_prefixlen=length(biniplist_prefix);\r
574 \r
575   biniplist_prefixlen=5;\r
576   \r
577 function biniplist_new:tbiniplist;\r
578 begin\r
579   result := biniplist_prefix;\r
580 end;\r
581 \r
582 procedure biniplist_add(var l:tbiniplist;ip:tbinip);\r
583 var\r
584   a:integer;\r
585 begin\r
586   a := biniplist_getcount(l);\r
587   biniplist_setcount(l,a+1);\r
588   biniplist_set(l,a,ip);\r
589 end;\r
590 \r
591 function biniplist_getcount(const l:tbiniplist):integer;\r
592 begin\r
593   result := (length(l)-biniplist_prefixlen) div sizeof(tbinip);\r
594 end;\r
595 \r
596 function biniplist_get(const l:tbiniplist;index:integer):tbinip;\r
597 begin\r
598   if (index >= biniplist_getcount(l)) then begin\r
599     fillchar(result,sizeof(result),0);\r
600     exit;\r
601   end;\r
602   move(l[index*sizeof(tbinip)+1+biniplist_prefixlen],result,sizeof(result));\r
603 end;\r
604 \r
605 procedure biniplist_set(var l:tbiniplist;index:integer;ip:tbinip);\r
606 begin\r
607   uniquestring(l);\r
608   move(ip,l[index*sizeof(tbinip)+1+biniplist_prefixlen],sizeof(ip));\r
609 end;\r
610 \r
611 procedure biniplist_setcount(var l:tbiniplist;newlen:integer);\r
612 begin\r
613   setlength(l,(sizeof(tbinip)*newlen)+biniplist_prefixlen);\r
614 end;\r
615 \r
616 procedure biniplist_free(var l:tbiniplist);\r
617 begin\r
618   l := '';\r
619 end;\r
620 \r
621 procedure biniplist_addlist;\r
622 begin\r
623   l := l + copy(l2,biniplist_prefixlen+1,maxlongint);\r
624 end;\r
625 \r
626 function biniplist_tostr(const l:tbiniplist):thostname;\r
627 var\r
628   a:integer;\r
629 begin\r
630   result := '(';\r
631   for a := 0 to biniplist_getcount(l)-1 do begin\r
632     if result <> '(' then result := result + ', ';\r
633     result := result + ipbintostr(biniplist_get(l,a));\r
634   end;\r
635   result := result + ')';\r
636 end;\r
637 \r
638 function isbiniplist(const l:tbiniplist):boolean;\r
639 var\r
640   i : integer;\r
641 begin\r
642   for i := 1 to biniplist_prefixlen do begin\r
643     if biniplist_prefix[i] <> l[i] then begin\r
644       result := false;\r
645       exit;\r
646     end;\r
647   end;\r
648   result := true;\r
649 end;\r
650 \r
651 procedure addipsoffamily(var l:tbiniplist;const l2:tbiniplist;family:integer);\r
652 var\r
653   a:integer;\r
654   biniptemp:tbinip;\r
655 begin\r
656   for a := biniplist_getcount(l2)-1 downto 0 do begin\r
657     biniptemp := biniplist_get(l2,a);\r
658     if (biniptemp.family = family) then biniplist_add(l,biniptemp);\r
659   end;\r
660 end;\r
661 \r
662 \r
663 end.\r