1 /* @(#)cmpdir.c 1.28 19/11/28 Copyright 2002-2019 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)cmpdir.c 1.28 19/11/28 Copyright 2002-2019 J. Schilling";
6 #endif
7 /*
8 * Blocked directory sort/compare.
9 *
10 * Copyright (c) 2002-2019 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include <schily/stdio.h>
27 #include <schily/stdlib.h>
28 #include <schily/unistd.h>
29 #include <schily/standard.h>
30 #include <schily/types.h>
31 #include <schily/utypes.h>
32 #include <schily/string.h>
33 #include <schily/schily.h>
34 #include <schily/fetchdir.h>
35
36 EXPORT int fdircomp __PR((const void *p1, const void *p2));
37 EXPORT char **sortdir __PR((char *dir, size_t *entp));
38 EXPORT int cmpdir __PR((size_t ents1, size_t ents2,
39 char **ep1, char **ep2,
40 char **oa, char **od,
41 size_t *alenp, size_t *dlenp));
42
43 /*
44 * Compare directory entries from fetchdir().
45 * Ignore first byte, it does not belong to the directory data.
46 */
47 EXPORT int
fdircomp(p1,p2)48 fdircomp(p1, p2)
49 const void *p1;
50 const void *p2;
51 {
52 register Uchar *s1;
53 register Uchar *s2;
54
55 s1 = *(Uchar **)p1;
56 s2 = *(Uchar **)p2;
57 s1++;
58 s2++;
59 while (*s1 == *s2) {
60 if (*s1 == '\0')
61 return (0);
62 s1++;
63 s2++;
64 }
65 return (*s1 - *s2);
66 }
67
68 /*
69 * Sort a directory string as returned by fetchdir().
70 *
71 * If "ents" == (size_t)-1, start with counting exisiting entries.
72 *
73 * Return allocated arry with string pointers.
74 */
75 EXPORT char **
sortdir(dir,entp)76 sortdir(dir, entp)
77 char *dir;
78 size_t *entp;
79 {
80 size_t ents = (size_t)-1;
81 char **ea;
82 char *d;
83 char *p;
84 size_t i;
85
86 if (entp)
87 ents = *entp;
88 if (ents == (size_t)-1) {
89 d = dir;
90 ents = 0;
91 while (*d) {
92 ents++;
93 p = strchr(d, '\0');
94 d = &p[1];
95 }
96 }
97 ea = ___malloc((ents+1)*sizeof (char *), "sortdir");
98 for (i = 0; i < ents; i++) {
99 ea[i] = NULL;
100 }
101 for (i = 0; i < ents; i++) {
102 ea[i] = dir;
103 p = strchr(dir, '\0');
104 if (p == NULL)
105 break;
106 dir = ++p;
107 }
108 ea[ents] = NULL;
109 qsort(ea, ents, sizeof (char *), fdircomp);
110 if (entp)
111 *entp = ents;
112 return (ea);
113 }
114
115 EXPORT int
cmpdir(ents1,ents2,ep1,ep2,oa,od,alenp,dlenp)116 cmpdir(ents1, ents2, ep1, ep2, oa, od, alenp, dlenp)
117 register size_t ents1; /* # of directory entries in arch */
118 register size_t ents2; /* # of directory entries on disk */
119 register char **ep1; /* Directory entry pointer array (arch) */
120 register char **ep2; /* Directory entry pointer array (disk) */
121 register char **oa; /* Only in arch pointer array */
122 register char **od; /* Only on disk pointer array */
123 size_t *alenp; /* Len pointer for "only in arch" array */
124 size_t *dlenp; /* Len pointer for "only on disk" array */
125 {
126 register size_t i1; /* Index for 'only in archive' */
127 register size_t i2; /* Index for 'only on disk' */
128 register int d; /* 'diff' amount (== 0 means equal) */
129 register size_t alen = 0; /* Number of ents only in archive */
130 register size_t dlen = 0; /* Number of ents only on disk */
131
132 for (i1 = i2 = 0; i1 < ents1 && i2 < ents2; i1++, i2++) {
133 d = fdircomp(&ep1[i1], &ep2[i2]);
134 retry:
135
136 if (d > 0) {
137 do {
138 d = fdircomp(&ep1[i1], &ep2[i2]);
139 if (d <= 0)
140 goto retry;
141 if (od)
142 od[dlen] = ep2[i2];
143 dlen++;
144 i2++;
145 } while (i1 < ents1 && i2 < ents2);
146 }
147 if (d < 0) {
148 do {
149 d = fdircomp(&ep1[i1], &ep2[i2]);
150 if (d >= 0)
151 goto retry;
152 if (oa)
153 oa[alen] = ep1[i1];
154 alen++;
155 i1++;
156 } while (i1 < ents1 && i2 < ents2);
157 }
158 /*
159 * Do not increment i1 & i2 in case that the last elements are
160 * not equal and need to be treaten as longer list elements in
161 * the code below.
162 */
163 if (i1 >= ents1 || i2 >= ents2)
164 break;
165 }
166 /*
167 * One of both lists is longer after some amount.
168 */
169 if (od == NULL) {
170 if (i2 < ents2)
171 dlen += ents2 - i2;
172 } else {
173 for (; i2 < ents2; i2++) {
174 od[dlen] = ep2[i2];
175 dlen++;
176 }
177 }
178 if (oa == NULL) {
179 if (i1 < ents1)
180 alen += ents1 - i1;
181 } else {
182 for (; i1 < ents1; i1++) {
183 oa[alen] = ep1[i1];
184 alen++;
185 }
186 }
187 if (alenp)
188 *alenp = alen;
189 if (dlenp)
190 *dlenp = dlen;
191
192 return (alen + dlen);
193 }
194