]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.bin/csup/pathcomp.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.bin / csup / pathcomp.c
1 /*-
2  * Copyright (c) 2006, Maxime Henrion <mux@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <assert.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "misc.h"
34 #include "pathcomp.h"
35
36 struct pathcomp {
37         char *target;
38         size_t targetlen;
39         char *trashed;
40         char *prev;
41         size_t prevlen;
42         size_t goal;
43         size_t curlen;
44 };
45
46 struct pathcomp *
47 pathcomp_new(void)
48 {
49         struct pathcomp *pc;
50
51         pc = xmalloc(sizeof(struct pathcomp));
52         pc->curlen = 0;
53         pc->target = NULL;
54         pc->targetlen = 0;
55         pc->trashed = NULL;
56         pc->prev = NULL;
57         pc->prevlen = 0;
58         return (pc);
59 }
60
61 int
62 pathcomp_put(struct pathcomp *pc, int type, char *path)
63 {
64         char *cp;
65
66         assert(pc->target == NULL);
67         if (*path == '/')
68                 return (-1);
69
70         switch (type) {
71         case PC_DIRDOWN:
72                 pc->target = path;
73                 pc->targetlen = strlen(path);
74                 break;
75         case PC_FILE:
76         case PC_DIRUP:
77                 cp = strrchr(path, '/');
78                 pc->target = path;
79                 if (cp != NULL)
80                         pc->targetlen = cp - path;
81                 else
82                         pc->targetlen = 0;
83                 break;
84         }
85         if (pc->prev != NULL)
86                 pc->goal = commonpathlength(pc->prev, pc->prevlen, pc->target,
87                     pc->targetlen);
88         else
89                 pc->goal = 0;
90         if (pc->curlen == pc->goal)     /* No need to go up. */
91                 pc->goal = pc->targetlen;
92         return (0);
93 }
94
95 int
96 pathcomp_get(struct pathcomp *pc, int *type, char **name)
97 {
98         char *cp;
99         size_t slashpos, start;
100
101         if (pc->curlen > pc->goal) {            /* Going up. */
102                 assert(pc->prev != NULL);
103                 pc->prev[pc->curlen] = '\0';
104                 cp = pc->prev + pc->curlen - 1;
105                 while (cp >= pc->prev) {
106                         if (*cp == '/')
107                                 break;
108                         cp--;
109                 }
110                 if (cp >= pc->prev)
111                         slashpos = cp - pc->prev;
112                 else
113                         slashpos = 0;
114                 pc->curlen = slashpos;
115                 if (pc->curlen <= pc->goal) {   /* Done going up. */
116                         assert(pc->curlen == pc->goal);
117                         pc->goal = pc->targetlen;
118                 }
119                 *type = PC_DIRUP;
120                 *name = pc->prev;
121                 return (1);
122         } else if (pc->curlen < pc->goal) {     /* Going down. */
123                 /* Restore the previously overwritten '/' character. */
124                 if (pc->trashed != NULL) {
125                         *pc->trashed = '/';
126                         pc->trashed = NULL;
127                 }
128                 if (pc->curlen == 0)
129                         start = pc->curlen;
130                 else
131                         start = pc->curlen + 1;
132                 slashpos = start;
133                 while (slashpos < pc->goal) {
134                         if (pc->target[slashpos] == '/')
135                                 break;
136                         slashpos++;
137                 }
138                 if (pc->target[slashpos] != '\0') {
139                         assert(pc->target[slashpos] == '/');
140                         pc->trashed = pc->target + slashpos;
141                         pc->target[slashpos] = '\0';
142                 }
143                 pc->curlen = slashpos;
144                 *type = PC_DIRDOWN;
145                 *name = pc->target;
146                 return (1);
147         } else {        /* Done. */
148                 if (pc->target != NULL) {
149                         if (pc->trashed != NULL) {
150                                 *pc->trashed = '/';
151                                 pc->trashed = NULL;
152                         }
153                         if (pc->prev != NULL)
154                                 free(pc->prev);
155                         pc->prev = xmalloc(pc->targetlen + 1);
156                         memcpy(pc->prev, pc->target, pc->targetlen);
157                         pc->prev[pc->targetlen] = '\0';
158                         pc->prevlen = pc->targetlen;
159                         pc->target = NULL;
160                         pc->targetlen = 0;
161                 }
162                 return (0);
163         }
164 }
165
166 void
167 pathcomp_finish(struct pathcomp *pc)
168 {
169
170         pc->target = NULL;
171         pc->targetlen = 0;
172         pc->goal = 0;
173 }
174
175 void
176 pathcomp_free(struct pathcomp *pc)
177 {
178
179         if (pc->prev != NULL)
180                 free(pc->prev);
181         free(pc);
182 }