pathcomp.c revision 267654
190075Sobrien/*- 2132718Skan * Copyright (c) 2006, Maxime Henrion <mux@FreeBSD.org> 390075Sobrien * All rights reserved. 490075Sobrien * 5132718Skan * Redistribution and use in source and binary forms, with or without 690075Sobrien * modification, are permitted provided that the following conditions 7132718Skan * are met: 8132718Skan * 1. Redistributions of source code must retain the above copyright 9132718Skan * notice, this list of conditions and the following disclaimer. 10132718Skan * 2. Redistributions in binary form must reproduce the above copyright 1190075Sobrien * notice, this list of conditions and the following disclaimer in the 12132718Skan * documentation and/or other materials provided with the distribution. 13132718Skan * 14132718Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15132718Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1690075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17132718Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19169706Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20169706Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2190075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2290075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2390075Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24209867Snwhitehorn * SUCH DAMAGE. 25209867Snwhitehorn * 26209867Snwhitehorn * $FreeBSD: releng/9.3/usr.bin/csup/pathcomp.c 204556 2010-03-02 07:26:07Z lulf $ 27209867Snwhitehorn */ 28209867Snwhitehorn 29209867Snwhitehorn#include <assert.h> 30209867Snwhitehorn#include <stdlib.h> 31209867Snwhitehorn#include <string.h> 3290075Sobrien 33209867Snwhitehorn#include "misc.h" 34147823Sscottl#include "pathcomp.h" 35209867Snwhitehorn 36209867Snwhitehornstruct pathcomp { 37209867Snwhitehorn char *target; 38209867Snwhitehorn size_t targetlen; 39209867Snwhitehorn char *trashed; 40218824Snwhitehorn char *prev; 41218824Snwhitehorn size_t prevlen; 42218824Snwhitehorn size_t goal; 43218824Snwhitehorn size_t curlen; 44218824Snwhitehorn}; 45218824Snwhitehorn 46218824Snwhitehornstruct pathcomp * 47209867Snwhitehornpathcomp_new(void) 48209867Snwhitehorn{ 49209867Snwhitehorn struct pathcomp *pc; 50209867Snwhitehorn 51209867Snwhitehorn pc = xmalloc(sizeof(struct pathcomp)); 52209867Snwhitehorn pc->curlen = 0; 53209867Snwhitehorn pc->target = NULL; 54209867Snwhitehorn pc->targetlen = 0; 55209867Snwhitehorn pc->trashed = NULL; 56209867Snwhitehorn pc->prev = NULL; 57209867Snwhitehorn pc->prevlen = 0; 58209867Snwhitehorn return (pc); 59209867Snwhitehorn} 60209867Snwhitehorn 61209867Snwhitehornint 62209867Snwhitehornpathcomp_put(struct pathcomp *pc, int type, char *path) 63209867Snwhitehorn{ 64209867Snwhitehorn char *cp; 65209867Snwhitehorn 66209867Snwhitehorn assert(pc->target == NULL); 67209867Snwhitehorn if (*path == '/') 68209867Snwhitehorn return (-1); 69209867Snwhitehorn 70209867Snwhitehorn switch (type) { 71209867Snwhitehorn case PC_DIRDOWN: 72209867Snwhitehorn pc->target = path; 73209867Snwhitehorn pc->targetlen = strlen(path); 74209867Snwhitehorn break; 75209867Snwhitehorn case PC_FILE: 76209867Snwhitehorn case PC_DIRUP: 77209867Snwhitehorn cp = strrchr(path, '/'); 78209867Snwhitehorn pc->target = path; 79209867Snwhitehorn if (cp != NULL) 80209867Snwhitehorn pc->targetlen = cp - path; 81209867Snwhitehorn else 82209867Snwhitehorn pc->targetlen = 0; 83209867Snwhitehorn break; 84209867Snwhitehorn } 85209867Snwhitehorn if (pc->prev != NULL) 86209867Snwhitehorn pc->goal = commonpathlength(pc->prev, pc->prevlen, pc->target, 87209867Snwhitehorn pc->targetlen); 88209867Snwhitehorn else 89209867Snwhitehorn pc->goal = 0; 90209867Snwhitehorn if (pc->curlen == pc->goal) /* No need to go up. */ 91209867Snwhitehorn pc->goal = pc->targetlen; 92209867Snwhitehorn return (0); 93209867Snwhitehorn} 94209867Snwhitehorn 95209867Snwhitehornint 96209867Snwhitehornpathcomp_get(struct pathcomp *pc, int *type, char **name) 97209867Snwhitehorn{ 98209867Snwhitehorn char *cp; 99209867Snwhitehorn size_t slashpos, start; 100209867Snwhitehorn 101209867Snwhitehorn if (pc->curlen > pc->goal) { /* Going up. */ 102209867Snwhitehorn assert(pc->prev != NULL); 103209867Snwhitehorn pc->prev[pc->curlen] = '\0'; 104209867Snwhitehorn cp = pc->prev + pc->curlen - 1; 105209867Snwhitehorn while (cp >= pc->prev) { 106209867Snwhitehorn if (*cp == '/') 107209867Snwhitehorn break; 108209867Snwhitehorn cp--; 109209867Snwhitehorn } 110209867Snwhitehorn if (cp >= pc->prev) 111209867Snwhitehorn slashpos = cp - pc->prev; 11290075Sobrien else 11390075Sobrien slashpos = 0; 11490075Sobrien pc->curlen = slashpos; 11590075Sobrien if (pc->curlen <= pc->goal) { /* Done going up. */ 11690075Sobrien assert(pc->curlen == pc->goal); 11790075Sobrien pc->goal = pc->targetlen; 11890075Sobrien } 11990075Sobrien *type = PC_DIRUP; 12090075Sobrien *name = pc->prev; 12190075Sobrien return (1); 12290075Sobrien } else if (pc->curlen < pc->goal) { /* Going down. */ 12390075Sobrien /* Restore the previously overwritten '/' character. */ 12490075Sobrien if (pc->trashed != NULL) { 12590075Sobrien *pc->trashed = '/'; 12690075Sobrien pc->trashed = NULL; 127117395Skan } 128132718Skan if (pc->curlen == 0) 129117395Skan start = pc->curlen; 130117395Skan else 13190075Sobrien start = pc->curlen + 1; 132117395Skan slashpos = start; 13390075Sobrien while (slashpos < pc->goal) { 13490075Sobrien if (pc->target[slashpos] == '/') 13590075Sobrien break; 13690075Sobrien slashpos++; 13790075Sobrien } 13890075Sobrien if (pc->target[slashpos] != '\0') { 139117395Skan assert(pc->target[slashpos] == '/'); 140209867Snwhitehorn pc->trashed = pc->target + slashpos; 141117395Skan pc->target[slashpos] = '\0'; 142209867Snwhitehorn } 143209867Snwhitehorn pc->curlen = slashpos; 144209867Snwhitehorn *type = PC_DIRDOWN; 14590075Sobrien *name = pc->target; 14690075Sobrien return (1); 14790075Sobrien } else { /* Done. */ 14890075Sobrien if (pc->target != NULL) { 14990075Sobrien if (pc->trashed != NULL) { 15090075Sobrien *pc->trashed = '/'; 15190075Sobrien pc->trashed = NULL; 15290075Sobrien } 15390075Sobrien if (pc->prev != NULL) 15490075Sobrien free(pc->prev); 15590075Sobrien pc->prev = xmalloc(pc->targetlen + 1); 15690075Sobrien memcpy(pc->prev, pc->target, pc->targetlen); 15790075Sobrien pc->prev[pc->targetlen] = '\0'; 15890075Sobrien pc->prevlen = pc->targetlen; 15990075Sobrien pc->target = NULL; 16090075Sobrien pc->targetlen = 0; 161209867Snwhitehorn } 162209867Snwhitehorn return (0); 163209867Snwhitehorn } 164209867Snwhitehorn} 165209867Snwhitehorn 166209867Snwhitehornvoid 167209867Snwhitehornpathcomp_finish(struct pathcomp *pc) 168209867Snwhitehorn{ 169209867Snwhitehorn 170209867Snwhitehorn pc->target = NULL; 171209867Snwhitehorn pc->targetlen = 0; 172209867Snwhitehorn pc->goal = 0; 173209867Snwhitehorn} 174209867Snwhitehorn 175209867Snwhitehornvoid 176209867Snwhitehornpathcomp_free(struct pathcomp *pc) 177209867Snwhitehorn{ 178209867Snwhitehorn 179209867Snwhitehorn if (pc->prev != NULL) 180209867Snwhitehorn free(pc->prev); 181209867Snwhitehorn free(pc); 182209867Snwhitehorn} 183209867Snwhitehorn