Tor 0.4.9.0-alpha-dev
ht.h
1/* Copyright (c) 2002, Christopher Clark.
2 * Copyright (c) 2005-2006, Nick Mathewson.
3 * Copyright (c) 2007-2019, The Tor Project, Inc. */
4/* See license at end. */
5
6/* Based on ideas by Christopher Clark and interfaces from Niels Provos. */
7
8/*
9 These macros provide an intrustive implementation for a typesafe chaining
10 hash table, loosely based on the BSD tree.h and queue.h macros. Here's
11 how to use them.
12
13 First, pick a the structure that you'll be storing in the hashtable. Let's
14 say that's "struct dinosaur". To this structure, you add an HT_ENTRY()
15 member, as such:
16
17 struct dinosaur {
18 HT_ENTRY(dinosaur) node; // The name inside the () must match the
19 // struct.
20
21 // These are just fields from the dinosaur structure...
22 long dinosaur_id;
23 char *name;
24 long age;
25 int is_ornithischian;
26 int is_herbivorous;
27 };
28
29 You can declare the hashtable itself as:
30
31 HT_HEAD(dinosaur_ht, dinosaur);
32
33 This declares a new 'struct dinosaur_ht' type.
34
35 Now you need to declare two functions to help implement the hashtable: one
36 compares two dinosaurs for equality, and one computes the hash of a
37 dinosaur. Let's say that two dinosaurs are equal if they have the same ID
38 and name.
39
40 int
41 dinosaurs_equal(const struct dinosaur *d1, const struct dinosaur *d2)
42 {
43 return d1->dinosaur_id == d2->dinosaur_id &&
44 0 == strcmp(d1->name, d2->name);
45 }
46
47 unsigned
48 dinosaur_hash(const struct dinosaur *d)
49 {
50 // This is a very bad hash function. Use siphash24g instead.
51 return (d->dinosaur_id + d->name[0] ) * 1337 + d->name[1] * 1337;
52 }
53
54 Now you'll need to declare the functions that manipulate the hash table.
55 To do this, you put this declaration either in a header file, or inside
56 a regular module, depending on what visibility you want.
57
58 HT_PROTOTYPE(dinosaur_ht, // The name of the hashtable struct
59 dinosaur, // The name of the element struct,
60 node, // The name of HT_ENTRY member
61 dinosaur_hash, dinosaurs_equal);
62
63 Later, inside a C function, you use this macro to declare the hashtable
64 functions.
65
66 HT_GENERATE2(dinosaur_ht, dinosaur, node, dinosaur_hash, dinosaurs_equal,
67 0.6, tor_reallocarray, tor_free_);
68
69 Note the use of tor_free_, not tor_free. The 0.6 is magic.
70
71 Now you can use the hashtable! You can initialize one with
72
73 struct dinosaur_ht my_dinos = HT_INITIALIZER();
74
75 Or create one in core with
76
77 struct dinosaur_ht *dinos = tor_malloc(sizeof(dinosaur_ht));
78 HT_INIT(dinosaur_ht, dinos);
79
80 To the hashtable, you use the HT_FOO(dinosaur_ht, ...) macros. For
81 example, to put new_dino into dinos, you say:
82
83 HT_REPLACE(dinosaur_ht, dinos, new_dino);
84
85 If you're searching for an element, you need to use a dummy 'key' element in
86 the search. For example.
87
88 struct dinosaur dino_key;
89 dino_key.dinosaur_id = 12345;
90 dino_key.name = tor_strdup("Atrociraptor");
91
92 struct dinosaur *found = HT_FIND(dinosaurs_ht, dinos, &dino_key);
93
94 Have fun with your hash table!
95
96 */
97
98#ifndef HT_H_INCLUDED_
99#define HT_H_INCLUDED_
100
101#define HT_HEAD(name, type) \
102 struct name { \
103 /* The hash table itself. */ \
104 struct type **hth_table; \
105 /* How long is the hash table? */ \
106 unsigned hth_table_length; \
107 /* How many elements does the table contain? */ \
108 unsigned hth_n_entries; \
109 /* How many elements will we allow in the table before resizing it? */ \
110 unsigned hth_load_limit; \
111 /* Position of hth_table_length in the primes table. */ \
112 int hth_prime_idx; \
113 }
114
115#define HT_INITIALIZER() \
116 { NULL, 0, 0, 0, -1 }
117
118#ifdef HT_NO_CACHE_HASH_VALUES
119#define HT_ENTRY(type) \
120 struct { \
121 struct type *hte_next; \
122 }
123#else
124#define HT_ENTRY(type) \
125 struct { \
126 struct type *hte_next; \
127 unsigned hte_hash; \
128 }
129#endif
130
131/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
132#define HT_EMPTY(head) \
133 (((head)->hth_n_entries == 0) || 0)
134
135/* How many elements in 'head'? */
136#define HT_SIZE(head) \
137 ((head)->hth_n_entries)
138
139/* Return memory usage for a hashtable (not counting the entries themselves) */
140#define HT_MEM_USAGE(head) \
141 (sizeof(*head) + (head)->hth_table_length * sizeof(void*))
142
143#define HT_FIND(name, head, elm) name##_HT_FIND((head), (elm))
144#define HT_INSERT(name, head, elm) name##_HT_INSERT((head), (elm))
145#define HT_REPLACE(name, head, elm) name##_HT_REPLACE((head), (elm))
146#define HT_REMOVE(name, head, elm) name##_HT_REMOVE((head), (elm))
147#define HT_START(name, head) name##_HT_START(head)
148#define HT_NEXT(name, head, elm) name##_HT_NEXT((head), (elm))
149#define HT_NEXT_RMV(name, head, elm) name##_HT_NEXT_RMV((head), (elm))
150#define HT_CLEAR(name, head) name##_HT_CLEAR(head)
151#define HT_INIT(name, head) name##_HT_INIT(head)
152#define HT_REP_IS_BAD_(name, head) name##_HT_REP_IS_BAD_(head)
153#define HT_FOREACH_FN(name, head, fn, data) \
154 name##_HT_FOREACH_FN((head), (fn), (data))
155/* Helper: */
156static inline unsigned
157ht_improve_hash(unsigned h)
158{
159 /* Aim to protect against poor hash functions by adding logic here
160 * - logic taken from java 1.4 hashtable source */
161 h += ~(h << 9);
162 h ^= ((h >> 14) | (h << 18)); /* >>> */
163 h += (h << 4);
164 h ^= ((h >> 10) | (h << 22)); /* >>> */
165 return h;
166}
167
168#if 0
169/** Basic string hash function, from Java standard String.hashCode(). */
170static inline unsigned
171ht_string_hash(const char *s)
172{
173 unsigned h = 0;
174 int m = 1;
175 while (*s) {
176 h += ((signed char)*s++)*m;
177 m = (m<<5)-1; /* m *= 31 */
178 }
179 return h;
180}
181#endif
182
183#if 0
184/** Basic string hash function, from Python's str.__hash__() */
185static inline unsigned
186ht_string_hash(const char *s)
187{
188 unsigned h;
189 const unsigned char *cp = (const unsigned char *)s;
190 h = *cp << 7;
191 while (*cp) {
192 h = (1000003*h) ^ *cp++;
193 }
194 /* This conversion truncates the length of the string, but that's ok. */
195 h ^= (unsigned)(cp-(const unsigned char*)s);
196 return h;
197}
198#endif
199
200#ifndef HT_NO_CACHE_HASH_VALUES
201#define HT_SET_HASH_(elm, field, hashfn) \
202 do { (elm)->field.hte_hash = hashfn(elm); } while (0)
203#define HT_SET_HASHVAL_(elm, field, val) \
204 do { (elm)->field.hte_hash = (val); } while (0)
205#define HT_ELT_HASH_(elm, field, hashfn) \
206 ((elm)->field.hte_hash)
207#else
208#define HT_SET_HASH_(elm, field, hashfn) \
209 ((void)0)
210#define HT_ELT_HASH_(elm, field, hashfn) \
211 (hashfn(elm))
212#define HT_SET_HASHVAL_(elm, field, val) \
213 ((void)0)
214#endif
215
216#define HT_BUCKET_NUM_(head, field, elm, hashfn) \
217 (HT_ELT_HASH_(elm,field,hashfn) % head->hth_table_length)
218
219/* Helper: alias for the bucket containing 'elm'. */
220#define HT_BUCKET_(head, field, elm, hashfn) \
221 ((head)->hth_table[HT_BUCKET_NUM_(head, field, elm, hashfn)])
222
223#define HT_FOREACH(x, name, head) \
224 for ((x) = HT_START(name, head); \
225 (x) != NULL; \
226 (x) = HT_NEXT(name, head, x))
227
228#ifndef HT_NDEBUG
229#include "lib/err/torerr.h"
230#define HT_ASSERT_(x) raw_assert(x)
231#else
232#define HT_ASSERT_(x) (void)0
233#endif
234
235/* Macro put at the end of the end of a macro definition so that it
236 * consumes the following semicolon at file scope. Used only inside ht.h. */
237#define HT_EAT_SEMICOLON__ struct ht_semicolon_eater
238
239#define HT_PROTOTYPE(name, type, field, hashfn, eqfn) \
240 int name##_HT_GROW(struct name *ht, unsigned min_capacity); \
241 void name##_HT_CLEAR(struct name *ht); \
242 int name##_HT_REP_IS_BAD_(const struct name *ht); \
243 static inline void \
244 name##_HT_INIT(struct name *head) { \
245 head->hth_table_length = 0; \
246 head->hth_table = NULL; \
247 head->hth_n_entries = 0; \
248 head->hth_load_limit = 0; \
249 head->hth_prime_idx = -1; \
250 } \
251 /* Helper: returns a pointer to the right location in the table \
252 * 'head' to find or insert the element 'elm'. */ \
253 static inline struct type ** \
254 name##_HT_FIND_P_(struct name *head, struct type *elm) \
255 { \
256 struct type **p; \
257 if (!head->hth_table) \
258 return NULL; \
259 p = &HT_BUCKET_(head, field, elm, hashfn); \
260 while (*p) { \
261 if (eqfn(*p, elm)) \
262 return p; \
263 p = &(*p)->field.hte_next; \
264 } \
265 return p; \
266 } \
267 /* Return a pointer to the element in the table 'head' matching 'elm', \
268 * or NULL if no such element exists */ \
269 ATTR_UNUSED static inline struct type * \
270 name##_HT_FIND(const struct name *head, struct type *elm) \
271 { \
272 struct type **p; \
273 struct name *h = (struct name *) head; \
274 HT_SET_HASH_(elm, field, hashfn); \
275 p = name##_HT_FIND_P_(h, elm); \
276 return p ? *p : NULL; \
277 } \
278 /* Insert the element 'elm' into the table 'head'. Do not call this \
279 * function if the table might already contain a matching element. */ \
280 ATTR_UNUSED static inline void \
281 name##_HT_INSERT(struct name *head, struct type *elm) \
282 { \
283 struct type **p; \
284 if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \
285 name##_HT_GROW(head, head->hth_n_entries+1); \
286 ++head->hth_n_entries; \
287 HT_SET_HASH_(elm, field, hashfn); \
288 p = &HT_BUCKET_(head, field, elm, hashfn); \
289 elm->field.hte_next = *p; \
290 *p = elm; \
291 } \
292 /* Insert the element 'elm' into the table 'head'. If there already \
293 * a matching element in the table, replace that element and return \
294 * it. */ \
295 ATTR_UNUSED static inline struct type * \
296 name##_HT_REPLACE(struct name *head, struct type *elm) \
297 { \
298 struct type **p, *r; \
299 if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \
300 name##_HT_GROW(head, head->hth_n_entries+1); \
301 HT_SET_HASH_(elm, field, hashfn); \
302 p = name##_HT_FIND_P_(head, elm); \
303 HT_ASSERT_(p != NULL); /* this holds because we called HT_GROW */ \
304 r = *p; \
305 *p = elm; \
306 if (r && (r!=elm)) { \
307 elm->field.hte_next = r->field.hte_next; \
308 r->field.hte_next = NULL; \
309 return r; \
310 } else { \
311 ++head->hth_n_entries; \
312 return NULL; \
313 } \
314 } \
315 /* Remove any element matching 'elm' from the table 'head'. If such \
316 * an element is found, return it; otherwise return NULL. */ \
317 ATTR_UNUSED static inline struct type * \
318 name##_HT_REMOVE(struct name *head, struct type *elm) \
319 { \
320 struct type **p, *r; \
321 HT_SET_HASH_(elm, field, hashfn); \
322 p = name##_HT_FIND_P_(head,elm); \
323 if (!p || !*p) \
324 return NULL; \
325 r = *p; \
326 *p = r->field.hte_next; \
327 r->field.hte_next = NULL; \
328 --head->hth_n_entries; \
329 return r; \
330 } \
331 /* Invoke the function 'fn' on every element of the table 'head', \
332 * using 'data' as its second argument. If the function returns \
333 * nonzero, remove the most recently examined element before invoking \
334 * the function again. */ \
335 ATTR_UNUSED static inline void \
336 name##_HT_FOREACH_FN(struct name *head, \
337 int (*fn)(struct type *, void *), \
338 void *data) \
339{ \
340 unsigned idx; \
341 struct type **p, **nextp, *next; \
342 if (!head->hth_table) \
343 return; \
344 for (idx=0; idx < head->hth_table_length; ++idx) { \
345 p = &head->hth_table[idx]; \
346 while (*p) { \
347 nextp = &(*p)->field.hte_next; \
348 next = *nextp; \
349 if (fn(*p, data)) { \
350 --head->hth_n_entries; \
351 *p = next; \
352 } else { \
353 p = nextp; \
354 } \
355 } \
356 } \
357 } \
358 /* Return a pointer to the first element in the table 'head', under \
359 * an arbitrary order. This order is stable under remove operations, \
360 * but not under others. If the table is empty, return NULL. */ \
361 ATTR_UNUSED static inline struct type ** \
362 name##_HT_START(struct name *head) \
363 { \
364 unsigned b = 0; \
365 while (b < head->hth_table_length) { \
366 if (head->hth_table[b]) { \
367 HT_ASSERT_(b == \
368 HT_BUCKET_NUM_(head,field,head->hth_table[b],hashfn)); \
369 return &head->hth_table[b]; \
370 } \
371 ++b; \
372 } \
373 return NULL; \
374 } \
375 /* Return the next element in 'head' after 'elm', under the arbitrary \
376 * order used by HT_START. If there are no more elements, return \
377 * NULL. If 'elm' is to be removed from the table, you must call \
378 * this function for the next value before you remove it, or use \
379 * HT_NEXT_RMV instead. \
380 */ \
381 ATTR_UNUSED static inline struct type ** \
382 name##_HT_NEXT(struct name *head, struct type **elm) \
383 { \
384 if ((*elm)->field.hte_next) { \
385 HT_ASSERT_(HT_BUCKET_NUM_(head,field,*elm,hashfn) == \
386 HT_BUCKET_NUM_(head,field,(*elm)->field.hte_next,hashfn)); \
387 return &(*elm)->field.hte_next; \
388 } else { \
389 unsigned b = HT_BUCKET_NUM_(head,field,*elm,hashfn)+1; \
390 while (b < head->hth_table_length) { \
391 if (head->hth_table[b]) { \
392 HT_ASSERT_(b == \
393 HT_BUCKET_NUM_(head,field,head->hth_table[b],hashfn)); \
394 return &head->hth_table[b]; \
395 } \
396 ++b; \
397 } \
398 return NULL; \
399 } \
400 } \
401 /* As HT_NEXT, but also remove the current element 'elm' from the \
402 * table. */ \
403 ATTR_UNUSED static inline struct type ** \
404 name##_HT_NEXT_RMV(struct name *head, struct type **elm) \
405 { \
406 unsigned h = HT_ELT_HASH_(*elm, field, hashfn); \
407 *elm = (*elm)->field.hte_next; \
408 --head->hth_n_entries; \
409 if (*elm) { \
410 return elm; \
411 } else { \
412 unsigned b = (h % head->hth_table_length)+1; \
413 while (b < head->hth_table_length) { \
414 if (head->hth_table[b]) \
415 return &head->hth_table[b]; \
416 ++b; \
417 } \
418 return NULL; \
419 } \
420 } \
421 HT_EAT_SEMICOLON__
422
423#define HT_GENERATE2(name, type, field, hashfn, eqfn, load, reallocarrayfn, \
424 freefn) \
425 /* Primes that aren't too far from powers of two. We stop at */ \
426 /* P=402653189 because P*sizeof(void*) is less than SSIZE_MAX */ \
427 /* even on a 32-bit platform. */ \
428 static unsigned name##_PRIMES[] = { \
429 53, 97, 193, 389, \
430 769, 1543, 3079, 6151, \
431 12289, 24593, 49157, 98317, \
432 196613, 393241, 786433, 1572869, \
433 3145739, 6291469, 12582917, 25165843, \
434 50331653, 100663319, 201326611, 402653189 \
435 }; \
436 static unsigned name##_N_PRIMES = \
437 (unsigned)(sizeof(name##_PRIMES)/sizeof(name##_PRIMES[0])); \
438 /* Expand the internal table of 'head' until it is large enough to \
439 * hold 'size' elements. Return 0 on success, -1 on allocation \
440 * failure. */ \
441 int \
442 name##_HT_GROW(struct name *head, unsigned size) \
443 { \
444 unsigned new_len, new_load_limit; \
445 int prime_idx; \
446 struct type **new_table; \
447 if (head->hth_prime_idx == (int)name##_N_PRIMES - 1) \
448 return 0; \
449 if (head->hth_load_limit > size) \
450 return 0; \
451 prime_idx = head->hth_prime_idx; \
452 do { \
453 new_len = name##_PRIMES[++prime_idx]; \
454 new_load_limit = (unsigned)(load*new_len); \
455 } while (new_load_limit <= size && \
456 prime_idx < (int)name##_N_PRIMES); \
457 if ((new_table = reallocarrayfn(NULL, new_len, sizeof(struct type*)))) { \
458 unsigned b; \
459 memset(new_table, 0, new_len*sizeof(struct type*)); \
460 for (b = 0; b < head->hth_table_length; ++b) { \
461 struct type *elm, *next; \
462 unsigned b2; \
463 elm = head->hth_table[b]; \
464 while (elm) { \
465 next = elm->field.hte_next; \
466 b2 = HT_ELT_HASH_(elm, field, hashfn) % new_len; \
467 elm->field.hte_next = new_table[b2]; \
468 new_table[b2] = elm; \
469 elm = next; \
470 } \
471 } \
472 if (head->hth_table) \
473 freefn(head->hth_table); \
474 head->hth_table = new_table; \
475 } else { \
476 unsigned b, b2; \
477 new_table = reallocarrayfn(head->hth_table, new_len, sizeof(struct type*)); \
478 if (!new_table) return -1; \
479 memset(new_table + head->hth_table_length, 0, \
480 (new_len - head->hth_table_length)*sizeof(struct type*)); \
481 for (b=0; b < head->hth_table_length; ++b) { \
482 struct type *e, **pE; \
483 for (pE = &new_table[b], e = *pE; e != NULL; e = *pE) { \
484 b2 = HT_ELT_HASH_(e, field, hashfn) % new_len; \
485 if (b2 == b) { \
486 pE = &e->field.hte_next; \
487 } else { \
488 *pE = e->field.hte_next; \
489 e->field.hte_next = new_table[b2]; \
490 new_table[b2] = e; \
491 } \
492 } \
493 } \
494 head->hth_table = new_table; \
495 } \
496 head->hth_table_length = new_len; \
497 head->hth_prime_idx = prime_idx; \
498 head->hth_load_limit = new_load_limit; \
499 return 0; \
500 } \
501 /* Free all storage held by 'head'. Does not free 'head' itself, or \
502 * individual elements. */ \
503 void \
504 name##_HT_CLEAR(struct name *head) \
505 { \
506 if (head->hth_table) \
507 freefn(head->hth_table); \
508 head->hth_table_length = 0; \
509 name##_HT_INIT(head); \
510 } \
511 /* Debugging helper: return false iff the representation of 'head' is \
512 * internally consistent. */ \
513 int \
514 name##_HT_REP_IS_BAD_(const struct name *head) \
515 { \
516 unsigned n, i; \
517 struct type *elm; \
518 if (!head->hth_table_length) { \
519 if (!head->hth_table && !head->hth_n_entries && \
520 !head->hth_load_limit && head->hth_prime_idx == -1) \
521 return 0; \
522 else \
523 return 1; \
524 } \
525 if (!head->hth_table || head->hth_prime_idx < 0 || \
526 !head->hth_load_limit) \
527 return 2; \
528 if (head->hth_n_entries > head->hth_load_limit) \
529 return 3; \
530 if (head->hth_table_length != name##_PRIMES[head->hth_prime_idx]) \
531 return 4; \
532 if (head->hth_load_limit != (unsigned)(load*head->hth_table_length)) \
533 return 5; \
534 for (n = i = 0; i < head->hth_table_length; ++i) { \
535 for (elm = head->hth_table[i]; elm; elm = elm->field.hte_next) { \
536 if (HT_ELT_HASH_(elm, field, hashfn) != hashfn(elm)) \
537 return 1000 + i; \
538 if (HT_BUCKET_NUM_(head,field,elm,hashfn) != i) \
539 return 10000 + i; \
540 ++n; \
541 } \
542 } \
543 if (n != head->hth_n_entries) \
544 return 6; \
545 return 0; \
546 } \
547 HT_EAT_SEMICOLON__
548
549#define HT_GENERATE(name, type, field, hashfn, eqfn, load, mallocfn, \
550 reallocfn, freefn) \
551 static void * \
552 name##_reallocarray(void *arg, size_t a, size_t b) \
553 { \
554 if ((b) && (a) > SIZE_MAX / (b)) \
555 return NULL; \
556 if (arg) \
557 return reallocfn((arg),(a)*(b)); \
558 else \
559 return mallocfn((a)*(b)); \
560 } \
561 HT_GENERATE2(name, type, field, hashfn, eqfn, load, \
562 name##_reallocarray, freefn)
563
564/** Implements an over-optimized "find and insert if absent" block;
565 * not meant for direct usage by typical code, or usage outside the critical
566 * path.*/
567#define HT_FIND_OR_INSERT_(name, field, hashfn, head, eltype, elm, var, y, n) \
568 { \
569 struct name *var##_head_ = head; \
570 struct eltype **var; \
571 if (!var##_head_->hth_table || \
572 var##_head_->hth_n_entries >= var##_head_->hth_load_limit) \
573 name##_HT_GROW(var##_head_, var##_head_->hth_n_entries+1); \
574 HT_SET_HASH_((elm), field, hashfn); \
575 var = name##_HT_FIND_P_(var##_head_, (elm)); \
576 HT_ASSERT_(var); /* Holds because we called HT_GROW */ \
577 if (*var) { \
578 y; \
579 } else { \
580 n; \
581 } \
582 }
583#define HT_FOI_INSERT_(field, head, elm, newent, var) \
584 { \
585 HT_SET_HASHVAL_(newent, field, (elm)->field.hte_hash); \
586 newent->field.hte_next = NULL; \
587 *var = newent; \
588 ++((head)->hth_n_entries); \
589 }
590
591/*
592 * Copyright 2005, Nick Mathewson. Implementation logic is adapted from code
593 * by Christopher Clark, retrofit to allow drop-in memory management, and to
594 * use the same interface as Niels Provos's tree.h. This is probably still
595 * a derived work, so the original license below still applies.
596 *
597 * Copyright (c) 2002, Christopher Clark
598 * All rights reserved.
599 *
600 * Redistribution and use in source and binary forms, with or without
601 * modification, are permitted provided that the following conditions
602 * are met:
603 *
604 * * Redistributions of source code must retain the above copyright
605 * notice, this list of conditions and the following disclaimer.
606 *
607 * * Redistributions in binary form must reproduce the above copyright
608 * notice, this list of conditions and the following disclaimer in the
609 * documentation and/or other materials provided with the distribution.
610 *
611 * * Neither the name of the original author; nor the names of any contributors
612 * may be used to endorse or promote products derived from this software
613 * without specific prior written permission.
614 *
615 *
616 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
617 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
618 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
619 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
620 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
621 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
622 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
623 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
624 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
625 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
626 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
627*/
628
629#endif
Headers for torerr.c.