Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtSvc / DtUtil1 / DtsSort.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
25  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
26  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
27  * (c) Copyright 1993, 1994 Novell, Inc.                                *
28  */
29 /*
30  *+SNOTICE
31  *
32  *      $XConsortium: DtsSort.c /main/6 1996/11/21 19:56:08 drk $
33  *
34  *      RESTRICTED CONFIDENTIAL INFORMATION:
35  *      
36  *      The information in this document is subject to special
37  *      restrictions in a confidential disclosure agreement bertween
38  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
39  *      document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
40  *      Sun's specific written approval.  This documment and all copies
41  *      and derivative works thereof must be returned or destroyed at
42  *      Sun's request.
43  *
44  *      Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
45  *
46  *+ENOTICE
47  */
48 #include <stdlib.h>
49 #include <ctype.h>
50 #include <string.h>
51 #include <sys/mman.h>
52 #include <fcntl.h>
53 #include <sys/stat.h>
54 #define X_INCLUDE_STRING_H
55 #define XOS_USE_XT_LOCKING
56 #include <X11/Xos_r.h>
57 #include <Dt/DbReader.h>
58 #include "Dt/DtsDb.h"
59 #include "Dt/Dts.h"
60
61 extern  char    *strdup(const char *);
62
63
64 static char *
65 get_value(DtDtsDbRecord *ce_entry, char *value)
66 {
67         int     i=0;
68         XrmQuark        tmp = XrmStringToQuark (value);
69
70         for(i = 0; i < ce_entry->fieldCount; i++)
71         {
72                 if(ce_entry->fieldList[i]->fieldName == tmp)
73                 {
74                         return(ce_entry->fieldList[i]->fieldValue);
75                 }
76         }
77         return(NULL);
78 }
79
80 void
81 parts_of_pattern(char *c, int *spec, int *count, int *front)
82 {
83         int     nested = 0;
84         int     found = 0;
85         int     len;
86
87         (*count) = 0;
88         (*spec) = 0;
89         (*front) = 0;
90
91         while(*c)
92         {
93                 if((len = mblen(c, MB_CUR_MAX)) > 1) {
94                     (*count) += len;
95                     if(!found)
96                         (*front) += len;
97                     c += len;
98                     continue;
99                 }
100                 switch(*c)
101                 {
102                 case    '*':
103                         if(!nested)
104                         {
105                                 (*spec) += 100;
106                                 found = 1;
107                         }
108                         break;
109                 case    '?':
110                         if(!nested)
111                         {
112                                 (*spec) += 1;
113                                 found = 1;
114                         }
115                         break;
116                 case    '[':
117                         (*spec) += 10;
118                         nested ++;
119                         found = 1;
120                         break;
121                 case    ']':
122                         if(nested)
123                         {
124                                 nested --;
125                         }
126                         break;
127                 case    '\\':
128                         if(!nested)
129                         {
130                             if((len = mblen(c + 1, MB_CUR_MAX)) > 1) {
131                                 (*count) += len + 1;
132                                 c += len;
133                             }
134                             else {
135                                 (*count) += 2;
136                                 c++;
137                             }
138                         }
139                         break;
140                 default:
141                         (*count)++;
142                         if(!found)
143                         {
144                                 (*front)++;
145                         }
146                 }
147                 c++;
148         }
149 }
150
151 int
152 check_pattern(char *value1, char *value2)
153 {
154         int             spec1 = 0,count1 = 0, front1 = 0;
155         int             spec2 = 0,count2 = 0, front2 = 0;
156
157         if(value1 && value2)
158         {
159                 parts_of_pattern(value1, &spec1, &count1, &front1);
160                 parts_of_pattern(value2, &spec2, &count2, &front2);
161         }
162         else if(!value1 && !value2)
163         {
164                 return(0);
165         }
166         else if(value1)
167         {
168                 return(-1);
169         }
170         else
171         {
172                 return(1);
173         }
174
175
176         if(front1 != front2)
177         {
178                 return(front2 - front1);
179         }
180
181         if(spec1 != spec2)
182         {
183                 return(spec1 - spec2);
184         }
185         if(count1 != count2)
186         {
187                 return(count2-count1);
188         }
189
190         return (0);
191 }
192
193 int
194 mode_count(char *c)
195 {
196         int     count = 0;
197
198         while(c && *c)
199         {
200
201                 if(strchr("fcbdlrwx", *c))
202                 {
203                         count++;
204                 }
205                 c++;
206         }
207         return(count);
208 }
209
210 #ifdef DEBUG
211 static int
212 bool(int i)
213 {
214         if(i > 0) return(1);
215         if(i < 0) return(-1);
216         else return(0);
217 }
218
219 #endif
220
221 check_content(char *val1, char *val2)
222 {
223         char    *v1 = strdup(val1);
224         char    *v2 = strdup(val2);
225         char    *loc1;
226         char    *loc2;
227         char    *type1;
228         char    *type2;
229         char    *cnt1;
230         char    *cnt2;
231         int     ret = 0;
232         _Xstrtokparams  strtok_buf;
233
234         loc1 = _XStrtok(v1, "\t \n", strtok_buf);
235         type1 = _XStrtok(NULL, "\t \n", strtok_buf);
236         cnt1 = &type1[strlen(type1)+1];
237         while(isspace((u_char)*cnt1))cnt1++;
238
239         loc2 = _XStrtok(v2, "\t \n", strtok_buf);
240         type2 = _XStrtok(NULL, "\t \n", strtok_buf);
241         cnt2 = &type2[strlen(type2)+1];
242         while(isspace((u_char)*cnt2))cnt2++;
243
244         ret = strcmp(type1, type2);
245         if(loc1 && loc2 && ret == 0)
246         {
247                 int     l1 = atoi(loc1);
248                 int     l2 = atoi(loc2);
249                 int     sl1 = strlen(cnt1);
250                 int     sl2 = strlen(cnt2);
251                 char    sym;
252
253                      if (sl1 > sl2) ret = -1;
254                 else if (sl1 < sl2) ret =  1;
255                 else if (l1  > l2 ) ret =  1;
256                 else if (l1  < l2 ) ret = -1;
257                 else ret = strcmp(cnt1,cnt2);
258
259 #ifdef DEBUG
260                 switch(bool(ret))
261                 {
262                 case    0:
263                         sym = '=';
264                         break;
265                 case    -1:
266                         sym = '>';
267                         break;
268                 case    1:
269                         sym = '<';
270                 }
271                 printf("cc (%d,%d) for \"%s\" %c \"%s\"\n", l1, l2, cnt1, sym, cnt2);
272 #endif
273         }
274         free(v1);
275         free(v2);
276         return(ret);
277 }
278
279 static int
280 sfe(DtDtsDbRecord * item1, DtDtsDbRecord * item2)
281 {
282         int             test1 = 0;
283         int             test2 = 0;
284         int             loc1;
285         int             loc2;
286         char           *value1, *value2;
287         DtDtsDbRecord  *rec;
288         DtDtsDbField   *fld;
289         int             val;
290
291         test1 |= get_value(item1, DtDTS_CONTENT) ? 2 : 0;
292         test2 |= get_value(item2, DtDTS_CONTENT) ? 2 : 0;
293
294         value1 = get_value(item1, DtDTS_NAME_PATTERN);
295         if (value1)
296         {
297                 if ((strlen(value1) == 1) && (*value1 == '*'))
298                 {
299                         test1 |= 0;
300                 }
301                 else
302                 {
303                         test1 |= 1;
304                 }
305         }
306
307         value2 = get_value(item2, DtDTS_NAME_PATTERN);
308         if (value2)
309         {
310                 if ((strlen(value2) == 1) && (*value2 == '*'))
311                 {
312                         test2 |= 0;
313                 }
314                 else
315                 {
316                         test2 |= 1;
317                 }
318         }
319
320         if (!(test1 & 1))
321         {
322                 test1 |= get_value(item1, DtDTS_PATH_PATTERN) ? 1 : 0;
323         }
324         if (!(test2 & 1))
325         {
326                 test2 |= get_value(item2, DtDTS_PATH_PATTERN) ? 1 : 0;
327         }
328
329         switch (test1)
330         {
331         case 0:
332                 loc1 = 4;
333                 break;
334         case 1:
335                 loc1 = 2;
336                 break;
337         case 2:
338                 loc1 = 3;
339                 break;
340         case 3:
341                 loc1 = 1;
342                 break;
343         }
344
345         switch (test2)
346         {
347         case 0:
348                 loc2 = 4;
349                 break;
350         case 1:
351                 loc2 = 2;
352                 break;
353         case 2:
354                 loc2 = 3;
355                 break;
356         case 3:
357                 loc2 = 1;
358                 break;
359         }
360
361         if (loc1 - loc2)
362         {
363                 return (loc1 - loc2);
364         }
365
366         if (loc1 == 2)          /* loc1 == loc2 */
367         {
368                 val = check_pattern(get_value(item1, DtDTS_PATH_PATTERN),
369                                         get_value(item2, DtDTS_PATH_PATTERN));
370                 if(val)
371                 {
372                         return(val);
373                 }
374                 val = check_pattern(get_value(item1, DtDTS_NAME_PATTERN),
375                                         get_value(item2, DtDTS_NAME_PATTERN));
376                 if(val)
377                 {
378                         return(val);
379                 }
380         }
381
382         if( loc1 == 3)
383         {
384                 val = check_content(get_value(item1, DtDTS_CONTENT),
385                                         get_value(item2, DtDTS_CONTENT));
386                 if(val)
387                 {
388                         return(val);
389                 }
390         }
391         /*
392          * neither pattern nor content, only needs to compare the
393          * number of fields. If they are equal then which has shorter
394          * record name will be more specific
395          */
396         if (item2->fieldCount - item1->fieldCount)
397         {
398                 return (item2->fieldCount - item1->fieldCount);
399         }
400
401         val =   mode_count(get_value(item2, DtDTS_MODE)) -
402                 mode_count(get_value(item1, DtDTS_MODE));
403         if(val)
404         {
405                 return(val);
406         }
407
408
409         val = strlen(XrmQuarkToString(item1->recordName)) - 
410               strlen(XrmQuarkToString(item2->recordName));
411         if(val)
412         {
413                 return(val);
414         }
415         else
416         {
417                 return(item1->recordName - item2->recordName);
418         }
419 }
420
421 int
422 cde_dc_compare(DtDtsDbRecord ** a, DtDtsDbRecord ** b)
423 {
424         DtDtsDbRecord **x = (DtDtsDbRecord **) a;
425         DtDtsDbRecord **y = (DtDtsDbRecord **) b;
426         int             results;
427         char            c;
428
429         results = sfe(*x, *y);
430         return(results);
431 }
432
433 static int
434 cde_ft_field_value(XrmQuark  name_quark)
435 {
436         if (name_quark == XrmStringToQuark(DtDTS_PATH_PATTERN))
437                 return (1);
438         else if (name_quark == XrmStringToQuark(DtDTS_NAME_PATTERN))
439                 return (2);
440         else if (name_quark == XrmStringToQuark(DtDTS_MODE))
441                 return (3);
442         else if (name_quark == XrmStringToQuark(DtDTS_LINK_PATH))
443                 return (4);
444         else if (name_quark == XrmStringToQuark(DtDTS_LINK_NAME))
445                 return (5);
446         else if (name_quark == XrmStringToQuark(DtDTS_CONTENT))
447                 return (6);
448         else if (name_quark == XrmStringToQuark(DtDTS_DATA_ATTRIBUTES_NAME))
449                 return (7);
450         else if (name_quark == XrmStringToQuark(DtDTS_DA_IS_SYNTHETIC))
451                 return (8);
452         else
453                 return (9);
454
455 }
456
457 int
458 cde_dc_field_compare(DtDtsDbField ** a, DtDtsDbField ** b)
459 {
460         return (cde_ft_field_value((*a)->fieldName) -
461                 cde_ft_field_value((*b)->fieldName));
462 }
463
464 cde_da_compare(DtDtsDbRecord ** a, DtDtsDbRecord ** b)
465 {
466         int             results = ((*a)->recordName) - ((*b)->recordName);
467
468         if (!results)
469         {
470                 results = (*a)->seq - (*b)->seq;
471         }
472         return (results);
473 }