/* pathalias -- by steve bellovin, as told to peter honeyman */
static char *sccsid
= "@(#)addnode.c 8.1 (down!honey) 86/01/19";
extern void lowercase(), rehash();
extern node
*isprivate();
* these numbers are chosen because:
* -> they are monotonic increasing,
* -> each is a tad smaller than a multiple of 1024,
* -> they form a fibonacci sequence (almost).
* the first point yields good hash functions, the second is used for the
* standard re-hashing implementation of open addressing, the third
* optimizes for quirks in some mallocs i have seen, and the fourth simply
1021, 2039, 3067, 5113, 8179,
static int Tabindex
= -1;
static int Collision
; /* mark host name collisions in hash() */
/* is it a private host? */
n
->n_name
= strsave(name
);
n
->n_tloc
= i
; /* essentially a back link to the table */
n
->n_flag
|= COLLISION
; /* name collision with private host */
l
= addlink(n1
, n2
, (Cost
) 0, DEFNET
, DEFDIR
);
l
= addlink(n2
, n1
, (Cost
) 0, DEFNET
, DEFDIR
);
* fold a string into a long int. this algorithm ignores all but the last
* eight bytes, which affects < 15% of all host names, many of which have
* common prefixes anyway.
#define HASH1(n) ((n) % Tabsize);
#define HASH2(n) (Tabsize - 2 - ((n) % (Tabsize-2))) /* princeton!rs */
* with a 0.75 high water mark, probes per access should be 1.84.
* use long constant to force promotion.
#define isfull(n, size) ((n) > ((size) * HIGHWATER) / 100)
register long probe
, hash2
;
if (Tabindex
< 0) { /* first time */
Table
= newtable(Tabsize
);
} else if (isfull(Ncount
, Tabsize
))
rehash(); /* more, more! */
/* don't change the order of the next two lines */
* if unique is set, we require a fresh slot.
* otherwise, use double hashing to find either
* (2) a non-private copy of this host name
* as a side effect, if we notice a collision with a private host
* we mark the other so that it is skipped at output time.
while ((n
= Table
[probe
]) != 0) {
if (strcmp(n
->n_name
, name
) == 0) {
else if (n
->n_flag
& ISPRIVATE
)
register node
**otable
, **optr
;
optr
= Table
+ Tabsize
- 1; /* ptr to last */
Tabsize
= Primes
[++Tabindex
];
if (Tabsize
== 0) { /* need more prime numbers */
fprintf(stderr
, "%s: > %d hosts\n", ProgName
, Primes
[Tabindex
-1]);
vprintf(stderr
, "rehash into %d\n", Tabsize
);
Table
= newtable(Tabsize
);
continue; /* empty slot in old table */
probe
= hash((*optr
)->n_name
, (*optr
)->n_flag
& ISPRIVATE
);
fprintf(stderr
, "%s: rehash error\n", ProgName
);
} while (optr
-- > otable
);
freetable(otable
, osize
);
int count
, i
, collision
[8];
int longest
= 0, total
= 0, slots
= 0;
int nslots
= sizeof(collision
)/sizeof(collision
[0]);
strclear((char *) collision
, sizeof(collision
));
for (i
= 0; i
< Tabsize
; i
++) {
/* private hosts too hard to account for ... */
if (Table
[i
]->n_flag
& ISPRIVATE
)
probe
= fold(Table
[i
]->n_name
);
/* don't change the order of the next two lines */
&& strcmp(Table
[probe
]->n_name
, Table
[i
]->n_name
) != 0) {
fprintf(stderr
, "%s: impossible hash error for %s\n",
ProgName
, Table
[i
]->n_name
);
for (i
= 1; i
< nslots
; i
++)
fprintf(stderr
, "%d chains: %d (%ld%%)\n",
i
, collision
[i
], (collision
[i
] * 100L)/ slots
);
fprintf(stderr
, "> %d chains: %d (%ld%%)\n",
nslots
- 1, collision
[0],
(collision
[0] * 100L)/ slots
);
fprintf(stderr
, "%2.2f probes per access, longest chain: %d\n",
(double) total
/ slots
, longest
);
*s
-= 'A' - 'a'; /* assumes ASCII */
* this might have to be recoded for performance if privates catch on
for (n
= Private
; n
!= 0; n
= n
->n_private
)
if (strcmp(name
, n
->n_name
) == 0)
for (n
= Private
; n
!= 0; n
= next
) {
n
->n_flag
|= ISPRIVATE
; /* overkill, but safe */
fprintf(stderr
, "%s: impossible private node error on %s\n",
n
->n_tloc
= i
; /* essentially a back link to the table */
n
->n_private
= 0; /* clear for later use */
if ((n
= isprivate(name
)) != 0)
n
->n_name
= strsave(name
);