undns 0.4.0a
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|