undns 0.4.0a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/undns_decode +29 -0
- data/ext/undns/buffer.c +247 -0
- data/ext/undns/buffer.h +59 -0
- data/ext/undns/config.h +2 -0
- data/ext/undns/conventions.c +1813 -0
- data/ext/undns/conventions.h +89 -0
- data/ext/undns/conventlex.c +2808 -0
- data/ext/undns/earth.c +180 -0
- data/ext/undns/earth.h +4 -0
- data/ext/undns/exception.h +12 -0
- data/ext/undns/extconf.rb +44 -0
- data/ext/undns/filetest.c +90 -0
- data/ext/undns/filetest.h +7 -0
- data/ext/undns/hashes.c +104 -0
- data/ext/undns/hashes.h +48 -0
- data/ext/undns/hashtable.c +518 -0
- data/ext/undns/hashtable.h +103 -0
- data/ext/undns/my_ruby.h +3 -0
- data/ext/undns/nscommon.h +207 -0
- data/ext/undns/originAS.c +134 -0
- data/ext/undns/originAS.h +17 -0
- data/ext/undns/progress.c +285 -0
- data/ext/undns/progress.h +45 -0
- data/ext/undns/queue.c +346 -0
- data/ext/undns/queue.h +70 -0
- data/ext/undns/radix.c +517 -0
- data/ext/undns/radix.h +72 -0
- data/ext/undns/ruleset.c +603 -0
- data/ext/undns/ruleset.h +108 -0
- data/ext/undns/swig-undns_wrap-rb.c +2995 -0
- data/ext/undns/typed_hashtable.h +158 -0
- data/ext/undns/typed_queue.h +112 -0
- data/ext/undns/xmalloc.c +153 -0
- data/ext/undns/xmalloc.h +14 -0
- data/lib/undns.rb +5 -0
- metadata +84 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
/* (c) neil spring 2002 */
|
2
|
+
|
3
|
+
#include "nscommon.h"
|
4
|
+
#include <netinet/in.h>
|
5
|
+
|
6
|
+
void origins_init(const char *origins_dat);
|
7
|
+
unsigned short origin_for_address(in_addr_t a);
|
8
|
+
unsigned short origin_for_address_str(const char *addrstring);
|
9
|
+
|
10
|
+
boolean origin_prefix_for_address(in_addr_t a,
|
11
|
+
/*@out@*/ unsigned short *asn,
|
12
|
+
/*@out@*/ in_addr_t *prefix,
|
13
|
+
/*@out@*/ unsigned char *prefixlen);
|
14
|
+
boolean origin_prefix_for_address_str(const char *addrstring,
|
15
|
+
/*@out@*/ unsigned short *asn,
|
16
|
+
/*@out@*/ in_addr_t *prefix,
|
17
|
+
/*@out@*/ unsigned char *prefixlen);
|
@@ -0,0 +1,285 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2002
|
3
|
+
* Neil Spring and the University of Washington.
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* Redistribution and use in source and binary forms, with or without
|
7
|
+
* modification, are permitted provided that the following conditions
|
8
|
+
* are met:
|
9
|
+
* 1. Redistributions of source code must retain the above copyright
|
10
|
+
* notice, this list of conditions and the following disclaimer.
|
11
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
12
|
+
* notice, this list of conditions and the following disclaimer in the
|
13
|
+
* documentation and/or other materials provided with the distribution.
|
14
|
+
* 3. The name of the author(s) may not be used to endorse or promote
|
15
|
+
* products derived from this software without specific prior
|
16
|
+
* written permission.
|
17
|
+
*
|
18
|
+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
19
|
+
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
20
|
+
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
21
|
+
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
22
|
+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
23
|
+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
24
|
+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
25
|
+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
26
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
27
|
+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
28
|
+
*/
|
29
|
+
|
30
|
+
#ifdef HAVE_CONFIG_H
|
31
|
+
#include <config.h>
|
32
|
+
#endif
|
33
|
+
#include<float.h>
|
34
|
+
#include<assert.h>
|
35
|
+
|
36
|
+
#include"nscommon.h"
|
37
|
+
|
38
|
+
/* gettimeofday */
|
39
|
+
#include <sys/time.h>
|
40
|
+
#include <unistd.h>
|
41
|
+
|
42
|
+
#include <string.h>
|
43
|
+
|
44
|
+
#include"progress.h"
|
45
|
+
|
46
|
+
/* snprintf */
|
47
|
+
#define _GNU_SOURCE
|
48
|
+
#include <stdio.h>
|
49
|
+
#ifdef HAVE_DMALLOC_H
|
50
|
+
#include<dmalloc.h>
|
51
|
+
#endif
|
52
|
+
#ifndef HAVE_SNPRINTF
|
53
|
+
int snprintf ( char *str, size_t n, const char *format, ... );
|
54
|
+
#endif
|
55
|
+
|
56
|
+
__inline static float diffTime(struct timeval bigger, struct timeval smaller) {
|
57
|
+
long sec = bigger.tv_sec - smaller.tv_sec;
|
58
|
+
long usec = bigger.tv_usec - smaller.tv_usec;
|
59
|
+
return((float)sec + (float)usec/1000000.0);
|
60
|
+
}
|
61
|
+
|
62
|
+
|
63
|
+
static unsigned int next = 1;
|
64
|
+
static float fnext;
|
65
|
+
static char barstore[] =
|
66
|
+
"==============================================================================";
|
67
|
+
static char fmtstring[60];
|
68
|
+
static const char *label ="";
|
69
|
+
static boolean bAnnotate = FALSE;
|
70
|
+
static boolean bEnabled = TRUE;
|
71
|
+
static unsigned int spoonum;
|
72
|
+
static char ratestring[20];
|
73
|
+
static char timestring[20];
|
74
|
+
|
75
|
+
static void progress_timestring(float rate);
|
76
|
+
#define iBAR_WIDTHdefault 51
|
77
|
+
#define bBAR_WIDTHdefault 51
|
78
|
+
#define fBAR_WIDTHdefault ((float)iBAR_WIDTH)
|
79
|
+
#define bfBAR_WIDTHdefault ((float)bBAR_WIDTH)
|
80
|
+
|
81
|
+
static unsigned int iBAR_WIDTH = iBAR_WIDTHdefault;
|
82
|
+
static unsigned int bBAR_WIDTH = bBAR_WIDTHdefault;
|
83
|
+
static float fBAR_WIDTH = ((float)iBAR_WIDTHdefault);
|
84
|
+
static float bfBAR_WIDTH = ((float)bBAR_WIDTHdefault);
|
85
|
+
|
86
|
+
void progress_reset() {
|
87
|
+
next = 0;
|
88
|
+
fnext = 0.0;
|
89
|
+
}
|
90
|
+
void progress_disable() {
|
91
|
+
bEnabled = FALSE;
|
92
|
+
}
|
93
|
+
|
94
|
+
void progress(const float f) {
|
95
|
+
// fprintf(stderr,"%f\n",f);
|
96
|
+
if(!bEnabled) return;
|
97
|
+
if(f < FLT_EPSILON) {
|
98
|
+
fprintf(stderr, "\r>");
|
99
|
+
next = 1;
|
100
|
+
} else {
|
101
|
+
if(f >= ((float)(next))/fBAR_WIDTH || f >= (float)1.0) {
|
102
|
+
next = (unsigned int)(f*fBAR_WIDTH)+1;
|
103
|
+
if(bAnnotate) {
|
104
|
+
snprintf(fmtstring, sizeof(fmtstring), "\r%s:%3.0f%%%% %%-%ds| %u", label, f*100.0, iBAR_WIDTH, spoonum);
|
105
|
+
}
|
106
|
+
else
|
107
|
+
snprintf(fmtstring, sizeof(fmtstring), "\r%s:%3.0f%%%% %%-%ds|", label, f*100.0, iBAR_WIDTH);
|
108
|
+
if(next > 1 )barstore[next-2]='>';
|
109
|
+
barstore[next-1]='\0';
|
110
|
+
fprintf(stderr, fmtstring, barstore);
|
111
|
+
//fprintf(stderr, "\r%s>", barstore);
|
112
|
+
barstore[next-1]='=';
|
113
|
+
if(next > 1 )barstore[next-2]='=';
|
114
|
+
}
|
115
|
+
if(f >= (float)1.0-FLT_EPSILON){
|
116
|
+
fprintf(stderr,"\n");
|
117
|
+
bAnnotate = FALSE;
|
118
|
+
}
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
void progress_label(const char *label_param) {
|
123
|
+
if(strlen(label_param) < bBAR_WIDTHdefault - 5) {
|
124
|
+
label = label_param;
|
125
|
+
bBAR_WIDTH = min(1, (int) bBAR_WIDTHdefault - (int)strlen(label_param));
|
126
|
+
iBAR_WIDTH = min(1, (int) iBAR_WIDTHdefault - (int)strlen(label_param));
|
127
|
+
}
|
128
|
+
fBAR_WIDTH = (float)iBAR_WIDTH;
|
129
|
+
bfBAR_WIDTH = (float)bBAR_WIDTH;
|
130
|
+
}
|
131
|
+
void progress_annotate(unsigned int spoo) {
|
132
|
+
bAnnotate = TRUE;
|
133
|
+
spoonum = spoo;
|
134
|
+
}
|
135
|
+
|
136
|
+
static struct timeval start;
|
137
|
+
|
138
|
+
void progress_bytes_of_bytes(unsigned long int bytes,
|
139
|
+
unsigned long int total ) {
|
140
|
+
struct timeval now;
|
141
|
+
if(bytes > total) return;
|
142
|
+
if(!bEnabled) return;
|
143
|
+
if(isatty(fileno(stderr)) == 0) return;
|
144
|
+
if(bytes == 0) {
|
145
|
+
gettimeofday(&start, NULL);
|
146
|
+
fprintf(stderr, "\r>");
|
147
|
+
fnext = 0.01;
|
148
|
+
} else {
|
149
|
+
float f = (float)bytes/(float)total;
|
150
|
+
if(f >= fnext || bytes >= total) {
|
151
|
+
float dt;
|
152
|
+
unsigned int thisint = (unsigned int)(f*bfBAR_WIDTH);
|
153
|
+
fnext = f+0.01;
|
154
|
+
gettimeofday(&now, NULL);
|
155
|
+
dt = diffTime(now,start);
|
156
|
+
progress_ratestring((double)bytes / (double)dt, "B");
|
157
|
+
progress_timestring(dt*((float)total-bytes)/((float)bytes));
|
158
|
+
snprintf(fmtstring, sizeof(fmtstring), "\r%s:%3.0f%%%% %%-%ds| %9s eta %6s",
|
159
|
+
label, f*100.0, bBAR_WIDTH, ratestring, timestring);
|
160
|
+
if(thisint > 0 )barstore[thisint-1]='>';
|
161
|
+
barstore[thisint]='\0';
|
162
|
+
fprintf(stderr, fmtstring, barstore);
|
163
|
+
//fprintf(stderr, "\r%s>", barstore);
|
164
|
+
barstore[thisint]='=';
|
165
|
+
if(thisint > 0 )barstore[thisint-1]='=';
|
166
|
+
}
|
167
|
+
}
|
168
|
+
if(bytes == total){
|
169
|
+
float dt = diffTime(now,start);
|
170
|
+
fprintf(stderr,"\n");
|
171
|
+
if(dt > 2) {
|
172
|
+
progress_timestring(dt);
|
173
|
+
fprintf(stderr, "%s process rate: %s for %s\n", label, ratestring, timestring);
|
174
|
+
}
|
175
|
+
}
|
176
|
+
}
|
177
|
+
|
178
|
+
void progress_n_of(unsigned int n,
|
179
|
+
unsigned int total ) {
|
180
|
+
struct timeval now;
|
181
|
+
float f = (float)n/(float)total;
|
182
|
+
if(n > total) return;
|
183
|
+
if(!bEnabled) return;
|
184
|
+
if(isatty(fileno(stderr)) == 0) return;
|
185
|
+
if(n == 0) {
|
186
|
+
gettimeofday(&start, NULL);
|
187
|
+
fprintf(stderr, "\r>");
|
188
|
+
fnext = 0;
|
189
|
+
progress_ratestring(0, "");
|
190
|
+
progress_timestring(0);
|
191
|
+
}
|
192
|
+
if(f >= fnext || n >= total) {
|
193
|
+
float dt;
|
194
|
+
unsigned int thisint = (unsigned int)(f*bfBAR_WIDTH);
|
195
|
+
fnext = f+0.01;
|
196
|
+
if(n != 0) {
|
197
|
+
gettimeofday(&now, NULL);
|
198
|
+
dt = diffTime(now,start);
|
199
|
+
progress_ratestring((double)n / (double)dt, "");
|
200
|
+
progress_timestring(dt*((float)total-n)/((float)n));
|
201
|
+
}
|
202
|
+
snprintf(fmtstring, sizeof(fmtstring), "\r%s:%3.0f%%%% %%-%ds| %9s eta %6s",
|
203
|
+
label, f*100.0, bBAR_WIDTH, ratestring, timestring);
|
204
|
+
if(thisint != 0 ) barstore[thisint-1]='>';
|
205
|
+
barstore[thisint]='\0';
|
206
|
+
fprintf(stderr, fmtstring, barstore);
|
207
|
+
//fprintf(stderr, "\r%s>", barstore);
|
208
|
+
barstore[thisint]='=';
|
209
|
+
if(thisint > 0 )barstore[thisint-1]='=';
|
210
|
+
}
|
211
|
+
if(n == total){
|
212
|
+
float dt = diffTime(now,start);
|
213
|
+
fprintf(stderr,"\n");
|
214
|
+
if(dt > 2) {
|
215
|
+
progress_timestring(dt);
|
216
|
+
fprintf(stderr, "%s process rate: %s for %s\n", label, ratestring, timestring);
|
217
|
+
}
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
/* technique stolen from ncftp. */
|
222
|
+
#define KByte 1024u
|
223
|
+
#define MByte (1024u*KByte)
|
224
|
+
#define GByte (1024u*MByte)
|
225
|
+
/* haha */
|
226
|
+
|
227
|
+
|
228
|
+
static void progress_timestring(float timeInSeconds) {
|
229
|
+
unsigned int hours=0;
|
230
|
+
unsigned int minutes=0;
|
231
|
+
unsigned int seconds=0;
|
232
|
+
unsigned int deciseconds=0;
|
233
|
+
hours = ((unsigned int)timeInSeconds) / 3600;
|
234
|
+
timeInSeconds -= hours*3600;
|
235
|
+
minutes = ((unsigned int)timeInSeconds) / 60;
|
236
|
+
timeInSeconds -= minutes*60;
|
237
|
+
seconds = ((unsigned int)timeInSeconds);
|
238
|
+
timeInSeconds-=seconds;
|
239
|
+
deciseconds = ((unsigned int)(timeInSeconds*10.0))%10;
|
240
|
+
if(hours >0) {
|
241
|
+
snprintf(timestring, sizeof(timestring), "%uh%02um", hours,minutes);
|
242
|
+
} else if(minutes >0) {
|
243
|
+
snprintf(timestring, sizeof(timestring), "%um%02us", minutes,seconds);
|
244
|
+
} else {
|
245
|
+
snprintf(timestring, sizeof(timestring), "%u.%01us", seconds, deciseconds);
|
246
|
+
}
|
247
|
+
}
|
248
|
+
|
249
|
+
const char * progress_ratestring(float rate, const char *units) {
|
250
|
+
char suff;
|
251
|
+
if(rate > 999.5 * GByte) {
|
252
|
+
suff = 'T';
|
253
|
+
rate = rate / GByte / 1024.0;
|
254
|
+
} else if(rate > 999.5 * MByte) {
|
255
|
+
suff = 'G';
|
256
|
+
rate /= GByte;
|
257
|
+
} else if(rate > 999.5 * KByte) {
|
258
|
+
suff = 'M';
|
259
|
+
rate /= MByte;
|
260
|
+
snprintf(ratestring, sizeof(ratestring),
|
261
|
+
"%.2fM", (float)rate / (float)MByte);
|
262
|
+
} else if(rate >= 999.5 ) {
|
263
|
+
suff = 'K';
|
264
|
+
rate /= KByte;;
|
265
|
+
} else {
|
266
|
+
suff = ' ';
|
267
|
+
snprintf(ratestring, sizeof(ratestring),
|
268
|
+
"%3.0f%s/s", rate, units);
|
269
|
+
}
|
270
|
+
if(rate >= 99.5) {
|
271
|
+
snprintf(ratestring, sizeof(ratestring),
|
272
|
+
"%3.0f%c%s/s", rate, suff, units);
|
273
|
+
} else if(rate >= 9.5) {
|
274
|
+
snprintf(ratestring, sizeof(ratestring),
|
275
|
+
"%4.1f%c%s/s", rate, suff, units);
|
276
|
+
} else {
|
277
|
+
snprintf(ratestring, sizeof(ratestring),
|
278
|
+
"%4.2f%c%s/s", rate, suff, units);
|
279
|
+
}
|
280
|
+
return(ratestring);
|
281
|
+
}
|
282
|
+
|
283
|
+
/*
|
284
|
+
vi:ts=2
|
285
|
+
*/
|
@@ -0,0 +1,45 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2002
|
3
|
+
* Neil Spring and the University of Washington.
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* Redistribution and use in source and binary forms, with or without
|
7
|
+
* modification, are permitted provided that the following conditions
|
8
|
+
* are met:
|
9
|
+
* 1. Redistributions of source code must retain the above copyright
|
10
|
+
* notice, this list of conditions and the following disclaimer.
|
11
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
12
|
+
* notice, this list of conditions and the following disclaimer in the
|
13
|
+
* documentation and/or other materials provided with the distribution.
|
14
|
+
* 3. The name of the author(s) may not be used to endorse or promote
|
15
|
+
* products derived from this software without specific prior
|
16
|
+
* written permission.
|
17
|
+
*
|
18
|
+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
19
|
+
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
20
|
+
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
21
|
+
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
22
|
+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
23
|
+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
24
|
+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
25
|
+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
26
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
27
|
+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
28
|
+
*/
|
29
|
+
|
30
|
+
void progress(const float progress_fraction);
|
31
|
+
void progress_label(const char *label_param);
|
32
|
+
void progress_annotate(unsigned int spoo);
|
33
|
+
|
34
|
+
void progress_bytes_of_bytes(unsigned long int bytes,
|
35
|
+
unsigned long int total );
|
36
|
+
void progress_n_of(unsigned int n,
|
37
|
+
unsigned int total );
|
38
|
+
void progress_disable(void);
|
39
|
+
void progress_reset(void);
|
40
|
+
|
41
|
+
/* internal, but handy */
|
42
|
+
const char * progress_ratestring(float rate, const char *units);
|
43
|
+
/*
|
44
|
+
vi:ts=2
|
45
|
+
*/
|
data/ext/undns/queue.c
ADDED
@@ -0,0 +1,346 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2002
|
3
|
+
* Neil Spring and the University of Washington.
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* Redistribution and use in source and binary forms, with or without
|
7
|
+
* modification, are permitted provided that the following conditions
|
8
|
+
* are met:
|
9
|
+
* 1. Redistributions of source code must retain the above copyright
|
10
|
+
* notice, this list of conditions and the following disclaimer.
|
11
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
12
|
+
* notice, this list of conditions and the following disclaimer in the
|
13
|
+
* documentation and/or other materials provided with the distribution.
|
14
|
+
* 3. The name of the author(s) may not be used to endorse or promote
|
15
|
+
* products derived from this software without specific prior
|
16
|
+
* written permission.
|
17
|
+
*
|
18
|
+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
19
|
+
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
20
|
+
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
21
|
+
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
22
|
+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
23
|
+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
24
|
+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
25
|
+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
26
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
27
|
+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
28
|
+
*/
|
29
|
+
|
30
|
+
#ifdef HAVE_CONFIG_H
|
31
|
+
#include <config.h>
|
32
|
+
#endif
|
33
|
+
#include <stdlib.h>
|
34
|
+
#include <stdio.h>
|
35
|
+
#include <string.h>
|
36
|
+
#include <assert.h>
|
37
|
+
#ifdef HAVE_LIBPTHREAD
|
38
|
+
#include <pthread.h>
|
39
|
+
#else
|
40
|
+
// dealt with using AC_NSPRING_NO_PTHREAD typedef void *pthread_mutex_t;
|
41
|
+
#define pthread_mutex_lock(x) (0)
|
42
|
+
#define pthread_mutex_unlock(x) (0)
|
43
|
+
#define pthread_mutex_init(x,y) (0)
|
44
|
+
#define pthread_mutex_destroy(x) (0)
|
45
|
+
#endif
|
46
|
+
#include "queue.h"
|
47
|
+
#ifdef HAVE_DMALLOC_H
|
48
|
+
#include <dmalloc.h>
|
49
|
+
#endif
|
50
|
+
|
51
|
+
struct queue_element_struct {
|
52
|
+
const void *value;
|
53
|
+
struct queue_element_struct *next;
|
54
|
+
struct queue_element_struct *prev;
|
55
|
+
};
|
56
|
+
|
57
|
+
struct queue_struct {
|
58
|
+
q_element head, tail;
|
59
|
+
int (*compare)(const void *v1, const void *v2);
|
60
|
+
void (*release)(void *v); /* aka free */
|
61
|
+
pthread_mutex_t mutex;
|
62
|
+
};
|
63
|
+
|
64
|
+
/*
|
65
|
+
#define LOCK { printf("^"); fflush(stdout); assert(pthread_mutex_lock(&q->mutex)==0); }
|
66
|
+
#define UNLOCK { assert(pthread_mutex_unlock(&q->mutex)==0); printf("."); fflush(stdout); };
|
67
|
+
*/
|
68
|
+
#define LOCK assert(pthread_mutex_lock(&q->mutex)==0);
|
69
|
+
#define UNLOCK assert(pthread_mutex_unlock(&q->mutex)==0);
|
70
|
+
|
71
|
+
#define check_invariants(q) check_invariants_internal(q, __FILE__, __LINE__)
|
72
|
+
|
73
|
+
static inline void check_invariants_internal(queue q, const char *str, int line) {
|
74
|
+
if(!(q->head == NULL || q->head->prev == NULL)) {
|
75
|
+
fprintf(stderr, "!(q->head == NULL || q->head->prev == NULL)) at %s:%d\n", str, line);
|
76
|
+
abort();
|
77
|
+
}
|
78
|
+
if(!(q->head == NULL || q->head->next == NULL || q->head->next->prev == q->head)) {
|
79
|
+
fprintf(stderr, "!(q->head == NULL || q->head->next == NULL || q->head->next->prev == q->head)) at %s:%d\n", str, line);
|
80
|
+
abort();
|
81
|
+
}
|
82
|
+
if(!(q->tail == NULL || q->tail->next == NULL)) {
|
83
|
+
fprintf(stderr, "!(q->tail == NULL || q->tail->next == NULL)) at %s:%d\n", str, line);
|
84
|
+
abort();
|
85
|
+
}
|
86
|
+
if(!(q->tail == NULL || q->tail->prev == NULL || q->tail->prev->next == q->tail) ) {
|
87
|
+
fprintf(stderr, "!(q->tail == NULL || q->tail->prev == NULL || q->tail->prev->next == q->tail)) at %s:%d\n", str, line);
|
88
|
+
abort();
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
/* compare has strcmp semantics */
|
93
|
+
queue q_new(int (*compare)(const void *v1, const void *v2),
|
94
|
+
void (*release)(void *v)) {
|
95
|
+
queue q = (queue)malloc(sizeof(struct queue_struct));
|
96
|
+
assert(q!=NULL);
|
97
|
+
memset(q, 0, sizeof(struct queue_struct));
|
98
|
+
q->compare = compare;
|
99
|
+
q->release = release;
|
100
|
+
(void)pthread_mutex_init(&q->mutex, NULL);
|
101
|
+
return(q);
|
102
|
+
}
|
103
|
+
|
104
|
+
void q_delete(/*@only@*/ queue q) {
|
105
|
+
void *v;
|
106
|
+
v = (void *)q_pop(q);
|
107
|
+
while(v) {
|
108
|
+
if(q->release) q->release(v); /* aka free */
|
109
|
+
v=(void *)q_pop(q);
|
110
|
+
}
|
111
|
+
(void)pthread_mutex_destroy(&q->mutex);
|
112
|
+
free(q);
|
113
|
+
}
|
114
|
+
|
115
|
+
q_element q_insert_fromdir(queue q, const void *v, boolean scan_backwards);
|
116
|
+
q_element q_insert(queue q, const void *v) {
|
117
|
+
return(q_insert_fromdir(q, v, FALSE));
|
118
|
+
}
|
119
|
+
q_element q_insert_fromdir(queue q, const void *v, boolean scan_backwards) {
|
120
|
+
q_element newelem;
|
121
|
+
assert(q!=NULL);
|
122
|
+
if(q->compare == NULL) {
|
123
|
+
fprintf(stderr, "you used q_insert instead of q_append on an unsorted queue\n");
|
124
|
+
assert(q->compare!=NULL); /* insert is sorted; needs a comparator */
|
125
|
+
}
|
126
|
+
|
127
|
+
newelem = malloc(sizeof(struct queue_element_struct));
|
128
|
+
assert(newelem!=NULL);
|
129
|
+
newelem->value = v;
|
130
|
+
|
131
|
+
LOCK;
|
132
|
+
if(!q->head) {
|
133
|
+
assert(q->tail == NULL);
|
134
|
+
newelem->prev = newelem->next = NULL;
|
135
|
+
q->head = q->tail = newelem;
|
136
|
+
} else {
|
137
|
+
q_element iter;
|
138
|
+
if(scan_backwards) {
|
139
|
+
if(q->compare(q->tail->value, v) <= 0) {
|
140
|
+
/* append */
|
141
|
+
newelem->prev = q->tail;
|
142
|
+
newelem->next = NULL;
|
143
|
+
if(q->tail) { /* should be trivially true, since q->head was non-null... */
|
144
|
+
q->tail->next = newelem;
|
145
|
+
}
|
146
|
+
q->tail=newelem;
|
147
|
+
} else {
|
148
|
+
for(iter = q->tail;
|
149
|
+
iter!=NULL && q->compare(iter->value, v) >= 0;
|
150
|
+
iter = iter->prev);
|
151
|
+
if(iter) { // must insert in middle
|
152
|
+
newelem->prev = iter;
|
153
|
+
newelem->next = iter->next;
|
154
|
+
iter->next = newelem;
|
155
|
+
if(newelem->next) {
|
156
|
+
newelem->next->prev = newelem;
|
157
|
+
} else {
|
158
|
+
q->tail = newelem;
|
159
|
+
}
|
160
|
+
} else {
|
161
|
+
/* prepend */
|
162
|
+
newelem->next = q->head;
|
163
|
+
newelem->prev = NULL;
|
164
|
+
q->head->prev = newelem;
|
165
|
+
q->head=newelem;
|
166
|
+
}
|
167
|
+
}
|
168
|
+
} else {
|
169
|
+
for(iter = q->head;
|
170
|
+
iter!=NULL && q->compare(iter->value, v) <= 0;
|
171
|
+
/* <= there should append equal things. < should prepend equal things */
|
172
|
+
iter = iter->next);
|
173
|
+
if(iter) { // must insert in middle
|
174
|
+
newelem = malloc(sizeof(struct queue_element_struct));
|
175
|
+
assert(newelem!=NULL);
|
176
|
+
newelem->value = v;
|
177
|
+
newelem->next = iter;
|
178
|
+
newelem->prev = iter->prev;
|
179
|
+
iter->prev = newelem;
|
180
|
+
if(newelem->prev) {
|
181
|
+
newelem->prev->next = newelem;
|
182
|
+
} else {
|
183
|
+
q->head = newelem;
|
184
|
+
}
|
185
|
+
} else {
|
186
|
+
/* append */
|
187
|
+
newelem->prev = q->tail;
|
188
|
+
newelem->next = NULL;
|
189
|
+
if(q->tail) { /* should be trivially true, since q->head was non-null... */
|
190
|
+
q->tail->next = newelem;
|
191
|
+
}
|
192
|
+
q->tail=newelem;
|
193
|
+
}
|
194
|
+
}
|
195
|
+
}
|
196
|
+
UNLOCK;
|
197
|
+
return newelem;
|
198
|
+
}
|
199
|
+
void q_append(queue q, const void *v) {
|
200
|
+
q_element newelem = malloc(sizeof(struct queue_element_struct));
|
201
|
+
assert(newelem!=NULL);
|
202
|
+
assert(q!=NULL);
|
203
|
+
newelem->value = v;
|
204
|
+
newelem->next = NULL;
|
205
|
+
LOCK;
|
206
|
+
check_invariants(q);
|
207
|
+
newelem->prev = q->tail;
|
208
|
+
if(q->tail) {
|
209
|
+
q->tail->next = newelem;
|
210
|
+
} else {
|
211
|
+
assert(q->head == NULL);
|
212
|
+
q->head = newelem;
|
213
|
+
}
|
214
|
+
q->tail = newelem;
|
215
|
+
check_invariants(q);
|
216
|
+
UNLOCK;
|
217
|
+
}
|
218
|
+
|
219
|
+
static /*@null@*/ const void *q_top_gotlock(const queue q) {
|
220
|
+
const void * retval = NULL;
|
221
|
+
if(q->head) {
|
222
|
+
retval = q->head->value;
|
223
|
+
}
|
224
|
+
return retval;
|
225
|
+
}
|
226
|
+
|
227
|
+
/*@null@*/ const void *q_pop(queue q) {
|
228
|
+
const void *retval;
|
229
|
+
q_element freeme;
|
230
|
+
LOCK;
|
231
|
+
check_invariants(q);
|
232
|
+
freeme = q->head;
|
233
|
+
retval = q_top_gotlock(q);
|
234
|
+
if(freeme!=NULL) {
|
235
|
+
q->head = q->head->next;
|
236
|
+
if(q->head)
|
237
|
+
q->head->prev=NULL;
|
238
|
+
else
|
239
|
+
q->tail=NULL;
|
240
|
+
free(freeme);
|
241
|
+
}
|
242
|
+
check_invariants(q);
|
243
|
+
UNLOCK;
|
244
|
+
return(retval);
|
245
|
+
}
|
246
|
+
|
247
|
+
/*@null@*/ const void *q_top(const queue q) {
|
248
|
+
const void * retval;
|
249
|
+
LOCK;
|
250
|
+
retval = q_top_gotlock(q);
|
251
|
+
UNLOCK;
|
252
|
+
return(retval);
|
253
|
+
}
|
254
|
+
|
255
|
+
/* returns true if not interrupted by a false callback return val */
|
256
|
+
boolean q_iterate(queue q, q_iterator iterator, void *user) {
|
257
|
+
q_element i;
|
258
|
+
boolean cont = TRUE;
|
259
|
+
LOCK;
|
260
|
+
check_invariants(q);
|
261
|
+
for( i = q->head; i != NULL && cont; i = i->next ) {
|
262
|
+
cont = iterator(i->value, user);
|
263
|
+
}
|
264
|
+
UNLOCK;
|
265
|
+
return cont;
|
266
|
+
}
|
267
|
+
|
268
|
+
/* returns true if not interrupted by a false callback return val */
|
269
|
+
boolean q_iterate_q(queue q, q_iterator_q iterator, void *user) {
|
270
|
+
q_element i;
|
271
|
+
boolean cont = TRUE;
|
272
|
+
LOCK;
|
273
|
+
check_invariants(q);
|
274
|
+
for( i = q->head; i != NULL && cont; i = i->next ) {
|
275
|
+
cont = iterator(q, i->value, user);
|
276
|
+
}
|
277
|
+
UNLOCK;
|
278
|
+
return cont;
|
279
|
+
}
|
280
|
+
|
281
|
+
static boolean counter(const void *v __attribute__ ((unused)),
|
282
|
+
void *count) {
|
283
|
+
(*(unsigned long *)count)++;
|
284
|
+
assert((*(unsigned long *)count) < 200000);
|
285
|
+
return TRUE;
|
286
|
+
}
|
287
|
+
unsigned long q_length(queue q) {
|
288
|
+
unsigned long count=0;
|
289
|
+
(void)q_iterate(q, counter, &count);
|
290
|
+
return count;
|
291
|
+
}
|
292
|
+
|
293
|
+
static boolean finder(queue q, const void *v, void *user) {
|
294
|
+
void **found = (void **)user;
|
295
|
+
if(q->compare(v, *found) == 0) {
|
296
|
+
*found = (void *)v;
|
297
|
+
return FALSE;
|
298
|
+
}
|
299
|
+
return TRUE;
|
300
|
+
}
|
301
|
+
|
302
|
+
void *q_find(queue q, const void *findme) {
|
303
|
+
void *found;
|
304
|
+
found = (void *)findme;
|
305
|
+
if(q_iterate_q(q, finder, &found) == 0)
|
306
|
+
return(found);
|
307
|
+
else
|
308
|
+
return(NULL);
|
309
|
+
}
|
310
|
+
|
311
|
+
void q_expunge(queue q, /*@owned@*/ q_element p) {
|
312
|
+
|
313
|
+
q_element prev;
|
314
|
+
assert(p!=NULL);
|
315
|
+
prev = p->prev;
|
316
|
+
if(prev != NULL) {
|
317
|
+
prev->next = p->next;
|
318
|
+
} else {
|
319
|
+
q->head = p->next;
|
320
|
+
}
|
321
|
+
if(p->next == NULL) {
|
322
|
+
q->tail = prev;
|
323
|
+
} else {
|
324
|
+
p->next->prev = prev;
|
325
|
+
}
|
326
|
+
free(p);
|
327
|
+
}
|
328
|
+
|
329
|
+
/* find the element with the value pointer equal to removeme */
|
330
|
+
/* then expunge that record. */
|
331
|
+
/* caller frees removeme as desired */
|
332
|
+
boolean q_remove(queue q, void *removeme) {
|
333
|
+
// q_element prev = NULL;
|
334
|
+
q_element p; /* the one to remove */
|
335
|
+
check_invariants(q);
|
336
|
+
/* the following should get fixed. */
|
337
|
+
for(p=q->head;
|
338
|
+
p != NULL && p->value != removeme;
|
339
|
+
// prev = p,
|
340
|
+
p=p->next);
|
341
|
+
if(p != NULL) {
|
342
|
+
q_expunge(q, p);
|
343
|
+
}
|
344
|
+
check_invariants(q);
|
345
|
+
return(p!=NULL); /* true if found and removed, false otherwise */
|
346
|
+
}
|