summaryrefslogtreecommitdiffstats
path: root/usr.bin/csup/pathcomp.c
diff options
context:
space:
mode:
authorlulf <lulf@FreeBSD.org>2010-03-02 07:26:07 +0000
committerlulf <lulf@FreeBSD.org>2010-03-02 07:26:07 +0000
commitc6aa3ac44645e36e9cc1e29aa598a706779c2c29 (patch)
tree34e14c6edd4db3c9e2addc2e9b8af07a970b71ed /usr.bin/csup/pathcomp.c
parentb86208843f144382d49d980b9908eb8618cfc5cd (diff)
downloadFreeBSD-src-c6aa3ac44645e36e9cc1e29aa598a706779c2c29.zip
FreeBSD-src-c6aa3ac44645e36e9cc1e29aa598a706779c2c29.tar.gz
- Move csup away from contrib/ and into usr.bin/. Software is no longer
contributed, and main development is happening in the FreeBSD repo. Suggested by: joel
Diffstat (limited to 'usr.bin/csup/pathcomp.c')
-rw-r--r--usr.bin/csup/pathcomp.c182
1 files changed, 182 insertions, 0 deletions
diff --git a/usr.bin/csup/pathcomp.c b/usr.bin/csup/pathcomp.c
new file mode 100644
index 0000000..380d042
--- /dev/null
+++ b/usr.bin/csup/pathcomp.c
@@ -0,0 +1,182 @@
+/*-
+ * Copyright (c) 2006, Maxime Henrion <mux@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "misc.h"
+#include "pathcomp.h"
+
+struct pathcomp {
+ char *target;
+ size_t targetlen;
+ char *trashed;
+ char *prev;
+ size_t prevlen;
+ size_t goal;
+ size_t curlen;
+};
+
+struct pathcomp *
+pathcomp_new(void)
+{
+ struct pathcomp *pc;
+
+ pc = xmalloc(sizeof(struct pathcomp));
+ pc->curlen = 0;
+ pc->target = NULL;
+ pc->targetlen = 0;
+ pc->trashed = NULL;
+ pc->prev = NULL;
+ pc->prevlen = 0;
+ return (pc);
+}
+
+int
+pathcomp_put(struct pathcomp *pc, int type, char *path)
+{
+ char *cp;
+
+ assert(pc->target == NULL);
+ if (*path == '/')
+ return (-1);
+
+ switch (type) {
+ case PC_DIRDOWN:
+ pc->target = path;
+ pc->targetlen = strlen(path);
+ break;
+ case PC_FILE:
+ case PC_DIRUP:
+ cp = strrchr(path, '/');
+ pc->target = path;
+ if (cp != NULL)
+ pc->targetlen = cp - path;
+ else
+ pc->targetlen = 0;
+ break;
+ }
+ if (pc->prev != NULL)
+ pc->goal = commonpathlength(pc->prev, pc->prevlen, pc->target,
+ pc->targetlen);
+ else
+ pc->goal = 0;
+ if (pc->curlen == pc->goal) /* No need to go up. */
+ pc->goal = pc->targetlen;
+ return (0);
+}
+
+int
+pathcomp_get(struct pathcomp *pc, int *type, char **name)
+{
+ char *cp;
+ size_t slashpos, start;
+
+ if (pc->curlen > pc->goal) { /* Going up. */
+ assert(pc->prev != NULL);
+ pc->prev[pc->curlen] = '\0';
+ cp = pc->prev + pc->curlen - 1;
+ while (cp >= pc->prev) {
+ if (*cp == '/')
+ break;
+ cp--;
+ }
+ if (cp >= pc->prev)
+ slashpos = cp - pc->prev;
+ else
+ slashpos = 0;
+ pc->curlen = slashpos;
+ if (pc->curlen <= pc->goal) { /* Done going up. */
+ assert(pc->curlen == pc->goal);
+ pc->goal = pc->targetlen;
+ }
+ *type = PC_DIRUP;
+ *name = pc->prev;
+ return (1);
+ } else if (pc->curlen < pc->goal) { /* Going down. */
+ /* Restore the previously overwritten '/' character. */
+ if (pc->trashed != NULL) {
+ *pc->trashed = '/';
+ pc->trashed = NULL;
+ }
+ if (pc->curlen == 0)
+ start = pc->curlen;
+ else
+ start = pc->curlen + 1;
+ slashpos = start;
+ while (slashpos < pc->goal) {
+ if (pc->target[slashpos] == '/')
+ break;
+ slashpos++;
+ }
+ if (pc->target[slashpos] != '\0') {
+ assert(pc->target[slashpos] == '/');
+ pc->trashed = pc->target + slashpos;
+ pc->target[slashpos] = '\0';
+ }
+ pc->curlen = slashpos;
+ *type = PC_DIRDOWN;
+ *name = pc->target;
+ return (1);
+ } else { /* Done. */
+ if (pc->target != NULL) {
+ if (pc->trashed != NULL) {
+ *pc->trashed = '/';
+ pc->trashed = NULL;
+ }
+ if (pc->prev != NULL)
+ free(pc->prev);
+ pc->prev = xmalloc(pc->targetlen + 1);
+ memcpy(pc->prev, pc->target, pc->targetlen);
+ pc->prev[pc->targetlen] = '\0';
+ pc->prevlen = pc->targetlen;
+ pc->target = NULL;
+ pc->targetlen = 0;
+ }
+ return (0);
+ }
+}
+
+void
+pathcomp_finish(struct pathcomp *pc)
+{
+
+ pc->target = NULL;
+ pc->targetlen = 0;
+ pc->goal = 0;
+}
+
+void
+pathcomp_free(struct pathcomp *pc)
+{
+
+ if (pc->prev != NULL)
+ free(pc->prev);
+ free(pc);
+}
OpenPOWER on IntegriCloud