1156230Smux/*- 2156230Smux * Copyright (c) 2006, Maxime Henrion <mux@FreeBSD.org> 3156230Smux * All rights reserved. 4156230Smux * 5156230Smux * Redistribution and use in source and binary forms, with or without 6156230Smux * modification, are permitted provided that the following conditions 7156230Smux * are met: 8156230Smux * 1. Redistributions of source code must retain the above copyright 9156230Smux * notice, this list of conditions and the following disclaimer. 10156230Smux * 2. Redistributions in binary form must reproduce the above copyright 11156230Smux * notice, this list of conditions and the following disclaimer in the 12156230Smux * documentation and/or other materials provided with the distribution. 13156230Smux * 14156230Smux * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15156230Smux * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16156230Smux * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17156230Smux * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18156230Smux * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19156230Smux * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20156230Smux * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21156230Smux * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22156230Smux * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23156230Smux * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24156230Smux * SUCH DAMAGE. 25156230Smux * 26156230Smux * $FreeBSD$ 27156230Smux */ 28156230Smux 29156230Smux#include <assert.h> 30156230Smux#include <stdlib.h> 31156230Smux#include <string.h> 32156230Smux 33156230Smux#include "misc.h" 34156230Smux#include "pathcomp.h" 35156230Smux 36156230Smuxstruct pathcomp { 37156230Smux char *target; 38156230Smux size_t targetlen; 39156230Smux char *trashed; 40156230Smux char *prev; 41156230Smux size_t prevlen; 42156230Smux size_t goal; 43156230Smux size_t curlen; 44156230Smux}; 45156230Smux 46156230Smuxstruct pathcomp * 47156230Smuxpathcomp_new(void) 48156230Smux{ 49156230Smux struct pathcomp *pc; 50156230Smux 51156230Smux pc = xmalloc(sizeof(struct pathcomp)); 52156230Smux pc->curlen = 0; 53156230Smux pc->target = NULL; 54156230Smux pc->targetlen = 0; 55156230Smux pc->trashed = NULL; 56156230Smux pc->prev = NULL; 57156230Smux pc->prevlen = 0; 58156230Smux return (pc); 59156230Smux} 60156230Smux 61156230Smuxint 62156230Smuxpathcomp_put(struct pathcomp *pc, int type, char *path) 63156230Smux{ 64156230Smux char *cp; 65156230Smux 66156230Smux assert(pc->target == NULL); 67156230Smux if (*path == '/') 68156230Smux return (-1); 69156230Smux 70156230Smux switch (type) { 71156230Smux case PC_DIRDOWN: 72156230Smux pc->target = path; 73156230Smux pc->targetlen = strlen(path); 74156230Smux break; 75156230Smux case PC_FILE: 76156230Smux case PC_DIRUP: 77156230Smux cp = strrchr(path, '/'); 78156230Smux pc->target = path; 79156230Smux if (cp != NULL) 80156230Smux pc->targetlen = cp - path; 81156230Smux else 82156230Smux pc->targetlen = 0; 83156230Smux break; 84156230Smux } 85156230Smux if (pc->prev != NULL) 86156230Smux pc->goal = commonpathlength(pc->prev, pc->prevlen, pc->target, 87156230Smux pc->targetlen); 88156230Smux else 89156230Smux pc->goal = 0; 90156230Smux if (pc->curlen == pc->goal) /* No need to go up. */ 91156230Smux pc->goal = pc->targetlen; 92156230Smux return (0); 93156230Smux} 94156230Smux 95156230Smuxint 96156230Smuxpathcomp_get(struct pathcomp *pc, int *type, char **name) 97156230Smux{ 98156230Smux char *cp; 99156230Smux size_t slashpos, start; 100156230Smux 101156230Smux if (pc->curlen > pc->goal) { /* Going up. */ 102156230Smux assert(pc->prev != NULL); 103156230Smux pc->prev[pc->curlen] = '\0'; 104156230Smux cp = pc->prev + pc->curlen - 1; 105156230Smux while (cp >= pc->prev) { 106156230Smux if (*cp == '/') 107156230Smux break; 108156230Smux cp--; 109156230Smux } 110156230Smux if (cp >= pc->prev) 111156230Smux slashpos = cp - pc->prev; 112156230Smux else 113156230Smux slashpos = 0; 114156230Smux pc->curlen = slashpos; 115156230Smux if (pc->curlen <= pc->goal) { /* Done going up. */ 116156230Smux assert(pc->curlen == pc->goal); 117156230Smux pc->goal = pc->targetlen; 118156230Smux } 119156230Smux *type = PC_DIRUP; 120156230Smux *name = pc->prev; 121156230Smux return (1); 122156230Smux } else if (pc->curlen < pc->goal) { /* Going down. */ 123156230Smux /* Restore the previously overwritten '/' character. */ 124156230Smux if (pc->trashed != NULL) { 125156230Smux *pc->trashed = '/'; 126156230Smux pc->trashed = NULL; 127156230Smux } 128156230Smux if (pc->curlen == 0) 129156230Smux start = pc->curlen; 130156230Smux else 131156230Smux start = pc->curlen + 1; 132156230Smux slashpos = start; 133156230Smux while (slashpos < pc->goal) { 134156230Smux if (pc->target[slashpos] == '/') 135156230Smux break; 136156230Smux slashpos++; 137156230Smux } 138156230Smux if (pc->target[slashpos] != '\0') { 139156230Smux assert(pc->target[slashpos] == '/'); 140156230Smux pc->trashed = pc->target + slashpos; 141156230Smux pc->target[slashpos] = '\0'; 142156230Smux } 143156230Smux pc->curlen = slashpos; 144156230Smux *type = PC_DIRDOWN; 145156230Smux *name = pc->target; 146156230Smux return (1); 147156230Smux } else { /* Done. */ 148156230Smux if (pc->target != NULL) { 149156230Smux if (pc->trashed != NULL) { 150156230Smux *pc->trashed = '/'; 151156230Smux pc->trashed = NULL; 152156230Smux } 153156230Smux if (pc->prev != NULL) 154156230Smux free(pc->prev); 155156230Smux pc->prev = xmalloc(pc->targetlen + 1); 156156230Smux memcpy(pc->prev, pc->target, pc->targetlen); 157156230Smux pc->prev[pc->targetlen] = '\0'; 158156230Smux pc->prevlen = pc->targetlen; 159156230Smux pc->target = NULL; 160156230Smux pc->targetlen = 0; 161156230Smux } 162156230Smux return (0); 163156230Smux } 164156230Smux} 165156230Smux 166156230Smuxvoid 167156230Smuxpathcomp_finish(struct pathcomp *pc) 168156230Smux{ 169156230Smux 170156230Smux pc->target = NULL; 171156230Smux pc->targetlen = 0; 172156230Smux pc->goal = 0; 173156230Smux} 174156230Smux 175156230Smuxvoid 176156230Smuxpathcomp_free(struct pathcomp *pc) 177156230Smux{ 178156230Smux 179156230Smux if (pc->prev != NULL) 180156230Smux free(pc->prev); 181156230Smux free(pc); 182156230Smux} 183