File: aquery.c

package info (click to toggle)
archie 1.4.1-9
  • links: PTS
  • area: non-free
  • in suites: slink
  • size: 516 kB
  • ctags: 1,022
  • sloc: ansic: 5,910; lisp: 454; makefile: 98
file content (296 lines) | stat: -rw-r--r-- 8,163 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
/*
 * aquery.c : Programmatic Prospero interface to Archie
 *
 * Copyright (c) 1991 by the University of Washington
 *
 * For copying and distribution information, please see the file
 * <copyright.h>.
 */

#include <stdio.h>

#include <pfs.h>
#include <perrno.h>
#include <archie.h>

#include <pmachine.h>
#ifdef NEED_STRING_H
# include <string.h>			/* for char *index() */
#else
# include <strings.h>			/* for char *index() */
#endif

#ifdef __GNUC__
#define INLINE __inline__
#else
#define INLINE
#endif

static void translateArchieResponse();
INLINE static int hostnamecmp();

extern int pwarn;
extern char p_warn_string[];

/*
 * archie_query : Sends a request to _host_, telling it to search for
 *                _string_ using _query_ as the search method.
 *                No more than _max_hits_ matches are to be returned
 *                skipping over _offset_ matches.
 *
 *		  archie_query returns a linked list of virtual links. 
 *                If _flags_ does not include AQ_NOTRANS, then the Archie
 *                responses will be translated. If _flags_ does not include 
 *                AQ_NOSORT, then the list will be sorted using _cmp_proc_ to
 *                compare pairs of links.  If _cmp_proc_ is NULL or AQ_DEFCMP,
 *                then the default comparison procedure, defcmplink(), is used
 *                sorting by host, then filename. If cmp_proc is AQ_INVDATECMP
 *                then invdatecmplink() is used, sorting inverted by date.
 *                otherwise a user-defined comparison procedure is called.
 *
 *                archie_query returns NULL and sets perrno if the query
 *                failed. Note that it can return NULL with perrno == PSUCCESS
 *                if the query didn't fail but there were simply no matches.
 *
 *        query:  S  Substring search ignoring case   
 *                C  Substring search with case significant
 *                R  Regular expression search
 *                =  Exact String Match
 *            s,c,e  Tries exact match first and falls back to S, C, or R 
 *                   if not found.
 *
 *     cmp_proc:  AQ_DEFCMP      Sort by host, then filename
 *                AQ_INVDATECMP  Sort inverted by date
 *
 *        flags:  AQ_NOSORT      Don't sort results
 *                AQ_NOTRANS     Don't translate results
 */
VLINK 
archie_query(host,string,max_hits,offset,query,cmp_proc,flags)
    char	*host,*string;
    int		max_hits,offset;
    Query	query;
    int		(*cmp_proc)();
    int		flags;
    {
	char qstring[MAX_VPATH];    /* For construting the query  */
	VLINK	links;		/* Matches returned by server */
	VDIR_ST	dir_st;         /* Filled in by get_vdir      */
	PVDIR	dir= &dir_st;
	
	VLINK	p,q,r,lowest,nextp,pnext,pprev;
	int	tmp;

	/* Set the cmp_proc if not given */
	if (cmp_proc == NULL) cmp_proc = defcmplink;

	/* Make the query string */
	sprintf(qstring,"ARCHIE/MATCH(%d,%d,%c)/%s",
		max_hits,offset, (char) query,string);

	/* Initialize Prospero structures */
	perrno = PSUCCESS; *p_err_string = '\0';
	pwarn = PNOWARN; *p_warn_string = '\0';
	vdir_init(dir);
	
	/* Retrieve the list of matches, return error if there was one */
#if defined(MSDOS)
	if(tmp = get_vdir(host, qstring, "", dir, (long)GVD_ATTRIB|GVD_NOSORT,
		NULL, NULL)) {
#else
	if(tmp = get_vdir(host,qstring,"",dir,GVD_ATTRIB|GVD_NOSORT,NULL,NULL)) {
# endif
	    perrno = tmp;
	    return(NULL);
	}

	/* Save the links, and clear in dir in case it's used again   */
	links = dir->links; dir->links = NULL;

	/* As returned, list is sorted by suffix, and conflicting     */
	/* suffixes appear on a list of "replicas".  We want to       */
	/* create a one-dimensional list sorted by host then filename */
	/* and maybe by some other parameter                          */

	/* First flatten the doubly-linked list */
	for (p = links; p != NULL; p = nextp) {
	    nextp = p->next;
	    if (p->replicas != NULL) {
		p->next = p->replicas;
		p->next->previous = p;
		for (r = p->replicas; r->next != NULL; r = r->next)
		    /*EMPTY*/ ;
		r->next = nextp;
		nextp->previous = r;
		p->replicas = NULL;
	    }
	}

	/* Translate the filenames unless NOTRANS was given */
	if (!(flags & AQ_NOTRANS))
	    for (p = links; p != NULL; p = p->next)
		translateArchieResponse(p);

	/* If NOSORT given, then just hand it back */
	if (flags & AQ_NOSORT) {
	    perrno = PSUCCESS;
	    return(links);
	}

	/* Otherwise sort it using a selection sort and the given cmp_proc */
	for (p = links; p != NULL; p = nextp) {
	    nextp = p->next;
	    lowest = p;
	    for (q = p->next; q != NULL; q = q->next)
		if ((*cmp_proc)(q,lowest) < 0)
		    lowest = q;
	    if (p != lowest) {
		/* swap the two links */
		pnext = p->next;
		pprev = p->previous;
		if (lowest->next != NULL)
		    lowest->next->previous = p;
		p->next = lowest->next;
		if (nextp == lowest) {
		    p->previous = lowest;
		} else {
		    lowest->previous->next = p;
		    p->previous = lowest->previous;
		}
		if (nextp == lowest) {
		    lowest->next = p;
		} else {
		    pnext->previous = lowest;
		    lowest->next = pnext;
		}
		if (pprev != NULL)
		    pprev->next = lowest;
		lowest->previous = pprev;
		/* keep the head of the list in the right place */
		if (links == p)
		    links = lowest;
	    }
	}

	/* Return the links */
	perrno = PSUCCESS;
	return(links);
    }

/*
 * translateArchieResponse: 
 *
 *   If the given link is for an archie-pseudo directory, fix it. 
 *   This is called unless AQ_NOTRANS was given to archie_query().
 */
static void
translateArchieResponse(l)
    VLINK l;
    {
	char *slash;

	if (strcmp(l->type,"DIRECTORY") == 0) {
	    if (strncmp(l->filename,"ARCHIE/HOST",11) == 0) {
		l->type = stcopyr("EXTERNAL(AFTP,DIRECTORY)",l->type);
		l->host = stcopyr(l->filename+12,l->host);
		slash = (char *)index(l->host,'/');
		if (slash) {
		    l->filename = stcopyr(slash,l->filename);
		    *slash++ = '\0';
		} else
		    l->filename = stcopyr("",l->filename);
	    }
	}
    }


/* hostnamecmp: Compare two hostnames based on domain,
 *              right-to-left.  Returns <0 if a belongs before b, >0
 *              if b belongs before a, and 0 if they are identical.
 *              Contributed by asami@cs.berkeley.edu (Satoshi ASAMI).
 */
INLINE
static int
hostnamecmp(a,b)
    char *a,*b;
    {
	char	*pa, *pb;
	int	result;

	for (pa = a ; *pa ; pa++)
	    ;
	for (pb = b ; *pb ; pb++)
	    ;

	while (pa > a && pb > b) {
	    for (; pa > a ; pa--)
		if (*pa == '.')	{
		    pa++;
		    break;
		}
	    for (; pb > b ; pb--)
		if (*pb == '.')	{
		    pb++;
		    break;
		}
	    if (result = strcmp(pa, pb))
		return (result);
	    pa -= 2;
	    pb -= 2;
	}
	if (pa <= a) {
	    if (pb <= b)
		return (0);
	    else
		return (-1);
	} else
	    return (1);
    }

/*
 * defcmplink: The default link comparison function for sorting. Compares
 *	       links p and q first by host then by filename. Returns < 0 if p
 *             belongs before q, > 0 if p belongs after q, and == 0 if their
 *             host and filename fields are identical.
 */
int
defcmplink(p,q)
    VLINK p,q;
    {
	int result;

	if ((result=hostnamecmp(p->host,q->host)) != 0)
	    return(result);
	else
	    return(strcmp(p->filename,q->filename));
    }

/*
 * invdatecmplink: An alternative comparison function for sorting that
 *	           compares links p and q first by LAST-MODIFIED date,
 *                 if they both have that attribute. If both links
 *                 don't have that attribute or the dates are the
 *                 same, it then calls defcmplink() and returns its 
 *		   value.
 */
int
invdatecmplink(p,q)
    VLINK p,q;
    {
	PATTRIB pat,qat;
	char *pdate,*qdate;
	int result;
	
	pdate = qdate = NULL;
	for (pat = p->lattrib; pat; pat = pat->next)
	    if(strcmp(pat->aname,"LAST-MODIFIED") == 0)
		pdate = pat->value.ascii;
	for (qat = q->lattrib; qat; qat = qat->next)
	    if(strcmp(qat->aname,"LAST-MODIFIED") == 0)
		qdate = qat->value.ascii;
	if(!pdate && !qdate) return(defcmplink(p,q));
	if(!pdate) return(1); 
	if(!qdate) return(-1);
	if((result=strcmp(qdate,pdate)) == 0) return(defcmplink(p,q));
	else return(result);
    }