1 /* Copyright (C) 2000-2015 Lavtech.com corp. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2 of the License, or
6    (at your option) any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 */
17 
18 #include "udm_config.h"
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28 #ifdef HAVE_IO_H
29 #include <io.h>
30 #endif
31 #include <errno.h>
32 #include <math.h>
33 
34 #include "udm_common.h"
35 #include "udm_utils.h"
36 #include "udm_searchtool.h"
37 #include "udm_boolean.h"
38 #include "udm_vars.h"
39 #include "udm_conf.h"
40 #include "udm_log.h"
41 
42 
43 /********** QSORT functions *******************************/
44 
45 
46 static int
cmppattern(UDM_URLDATALIST * Data,UDM_URLDATA * D,long j,const char * pattern)47 cmppattern(UDM_URLDATALIST *Data, UDM_URLDATA *D,
48            long j, const char *pattern)
49 {
50   int rc;
51 
52   for(; *pattern != '\0'; pattern++)
53   {
54     switch(*pattern)
55     {
56       case 'R':
57       case 'r':
58         if (D->score > Data->Item[j].score) return (*pattern == 'R') ? 1 : -1;
59         if (D->score < Data->Item[j].score) return (*pattern == 'R') ? -1 : 1;
60         break;
61       case 'P':
62       case 'p':
63         if (D->pop_rank > Data->Item[j].pop_rank) return (*pattern == 'P') ? 1 : -1;
64         if (D->pop_rank < Data->Item[j].pop_rank) return (*pattern == 'P') ? -1 : 1;
65         break;
66       case 'D':
67       case 'd':
68         if (D->last_mod_time > Data->Item[j].last_mod_time) return (*pattern == 'D') ? 1 : -1;
69         if (D->last_mod_time < Data->Item[j].last_mod_time) return (*pattern == 'D') ? -1 : 1;
70         break;
71       case 'U':
72       case 'u':
73         rc= strcmp(UDM_NULL2EMPTY(D->url), UDM_NULL2EMPTY(Data->Item[j].url));
74         if (rc) return(*pattern == 'U' ? -rc : rc);
75         break;
76       case 'S':
77       case 's':
78         rc= strcmp(UDM_NULL2EMPTY(D->section),
79                    UDM_NULL2EMPTY(Data->Item[j].section));
80         if (rc) return(*pattern == 'S' ? -rc : rc);
81         break;
82     }
83   }
84   return 0;
85 }
86 
87 
88 static int
cmppatternRP(UDM_URLDATA * D1,UDM_URLDATA * D2)89 cmppatternRP(UDM_URLDATA *D1, UDM_URLDATA *D2)
90 {
91   if (D1->score > D2->score) return -1;
92   if (D1->score < D2->score) return  1;
93 
94   if (D1->pop_rank > D2->pop_rank) return -1;
95   if (D1->pop_rank < D2->pop_rank) return 1;
96   return 0;
97 }
98 
99 
100 static int
cmppatternR(UDM_URLDATA * D1,UDM_URLDATA * D2)101 cmppatternR(UDM_URLDATA *D1, UDM_URLDATA *D2)
102 {
103   if (D1->score > D2->score) return -1;
104   if (D1->score < D2->score) return  1;
105   return 0;
106 }
107 
108 
109 
110 /****************************************************/
111 
112 static int
cmpsiteid2(UDM_URLDATA * p1,UDM_URLDATA * p2)113 cmpsiteid2(UDM_URLDATA *p1, UDM_URLDATA *p2)
114 {
115   if (p1->site_id  > p2->site_id)  return -1;
116   if (p1->site_id  < p2->site_id)  return 1;
117 #if 0
118   if (p1->score    > p2->score)    return -1;
119   if (p1->score    < p2->score)    return 1;
120   if (p1->pop_rank > p2->pop_rank) return -1;
121   if (p1->pop_rank < p2->pop_rank) return 1;
122 #endif
123   return 0;
124 }
125 
126 
127 void
UdmURLDataSortBySite(UDM_URLDATALIST * L)128 UdmURLDataSortBySite(UDM_URLDATALIST *L)
129 {
130   UdmSort((void*) L->Item, L->nitems, sizeof(*L->Item), (udm_qsort_cmp) cmpsiteid2);
131 #if 0
132   {
133     size_t i;
134     printf("L->num: %d num: %d\n", L->ncoords, num);
135     for (i= 0; i < num; i++)
136       printf("%d %d %d %d %.6f\n", i,
137       L->Data[i].url_id, L->Data[i].site_id, L->Data[i].coord, L->Data[i].pop_rank);
138   }
139 #endif
140 }
141 
142 
143 static void
UdmURLDataSortByPatternRP(UDM_URLDATALIST * L)144 UdmURLDataSortByPatternRP(UDM_URLDATALIST *L)
145 {
146   UdmSort((void*) L->Item, L->nitems, sizeof(*L->Item), (udm_qsort_cmp) cmppatternRP);
147 }
148 
149 
150 static void
UdmURLDataSortByPatternR(UDM_URLDATALIST * L)151 UdmURLDataSortByPatternR(UDM_URLDATALIST *L)
152 {
153   UdmSort((void*) L->Item, L->nitems, sizeof(*L->Item), (udm_qsort_cmp) cmppatternR);
154 }
155 
156 
157 static size_t UdmH[] = {1, 5, 19, 41, 109, 209, 505, 929, 2161,
158                         3905, 8929, 16001, 36289, 64769};
UdmURLDataSortByPattern(UDM_URLDATALIST * L,const char * pattern)159 void UdmURLDataSortByPattern(UDM_URLDATALIST *L, const char *pattern)
160 {
161   register ssize_t h, i, j;
162   int s = 13;
163   size_t num= L->nitems;
164   UDM_URLDATA Dat;
165 
166   if (!strcmp(pattern, "RP"))
167   {
168     UdmURLDataSortByPatternRP(L);
169     goto ret;
170   }
171   if (!strcmp(pattern, "R"))
172   {
173     UdmURLDataSortByPatternR(L);
174     goto ret;
175   }
176 
177   while( (s > 0) && ((num / 3) < UdmH[s])) s--;
178   while(s >= 0)
179   {
180     h= UdmH[s];
181     for (j= h; j < (ssize_t) num; j++)
182     {
183       Dat= L->Item[j];
184       i= j - h;
185 D4:
186       if (cmppattern(L, &Dat, i, pattern) <= 0) goto D6;
187       L->Item[i + h]= L->Item[i];
188       i-= h;
189       if (i >= 0) goto D4;
190 D6:
191       L->Item[i + h]= Dat;
192     }
193     s--;
194   }
195 
196 ret:
197 
198 #if 0
199   {
200     size_t i;
201     printf("L->num: %d num:%d pattern:%s\n", L->ncoords, num, pattern);
202     for (i= 0; i < num; i++)
203     {
204       printf("[%d]%d %d %d %d %.6f\n", i,
205              L->Coords[i].url_id, L->Coords[i].coord,
206              L->Data[i].url_id, L->Data[i].coord, (float) L->Data[i].pop_rank);
207     }
208   }
209 #endif
210   return;
211 }
212 
213 
214 /* TODO: Reuse the same function in sql.c */
215 static int
cmp_data_urls(UDM_URLDATA * d1,UDM_URLDATA * d2)216 cmp_data_urls(UDM_URLDATA *d1, UDM_URLDATA *d2)
217 {
218   if (d1->url_id > d2->url_id) return 1;
219   if (d1->url_id < d2->url_id) return -1;
220   return 0;
221 }
222 
223 
UdmURLDataListSearch(UDM_URLDATALIST * List,urlid_t id)224 UDM_URLDATA *UdmURLDataListSearch(UDM_URLDATALIST *List, urlid_t id)
225 {
226   UDM_URLDATA d;
227   void *found;
228   if (!List->nitems)
229     return 0;
230   d.url_id= id;
231   found= UdmBSearch(&d, List->Item, List->nitems, sizeof(UDM_URLDATA),
232                     (udm_qsort_cmp) cmp_data_urls);
233   return (UDM_URLDATA*) found;
234 }
235 
236 
237 void
UdmURLDataListSort(UDM_URLDATALIST * List)238 UdmURLDataListSort(UDM_URLDATALIST *List)
239 {
240   if (List->nitems)
241     UdmSort(List->Item, List->nitems, sizeof(UDM_URLDATA), (udm_qsort_cmp) cmp_data_urls);
242 }
243 
244 
245 /*
246   Clear all params.
247   Keep url_id untouched.
248 */
249 void
UdmURLDataListClearParams(UDM_URLDATALIST * DataList)250 UdmURLDataListClearParams(UDM_URLDATALIST *DataList)
251 {
252   size_t i;
253   for (i= 0; i < DataList->nitems; i++)
254   {
255     UDM_URLDATA *D= &DataList->Item[i];
256     D->site_id= 0;
257     D->pop_rank= 0;
258     D->last_mod_time= 0;
259     D->url= NULL;
260     D->section= NULL;
261   }
262 }
263 
264 
265 void
UdmURLDataListInit(UDM_URLDATALIST * L)266 UdmURLDataListInit(UDM_URLDATALIST *L)
267 {
268   bzero((void *) L, sizeof(*L));
269 }
270 
271 
272 void
UdmURLDataFree(UDM_URLDATA * D)273 UdmURLDataFree(UDM_URLDATA *D)
274 {
275   UDM_FREE(D->url);
276   UDM_FREE(D->section);
277 }
278 
279 
280 /*
281   Free items in the given range
282 */
283 void
UdmURLDataListFreeItems(UDM_URLDATALIST * DataList,size_t first,size_t last)284 UdmURLDataListFreeItems(UDM_URLDATALIST *DataList, size_t first, size_t last)
285 {
286   size_t i;
287   for (i= first; i < last; i++)
288     UdmURLDataFree(&DataList->Item[i]);
289 }
290 
291 
292 void
UdmURLDataListFree(UDM_URLDATALIST * DataList)293 UdmURLDataListFree(UDM_URLDATALIST *DataList)
294 {
295   if (DataList->Item)
296   {
297     UdmURLDataListFreeItems(DataList, 0, DataList->nitems);
298     UdmFree(DataList->Item);
299   }
300   bzero((void*) DataList, sizeof(*DataList));
301 }
302 
303 
304 /*
305   Skip empty records and return the number of non-empty records
306 */
307 size_t
UdmURLDataCompact(UDM_URLDATA * dst,UDM_URLDATA * src,size_t n)308 UdmURLDataCompact(UDM_URLDATA *dst, UDM_URLDATA *src, size_t n)
309 {
310   UDM_URLDATA *dst0= dst, *srcend= src + n;
311   for ( ; src < srcend ; src++)
312   {
313     if (src->site_id)
314     {
315       *dst++= *src;
316     }
317   }
318   return dst - dst0;
319 }
320